@delali/narsil 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -3
- package/dist/{chunk-Q4OVNESD.mjs → chunk-HMO6OMZ3.mjs} +1766 -1131
- package/dist/{chunk-CU6BVZEU.mjs → chunk-MEW7HD75.mjs} +87 -155
- package/dist/{config-DX--2Owg.d.ts → config-CojEPOgS.d.ts} +10 -1
- package/dist/{direct-executor-6FOKJKLD.mjs → direct-executor-E52FFGDE.mjs} +1 -1
- package/dist/distribution/coordinator/etcd.d.ts +2 -2
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution.d.ts +4 -4
- package/dist/distribution.mjs +4 -3
- package/dist/index.browser.mjs +1868 -1301
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/{narsil-B3jKyXCr.d.ts → narsil-D-84Nvm4.d.ts} +2 -2
- package/dist/persistence/durability/checkpoint-worker.d.ts +2 -0
- package/dist/persistence/durability/checkpoint-worker.mjs +2 -2
- package/dist/{schema-C3VhNvfw.d.ts → schema-DCgkO1j4.d.ts} +5 -0
- package/dist/server.d.ts +4 -3
- package/dist/server.mjs +1 -0
- package/dist/{types-CTVVm4GG.d.ts → types-DHX6zGeD.d.ts} +1 -1
- package/dist/workers/entry.mjs +1 -1
- package/package.json +1 -1
|
@@ -185,6 +185,7 @@ function computeDefaultCacheSize() {
|
|
|
185
185
|
return Math.max(CACHE_SIZE_FLOOR, Math.min(2e5, CACHE_SIZE_CEILING));
|
|
186
186
|
}
|
|
187
187
|
var normalizationCache = /* @__PURE__ */ new Map();
|
|
188
|
+
var normalizationCacheSize = 0;
|
|
188
189
|
var maxCacheSize = computeDefaultCacheSize();
|
|
189
190
|
function configureNormalizationCache(maxSize) {
|
|
190
191
|
if (!Number.isFinite(maxSize)) {
|
|
@@ -207,19 +208,13 @@ function configureNormalizationCache(maxSize) {
|
|
|
207
208
|
);
|
|
208
209
|
}
|
|
209
210
|
maxCacheSize = Math.max(CACHE_SIZE_FLOOR, Math.min(Math.floor(maxSize), CACHE_SIZE_CEILING));
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
let count = 0;
|
|
213
|
-
for (const key of normalizationCache.keys()) {
|
|
214
|
-
if (count >= excess) break;
|
|
215
|
-
normalizationCache.delete(key);
|
|
216
|
-
count++;
|
|
217
|
-
}
|
|
211
|
+
if (normalizationCacheSize > maxCacheSize) {
|
|
212
|
+
evictOldestEntries(normalizationCacheSize - maxCacheSize);
|
|
218
213
|
}
|
|
219
214
|
}
|
|
220
215
|
var cachedLangName = "";
|
|
221
216
|
var cachedFlags = "";
|
|
222
|
-
var
|
|
217
|
+
var cachedBucket = null;
|
|
223
218
|
function stripDiacritics(text) {
|
|
224
219
|
return text.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
225
220
|
}
|
|
@@ -228,18 +223,44 @@ function resolveStopWords(language, override) {
|
|
|
228
223
|
if (override instanceof Set) return override;
|
|
229
224
|
return override(language.stopWords);
|
|
230
225
|
}
|
|
231
|
-
function
|
|
232
|
-
if (language.name === cachedLangName && flags === cachedFlags) return
|
|
226
|
+
function getCacheBucket(language, flags) {
|
|
227
|
+
if (cachedBucket && language.name === cachedLangName && flags === cachedFlags) return cachedBucket;
|
|
228
|
+
const key = `${language.name}:${flags}`;
|
|
229
|
+
let bucket = normalizationCache.get(key);
|
|
230
|
+
if (!bucket) {
|
|
231
|
+
bucket = /* @__PURE__ */ new Map();
|
|
232
|
+
normalizationCache.set(key, bucket);
|
|
233
|
+
}
|
|
233
234
|
cachedLangName = language.name;
|
|
234
235
|
cachedFlags = flags;
|
|
235
|
-
|
|
236
|
-
return
|
|
236
|
+
cachedBucket = bucket;
|
|
237
|
+
return bucket;
|
|
238
|
+
}
|
|
239
|
+
function evictOldestEntries(count) {
|
|
240
|
+
let remaining = count;
|
|
241
|
+
for (const [key, bucket] of normalizationCache) {
|
|
242
|
+
if (remaining <= 0) break;
|
|
243
|
+
if (bucket.size <= remaining) {
|
|
244
|
+
remaining -= bucket.size;
|
|
245
|
+
normalizationCacheSize -= bucket.size;
|
|
246
|
+
normalizationCache.delete(key);
|
|
247
|
+
if (bucket === cachedBucket) cachedBucket = null;
|
|
248
|
+
} else {
|
|
249
|
+
let deleted = 0;
|
|
250
|
+
for (const raw of bucket.keys()) {
|
|
251
|
+
if (deleted >= remaining) break;
|
|
252
|
+
bucket.delete(raw);
|
|
253
|
+
deleted++;
|
|
254
|
+
}
|
|
255
|
+
normalizationCacheSize -= deleted;
|
|
256
|
+
remaining = 0;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
237
259
|
}
|
|
238
260
|
function transformToken(raw, language, stem, removeDiacritics) {
|
|
239
261
|
const flags = (stem ? "s" : "") + (removeDiacritics ? "d" : "");
|
|
240
|
-
|
|
241
|
-
const
|
|
242
|
-
const cached = normalizationCache.get(cacheKey);
|
|
262
|
+
let bucket = getCacheBucket(language, flags);
|
|
263
|
+
const cached = bucket.get(raw);
|
|
243
264
|
if (cached !== void 0) return cached;
|
|
244
265
|
let normalized = raw;
|
|
245
266
|
if (removeDiacritics) {
|
|
@@ -248,16 +269,12 @@ function transformToken(raw, language, stem, removeDiacritics) {
|
|
|
248
269
|
if (stem && language.stemmer) {
|
|
249
270
|
normalized = language.stemmer(normalized);
|
|
250
271
|
}
|
|
251
|
-
if (
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
for (const key of normalizationCache.keys()) {
|
|
255
|
-
if (count >= evictCount) break;
|
|
256
|
-
normalizationCache.delete(key);
|
|
257
|
-
count++;
|
|
258
|
-
}
|
|
272
|
+
if (normalizationCacheSize >= maxCacheSize) {
|
|
273
|
+
evictOldestEntries(Math.max(1, maxCacheSize >>> 2));
|
|
274
|
+
bucket = getCacheBucket(language, flags);
|
|
259
275
|
}
|
|
260
|
-
|
|
276
|
+
bucket.set(raw, normalized);
|
|
277
|
+
normalizationCacheSize++;
|
|
261
278
|
return normalized;
|
|
262
279
|
}
|
|
263
280
|
function splitText(text, language) {
|
|
@@ -287,24 +304,28 @@ function tokenize(text, language, options) {
|
|
|
287
304
|
stem = true,
|
|
288
305
|
removeStopWords = true,
|
|
289
306
|
removeDiacritics = false,
|
|
307
|
+
collectSurfaces = false,
|
|
290
308
|
customTokenizer,
|
|
291
309
|
stopWordOverride
|
|
292
310
|
} = options ?? {};
|
|
293
311
|
if (customTokenizer) {
|
|
294
312
|
const customResult = customTokenizer.tokenize(text);
|
|
313
|
+
const originals = customResult.map((t) => t.token);
|
|
295
314
|
return {
|
|
296
315
|
tokens: customResult,
|
|
297
|
-
originalTokens:
|
|
316
|
+
originalTokens: originals
|
|
298
317
|
};
|
|
299
318
|
}
|
|
300
319
|
const normalized = isAscii(text) ? text.toLowerCase() : text.normalize("NFC").toLowerCase();
|
|
301
320
|
const rawParts = splitText(normalized, language);
|
|
302
321
|
const minLength = language.tokenizer?.minTokenLength ?? DEFAULT_MIN_TOKEN_LENGTH;
|
|
303
322
|
const effectiveDiacritics = removeDiacritics || (language.tokenizer?.normalizeDiacritics ?? false);
|
|
323
|
+
const stemsTokens = stem && language.stemmer !== void 0;
|
|
304
324
|
const stopWords = removeStopWords ? resolveStopWords(language, stopWordOverride) : /* @__PURE__ */ new Set();
|
|
305
325
|
const stripPossessives = language.tokenizer?.stripPossessive ?? false;
|
|
306
326
|
const tokens = [];
|
|
307
327
|
const originalTokens = [];
|
|
328
|
+
const surfaces = collectSurfaces && stemsTokens ? [] : void 0;
|
|
308
329
|
let position = 0;
|
|
309
330
|
for (const part of rawParts) {
|
|
310
331
|
const candidate = stripPossessives ? stripPossessive(part) : part;
|
|
@@ -320,16 +341,21 @@ function tokenize(text, language, options) {
|
|
|
320
341
|
if (processed.length > 0) {
|
|
321
342
|
tokens.push({ token: processed, position });
|
|
322
343
|
originalTokens.push(part);
|
|
344
|
+
if (surfaces) {
|
|
345
|
+
const surface = effectiveDiacritics ? transformToken(candidate, language, false, true) : candidate;
|
|
346
|
+
surfaces.push(surface === processed ? void 0 : surface);
|
|
347
|
+
}
|
|
323
348
|
}
|
|
324
349
|
position++;
|
|
325
350
|
}
|
|
326
|
-
return { tokens, originalTokens };
|
|
351
|
+
return { tokens, originalTokens, surfaces };
|
|
327
352
|
}
|
|
328
353
|
function* tokenizeIterator(text, language, options) {
|
|
329
354
|
const {
|
|
330
355
|
stem = true,
|
|
331
356
|
removeStopWords = true,
|
|
332
357
|
removeDiacritics = false,
|
|
358
|
+
collectSurfaces = false,
|
|
333
359
|
customTokenizer,
|
|
334
360
|
stopWordOverride
|
|
335
361
|
} = options ?? {};
|
|
@@ -344,6 +370,8 @@ function* tokenizeIterator(text, language, options) {
|
|
|
344
370
|
const rawParts = splitText(normalized, language);
|
|
345
371
|
const minLength = language.tokenizer?.minTokenLength ?? DEFAULT_MIN_TOKEN_LENGTH;
|
|
346
372
|
const effectiveDiacritics = removeDiacritics || (language.tokenizer?.normalizeDiacritics ?? false);
|
|
373
|
+
const stemsTokens = stem && language.stemmer !== void 0;
|
|
374
|
+
const wantSurfaces = collectSurfaces && stemsTokens;
|
|
347
375
|
const stopWords = removeStopWords ? resolveStopWords(language, stopWordOverride) : /* @__PURE__ */ new Set();
|
|
348
376
|
const stripPossessives = language.tokenizer?.stripPossessive ?? false;
|
|
349
377
|
let position = 0;
|
|
@@ -359,20 +387,27 @@ function* tokenizeIterator(text, language, options) {
|
|
|
359
387
|
}
|
|
360
388
|
const processed = transformToken(candidate, language, stem, effectiveDiacritics);
|
|
361
389
|
if (processed.length > 0) {
|
|
362
|
-
|
|
390
|
+
if (wantSurfaces) {
|
|
391
|
+
const surface = effectiveDiacritics ? transformToken(candidate, language, false, true) : candidate;
|
|
392
|
+
yield { token: processed, position, surface: surface === processed ? void 0 : surface };
|
|
393
|
+
} else {
|
|
394
|
+
yield { token: processed, position };
|
|
395
|
+
}
|
|
363
396
|
}
|
|
364
397
|
position++;
|
|
365
398
|
}
|
|
366
399
|
}
|
|
367
400
|
function clearNormalizationCache() {
|
|
368
401
|
normalizationCache.clear();
|
|
402
|
+
normalizationCacheSize = 0;
|
|
403
|
+
cachedBucket = null;
|
|
369
404
|
}
|
|
370
405
|
function resetNormalizationCache() {
|
|
371
|
-
|
|
406
|
+
clearNormalizationCache();
|
|
372
407
|
maxCacheSize = computeDefaultCacheSize();
|
|
373
408
|
}
|
|
374
409
|
function getNormalizationCacheSize() {
|
|
375
|
-
return
|
|
410
|
+
return normalizationCacheSize;
|
|
376
411
|
}
|
|
377
412
|
|
|
378
413
|
// src/schema/validator/shared.ts
|
|
@@ -771,6 +806,36 @@ function validateVectorPromotion(config) {
|
|
|
771
806
|
}
|
|
772
807
|
|
|
773
808
|
// src/search/fulltext.ts
|
|
809
|
+
var PREFIX_MAX_EXPANSIONS = 50;
|
|
810
|
+
function resolvePrefixExpansion(partition, params, language, options, queryTokens, lastToken) {
|
|
811
|
+
const term = params.term;
|
|
812
|
+
if (term === void 0) return void 0;
|
|
813
|
+
const unstemmed = tokenize(term, language, {
|
|
814
|
+
stem: false,
|
|
815
|
+
removeStopWords: true,
|
|
816
|
+
customTokenizer: options?.customTokenizer,
|
|
817
|
+
stopWordOverride: options?.stopWords
|
|
818
|
+
});
|
|
819
|
+
let surfacePrefix;
|
|
820
|
+
for (const t of unstemmed.tokens) {
|
|
821
|
+
if (t.position === lastToken.position) {
|
|
822
|
+
surfacePrefix = t.token;
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
if (surfacePrefix === void 0 || surfacePrefix.length === 0) return void 0;
|
|
827
|
+
const expansions = partition.expandTermPrefix(surfacePrefix, lastToken.token, PREFIX_MAX_EXPANSIONS);
|
|
828
|
+
const terms = [];
|
|
829
|
+
for (const expanded of expansions) {
|
|
830
|
+
if (expanded !== lastToken.token) terms.push(expanded);
|
|
831
|
+
}
|
|
832
|
+
for (const qt of queryTokens) {
|
|
833
|
+
if (qt.token === lastToken.token) {
|
|
834
|
+
return { token: qt.token, terms };
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return void 0;
|
|
838
|
+
}
|
|
774
839
|
function fulltextSearch(partition, params, language, schema, options) {
|
|
775
840
|
if (!params.term || params.term.trim().length === 0) {
|
|
776
841
|
return { scored: [], totalMatched: 0 };
|
|
@@ -792,6 +857,11 @@ function fulltextSearch(partition, params, language, schema, options) {
|
|
|
792
857
|
return { scored: [], totalMatched: 0 };
|
|
793
858
|
}
|
|
794
859
|
const queryTokens = deduplicateTokens(queryTokenResult.tokens);
|
|
860
|
+
let prefixExpansion;
|
|
861
|
+
if (params.prefix === true && params.exact !== true) {
|
|
862
|
+
const lastToken = queryTokenResult.tokens[queryTokenResult.tokens.length - 1];
|
|
863
|
+
prefixExpansion = resolvePrefixExpansion(partition, params, language, options, queryTokens, lastToken);
|
|
864
|
+
}
|
|
795
865
|
let filterBitset;
|
|
796
866
|
if (params.filters) {
|
|
797
867
|
filterBitset = partition.applyFiltersBitset(params.filters, schema);
|
|
@@ -805,6 +875,7 @@ function fulltextSearch(partition, params, language, schema, options) {
|
|
|
805
875
|
const collectComponents = params.includeScoreComponents === true || params.termMatch !== void 0 && params.termMatch !== "any";
|
|
806
876
|
const rawResult = partition.searchFulltext({
|
|
807
877
|
queryTokens,
|
|
878
|
+
prefixExpansion,
|
|
808
879
|
fields: params.fields,
|
|
809
880
|
boost: params.boost,
|
|
810
881
|
tolerance: params.tolerance ?? 0,
|
|
@@ -820,7 +891,14 @@ function fulltextSearch(partition, params, language, schema, options) {
|
|
|
820
891
|
let scored = rawResult.scored;
|
|
821
892
|
const termMatch = params.termMatch ?? "any";
|
|
822
893
|
if (termMatch !== "any") {
|
|
823
|
-
scored = filterByTermCoverage(
|
|
894
|
+
scored = filterByTermCoverage(
|
|
895
|
+
scored,
|
|
896
|
+
queryTokens,
|
|
897
|
+
termMatch,
|
|
898
|
+
params.tolerance ?? 0,
|
|
899
|
+
params.exact ?? false,
|
|
900
|
+
prefixExpansion
|
|
901
|
+
);
|
|
824
902
|
}
|
|
825
903
|
if (params.minScore !== void 0 && params.minScore > 0) {
|
|
826
904
|
const threshold = params.minScore;
|
|
@@ -855,26 +933,40 @@ function deduplicateTokens(tokens) {
|
|
|
855
933
|
}
|
|
856
934
|
return result;
|
|
857
935
|
}
|
|
858
|
-
function filterByTermCoverage(scored, queryTokens, policy, tolerance, exact) {
|
|
936
|
+
function filterByTermCoverage(scored, queryTokens, policy, tolerance, exact, prefixExpansion) {
|
|
859
937
|
const requiredCount = policy === "all" ? queryTokens.length : policy;
|
|
860
938
|
if (requiredCount <= 0) return scored;
|
|
861
939
|
if (requiredCount > queryTokens.length) return [];
|
|
940
|
+
const expansionTerms = prefixExpansion ? new Set(prefixExpansion.terms) : void 0;
|
|
862
941
|
return scored.filter((doc) => {
|
|
863
|
-
const matched = countDocTermMatches(doc, queryTokens, tolerance, exact);
|
|
942
|
+
const matched = countDocTermMatches(doc, queryTokens, tolerance, exact, prefixExpansion?.token, expansionTerms);
|
|
864
943
|
return matched >= requiredCount;
|
|
865
944
|
});
|
|
866
945
|
}
|
|
867
|
-
function countDocTermMatches(doc, queryTokens, tolerance, exact) {
|
|
946
|
+
function countDocTermMatches(doc, queryTokens, tolerance, exact, prefixToken, expansionTerms) {
|
|
868
947
|
const indexTokens = Object.keys(doc.idf);
|
|
869
948
|
if (indexTokens.length === 0) return 0;
|
|
870
949
|
let count = 0;
|
|
871
950
|
for (const qt of queryTokens) {
|
|
951
|
+
if (prefixToken !== void 0 && qt.token === prefixToken) {
|
|
952
|
+
if (prefixTokenSatisfied(qt.token, indexTokens, expansionTerms)) {
|
|
953
|
+
count++;
|
|
954
|
+
}
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
872
957
|
if (queryTermSatisfied(qt.token, indexTokens, tolerance, exact)) {
|
|
873
958
|
count++;
|
|
874
959
|
}
|
|
875
960
|
}
|
|
876
961
|
return count;
|
|
877
962
|
}
|
|
963
|
+
function prefixTokenSatisfied(prefixToken, indexTokens, expansionTerms) {
|
|
964
|
+
for (const indexToken of indexTokens) {
|
|
965
|
+
if (indexToken === prefixToken) return true;
|
|
966
|
+
if (expansionTerms?.has(indexToken)) return true;
|
|
967
|
+
}
|
|
968
|
+
return false;
|
|
969
|
+
}
|
|
878
970
|
function queryTermSatisfied(queryToken, indexTokens, tolerance, exact) {
|
|
879
971
|
if (exact || tolerance === 0) {
|
|
880
972
|
return indexTokens.includes(queryToken);
|
|
@@ -1120,8 +1212,20 @@ function heapPop(heap) {
|
|
|
1120
1212
|
}
|
|
1121
1213
|
return top;
|
|
1122
1214
|
}
|
|
1123
|
-
function
|
|
1124
|
-
|
|
1215
|
+
function sanitizeSurfaceForms(raw) {
|
|
1216
|
+
if (raw === void 0 || raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
1217
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
1218
|
+
let count = 0;
|
|
1219
|
+
for (const [surface, value] of Object.entries(raw)) {
|
|
1220
|
+
if (typeof value === "number") {
|
|
1221
|
+
result[surface] = value;
|
|
1222
|
+
count++;
|
|
1223
|
+
} else if (Array.isArray(value) && typeof value[0] === "number" && typeof value[1] === "string") {
|
|
1224
|
+
result[surface] = [value[0], value[1]];
|
|
1225
|
+
count++;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
return count > 0 ? result : void 0;
|
|
1125
1229
|
}
|
|
1126
1230
|
var VALID_HNSW_METRICS = /* @__PURE__ */ new Set(["cosine", "dotProduct", "euclidean"]);
|
|
1127
1231
|
function validateHnswMetric(value) {
|
|
@@ -1131,6 +1235,153 @@ function validateHnswMetric(value) {
|
|
|
1131
1235
|
}
|
|
1132
1236
|
return void 0;
|
|
1133
1237
|
}
|
|
1238
|
+
function wireToPartition(raw) {
|
|
1239
|
+
const documents = {};
|
|
1240
|
+
for (const [docId, doc] of Object.entries(raw.documents ?? {})) {
|
|
1241
|
+
documents[docId] = {
|
|
1242
|
+
fields: doc.fields,
|
|
1243
|
+
fieldLengths: doc.field_lengths ?? {}
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
const invertedIndex = {};
|
|
1247
|
+
for (const [token, list] of Object.entries(raw.inverted_index ?? {})) {
|
|
1248
|
+
invertedIndex[token] = {
|
|
1249
|
+
docFrequency: list.doc_freq,
|
|
1250
|
+
postings: (list.postings ?? []).map((p) => ({
|
|
1251
|
+
docId: p.doc_id,
|
|
1252
|
+
termFrequency: p.term_freq,
|
|
1253
|
+
field: p.field,
|
|
1254
|
+
positions: p.positions ?? []
|
|
1255
|
+
}))
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
const numeric = {};
|
|
1259
|
+
for (const [field, entries] of Object.entries(raw.field_indexes?.numeric ?? {})) {
|
|
1260
|
+
numeric[field] = entries.map((e) => ({ value: e.value, docId: e.doc_id }));
|
|
1261
|
+
}
|
|
1262
|
+
const boolean = {};
|
|
1263
|
+
for (const [field, idx] of Object.entries(raw.field_indexes?.boolean ?? {})) {
|
|
1264
|
+
boolean[field] = { trueDocs: idx.true_docs ?? [], falseDocs: idx.false_docs ?? [] };
|
|
1265
|
+
}
|
|
1266
|
+
const geopoint = {};
|
|
1267
|
+
for (const [field, entries] of Object.entries(raw.field_indexes?.geopoint ?? {})) {
|
|
1268
|
+
geopoint[field] = entries.map((e) => ({ lat: e.lat, lon: e.lon, docId: e.doc_id }));
|
|
1269
|
+
}
|
|
1270
|
+
const vectorData = {};
|
|
1271
|
+
for (const [field, data] of Object.entries(raw.vector_data ?? {})) {
|
|
1272
|
+
vectorData[field] = {
|
|
1273
|
+
dimension: data.dimension,
|
|
1274
|
+
vectors: (data.vectors ?? []).map((v) => ({ docId: v.doc_id, vector: v.vector })),
|
|
1275
|
+
hnswGraph: data.hnsw_graph ? {
|
|
1276
|
+
entryPoint: data.hnsw_graph.entry_point,
|
|
1277
|
+
maxLayer: data.hnsw_graph.max_layer,
|
|
1278
|
+
m: data.hnsw_graph.m,
|
|
1279
|
+
efConstruction: data.hnsw_graph.ef_construction,
|
|
1280
|
+
metric: validateHnswMetric(data.hnsw_graph.metric),
|
|
1281
|
+
nodes: data.hnsw_graph.nodes
|
|
1282
|
+
} : null,
|
|
1283
|
+
sq8: data.sq8 ? {
|
|
1284
|
+
alpha: data.sq8.alpha,
|
|
1285
|
+
offset: data.sq8.offset,
|
|
1286
|
+
quantizedVectors: data.sq8.quantized_vectors,
|
|
1287
|
+
vectorSums: data.sq8.vector_sums,
|
|
1288
|
+
vectorSumSqs: data.sq8.vector_sum_sqs
|
|
1289
|
+
} : null
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
return {
|
|
1293
|
+
indexName: raw.index_name,
|
|
1294
|
+
partitionId: raw.partition_id,
|
|
1295
|
+
totalPartitions: raw.total_partitions,
|
|
1296
|
+
language: raw.language ?? "english",
|
|
1297
|
+
schema: raw.schema ?? {},
|
|
1298
|
+
docCount: raw.doc_count ?? 0,
|
|
1299
|
+
avgDocLength: raw.avg_doc_length ?? 0,
|
|
1300
|
+
documents,
|
|
1301
|
+
invertedIndex,
|
|
1302
|
+
fieldIndexes: {
|
|
1303
|
+
numeric,
|
|
1304
|
+
boolean,
|
|
1305
|
+
enum: raw.field_indexes?.enum ?? {},
|
|
1306
|
+
geopoint
|
|
1307
|
+
},
|
|
1308
|
+
surfaceForms: sanitizeSurfaceForms(raw.surface_forms),
|
|
1309
|
+
vectorData,
|
|
1310
|
+
statistics: {
|
|
1311
|
+
totalDocuments: raw.statistics?.total_documents ?? 0,
|
|
1312
|
+
totalFieldLengths: raw.statistics?.total_field_lengths ?? {},
|
|
1313
|
+
averageFieldLengths: raw.statistics?.average_field_lengths ?? {},
|
|
1314
|
+
docFrequencies: raw.statistics?.doc_frequencies ?? {}
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
function deserializePayloadV1(data) {
|
|
1319
|
+
const raw = decode(data);
|
|
1320
|
+
return wireToPartition(raw);
|
|
1321
|
+
}
|
|
1322
|
+
function metadataToWire(meta) {
|
|
1323
|
+
const wire = {
|
|
1324
|
+
index_name: meta.indexName,
|
|
1325
|
+
schema: meta.schema,
|
|
1326
|
+
language: meta.language,
|
|
1327
|
+
partition_count: meta.partitionCount,
|
|
1328
|
+
bm25_params: meta.bm25Params,
|
|
1329
|
+
created_at: meta.createdAt,
|
|
1330
|
+
engine_version: meta.engineVersion
|
|
1331
|
+
};
|
|
1332
|
+
if (meta.vectorFields) {
|
|
1333
|
+
wire.vector_fields = meta.vectorFields;
|
|
1334
|
+
}
|
|
1335
|
+
if (meta.embedding) {
|
|
1336
|
+
wire.embedding = meta.embedding.adapter !== void 0 ? { adapter: meta.embedding.adapter, fields: meta.embedding.fields } : { fields: meta.embedding.fields };
|
|
1337
|
+
}
|
|
1338
|
+
if (meta.surfaceForms === true) {
|
|
1339
|
+
wire.surface_forms_enabled = true;
|
|
1340
|
+
}
|
|
1341
|
+
return wire;
|
|
1342
|
+
}
|
|
1343
|
+
function wireToMetadata(raw) {
|
|
1344
|
+
const meta = {
|
|
1345
|
+
indexName: raw.index_name,
|
|
1346
|
+
schema: raw.schema ?? {},
|
|
1347
|
+
language: raw.language ?? "english",
|
|
1348
|
+
partitionCount: raw.partition_count ?? 1,
|
|
1349
|
+
bm25Params: raw.bm25_params ?? { k1: 1.2, b: 0.75 },
|
|
1350
|
+
createdAt: raw.created_at ?? 0,
|
|
1351
|
+
engineVersion: raw.engine_version ?? "0.0.0"
|
|
1352
|
+
};
|
|
1353
|
+
if (raw.vector_fields) {
|
|
1354
|
+
meta.vectorFields = raw.vector_fields;
|
|
1355
|
+
}
|
|
1356
|
+
if (raw.embedding && typeof raw.embedding === "object" && typeof raw.embedding.fields === "object") {
|
|
1357
|
+
meta.embedding = typeof raw.embedding.adapter === "string" ? { adapter: raw.embedding.adapter, fields: raw.embedding.fields } : { fields: raw.embedding.fields };
|
|
1358
|
+
}
|
|
1359
|
+
if (raw.surface_forms_enabled === true) {
|
|
1360
|
+
meta.surfaceForms = true;
|
|
1361
|
+
}
|
|
1362
|
+
return meta;
|
|
1363
|
+
}
|
|
1364
|
+
function serializeMetadata(meta) {
|
|
1365
|
+
const wire = metadataToWire(meta);
|
|
1366
|
+
return encode(wire);
|
|
1367
|
+
}
|
|
1368
|
+
function deserializeMetadata(data) {
|
|
1369
|
+
const raw = decode(data);
|
|
1370
|
+
return wireToMetadata(raw);
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// src/serialization/payload-v2.ts
|
|
1374
|
+
function encodeRawPayloadV2(wire) {
|
|
1375
|
+
return encode(wire);
|
|
1376
|
+
}
|
|
1377
|
+
var VALID_HNSW_METRICS2 = /* @__PURE__ */ new Set(["cosine", "dotProduct", "euclidean"]);
|
|
1378
|
+
function validateHnswMetric2(value) {
|
|
1379
|
+
if (value === void 0 || value === null) return void 0;
|
|
1380
|
+
if (typeof value === "string" && VALID_HNSW_METRICS2.has(value)) {
|
|
1381
|
+
return value;
|
|
1382
|
+
}
|
|
1383
|
+
return void 0;
|
|
1384
|
+
}
|
|
1134
1385
|
function deserializePayloadV2(data) {
|
|
1135
1386
|
const raw = decode(data);
|
|
1136
1387
|
const documents = {};
|
|
@@ -1180,7 +1431,7 @@ function deserializePayloadV2(data) {
|
|
|
1180
1431
|
maxLayer: data2.hnsw_graph.max_layer,
|
|
1181
1432
|
m: data2.hnsw_graph.m,
|
|
1182
1433
|
efConstruction: data2.hnsw_graph.ef_construction,
|
|
1183
|
-
metric:
|
|
1434
|
+
metric: validateHnswMetric2(data2.hnsw_graph.metric),
|
|
1184
1435
|
nodes: data2.hnsw_graph.nodes
|
|
1185
1436
|
} : null,
|
|
1186
1437
|
sq8: data2.sq8 ? {
|
|
@@ -1208,6 +1459,7 @@ function deserializePayloadV2(data) {
|
|
|
1208
1459
|
enum: raw.field_indexes?.enum ?? {},
|
|
1209
1460
|
geopoint
|
|
1210
1461
|
},
|
|
1462
|
+
surfaceForms: sanitizeSurfaceForms(raw.surface_forms),
|
|
1211
1463
|
vectorData,
|
|
1212
1464
|
statistics: {
|
|
1213
1465
|
totalDocuments: raw.statistics?.total_documents ?? 0,
|
|
@@ -1374,7 +1626,8 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1374
1626
|
fieldNameIndices: new Uint8Array(INITIAL_CAPACITY),
|
|
1375
1627
|
positions: null,
|
|
1376
1628
|
docIdSet: /* @__PURE__ */ new Set(),
|
|
1377
|
-
deletedDocs: /* @__PURE__ */ new Set()
|
|
1629
|
+
deletedDocs: /* @__PURE__ */ new Set(),
|
|
1630
|
+
totalTermFrequency: 0
|
|
1378
1631
|
};
|
|
1379
1632
|
index.set(token, list);
|
|
1380
1633
|
trackToken(token);
|
|
@@ -1404,6 +1657,8 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1404
1657
|
}
|
|
1405
1658
|
}
|
|
1406
1659
|
writeIdx++;
|
|
1660
|
+
} else {
|
|
1661
|
+
list.totalTermFrequency -= list.termFrequencies[i];
|
|
1407
1662
|
}
|
|
1408
1663
|
}
|
|
1409
1664
|
list.docIds.length = writeIdx;
|
|
@@ -1424,6 +1679,8 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1424
1679
|
}
|
|
1425
1680
|
}
|
|
1426
1681
|
writeIdx++;
|
|
1682
|
+
} else {
|
|
1683
|
+
list.totalTermFrequency -= list.termFrequencies[i];
|
|
1427
1684
|
}
|
|
1428
1685
|
}
|
|
1429
1686
|
list.docIds.length = writeIdx;
|
|
@@ -1444,6 +1701,7 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1444
1701
|
list.docIds.push(internalId);
|
|
1445
1702
|
list.termFrequencies[idx] = termFrequency > MAX_TERM_FREQUENCY ? MAX_TERM_FREQUENCY : termFrequency;
|
|
1446
1703
|
list.fieldNameIndices[idx] = fieldNameIndex;
|
|
1704
|
+
list.totalTermFrequency += list.termFrequencies[idx];
|
|
1447
1705
|
if (positions !== null) {
|
|
1448
1706
|
if (!list.positions) {
|
|
1449
1707
|
list.positions = [];
|
|
@@ -1571,12 +1829,14 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1571
1829
|
const fieldNameIndices = new Uint8Array(count);
|
|
1572
1830
|
let hasPositions = false;
|
|
1573
1831
|
let validCount = 0;
|
|
1832
|
+
let totalTermFrequency = 0;
|
|
1574
1833
|
for (let i = 0; i < count; i++) {
|
|
1575
1834
|
const p = src.postings[i];
|
|
1576
1835
|
const internalId = resolver.toInternal(p.docId);
|
|
1577
1836
|
if (internalId === void 0) continue;
|
|
1578
1837
|
docIds[validCount] = internalId;
|
|
1579
1838
|
termFrequencies[validCount] = p.termFrequency > MAX_TERM_FREQUENCY ? MAX_TERM_FREQUENCY : p.termFrequency;
|
|
1839
|
+
totalTermFrequency += termFrequencies[validCount];
|
|
1580
1840
|
let fnIndex = fieldNameTable.indexMap.get(p.fieldName);
|
|
1581
1841
|
if (fnIndex === void 0) {
|
|
1582
1842
|
fnIndex = fieldNameTable.names.length;
|
|
@@ -1610,7 +1870,8 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1610
1870
|
fieldNameIndices: finalFNI,
|
|
1611
1871
|
positions,
|
|
1612
1872
|
docIdSet,
|
|
1613
|
-
deletedDocs: /* @__PURE__ */ new Set()
|
|
1873
|
+
deletedDocs: /* @__PURE__ */ new Set(),
|
|
1874
|
+
totalTermFrequency
|
|
1614
1875
|
});
|
|
1615
1876
|
trackToken(token);
|
|
1616
1877
|
}
|
|
@@ -1752,6 +2013,115 @@ function createPartitionStats() {
|
|
|
1752
2013
|
return stats;
|
|
1753
2014
|
}
|
|
1754
2015
|
|
|
2016
|
+
// src/core/surface-registry.ts
|
|
2017
|
+
function createSurfaceRegistry() {
|
|
2018
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2019
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
2020
|
+
let totalsByToken = null;
|
|
2021
|
+
function track(surface) {
|
|
2022
|
+
const ch = surface[0];
|
|
2023
|
+
let bucket = buckets.get(ch);
|
|
2024
|
+
if (!bucket) {
|
|
2025
|
+
bucket = /* @__PURE__ */ new Set();
|
|
2026
|
+
buckets.set(ch, bucket);
|
|
2027
|
+
}
|
|
2028
|
+
bucket.add(surface);
|
|
2029
|
+
}
|
|
2030
|
+
function untrack(surface) {
|
|
2031
|
+
const ch = surface[0];
|
|
2032
|
+
const bucket = buckets.get(ch);
|
|
2033
|
+
if (bucket) {
|
|
2034
|
+
bucket.delete(surface);
|
|
2035
|
+
if (bucket.size === 0) buckets.delete(ch);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
function adjustTotals(token, delta) {
|
|
2039
|
+
if (!totalsByToken || delta === 0) return;
|
|
2040
|
+
const next = (totalsByToken.get(token) ?? 0) + delta;
|
|
2041
|
+
if (next <= 0) totalsByToken.delete(token);
|
|
2042
|
+
else totalsByToken.set(token, next);
|
|
2043
|
+
}
|
|
2044
|
+
return {
|
|
2045
|
+
add(surface, token, occurrences) {
|
|
2046
|
+
if (surface.length === 0 || token.length === 0 || occurrences <= 0) return;
|
|
2047
|
+
if (surface === token) return;
|
|
2048
|
+
const existing = entries.get(surface);
|
|
2049
|
+
if (existing) {
|
|
2050
|
+
existing.count += occurrences;
|
|
2051
|
+
adjustTotals(existing.token, occurrences);
|
|
2052
|
+
return;
|
|
2053
|
+
}
|
|
2054
|
+
entries.set(surface, { token, count: occurrences });
|
|
2055
|
+
track(surface);
|
|
2056
|
+
adjustTotals(token, occurrences);
|
|
2057
|
+
},
|
|
2058
|
+
subtract(surface, occurrences) {
|
|
2059
|
+
if (occurrences <= 0) return;
|
|
2060
|
+
const existing = entries.get(surface);
|
|
2061
|
+
if (!existing) return;
|
|
2062
|
+
const removed = Math.min(occurrences, existing.count);
|
|
2063
|
+
existing.count -= occurrences;
|
|
2064
|
+
adjustTotals(existing.token, -removed);
|
|
2065
|
+
if (existing.count <= 0) {
|
|
2066
|
+
entries.delete(surface);
|
|
2067
|
+
untrack(surface);
|
|
2068
|
+
}
|
|
2069
|
+
},
|
|
2070
|
+
candidatesForPrefix(prefix) {
|
|
2071
|
+
if (prefix.length === 0) return [];
|
|
2072
|
+
const bucket = buckets.get(prefix[0]);
|
|
2073
|
+
if (!bucket) return [];
|
|
2074
|
+
const results = [];
|
|
2075
|
+
for (const surface of bucket) {
|
|
2076
|
+
if (surface.length < prefix.length || !surface.startsWith(prefix)) continue;
|
|
2077
|
+
const entry = entries.get(surface);
|
|
2078
|
+
if (!entry) continue;
|
|
2079
|
+
results.push({ surface, token: entry.token, occurrences: entry.count });
|
|
2080
|
+
}
|
|
2081
|
+
return results;
|
|
2082
|
+
},
|
|
2083
|
+
stemChangedTotalFor(token) {
|
|
2084
|
+
if (!totalsByToken) {
|
|
2085
|
+
totalsByToken = /* @__PURE__ */ new Map();
|
|
2086
|
+
for (const entry of entries.values()) {
|
|
2087
|
+
totalsByToken.set(entry.token, (totalsByToken.get(entry.token) ?? 0) + entry.count);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
return totalsByToken.get(token) ?? 0;
|
|
2091
|
+
},
|
|
2092
|
+
size() {
|
|
2093
|
+
return entries.size;
|
|
2094
|
+
},
|
|
2095
|
+
clear() {
|
|
2096
|
+
entries.clear();
|
|
2097
|
+
buckets.clear();
|
|
2098
|
+
totalsByToken = null;
|
|
2099
|
+
},
|
|
2100
|
+
serialize() {
|
|
2101
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
2102
|
+
for (const [surface, entry] of entries) {
|
|
2103
|
+
result[surface] = [entry.count, entry.token];
|
|
2104
|
+
}
|
|
2105
|
+
return result;
|
|
2106
|
+
},
|
|
2107
|
+
deserialize(data) {
|
|
2108
|
+
entries.clear();
|
|
2109
|
+
buckets.clear();
|
|
2110
|
+
totalsByToken = null;
|
|
2111
|
+
for (const surface of Object.keys(data)) {
|
|
2112
|
+
if (surface.length === 0) continue;
|
|
2113
|
+
const value = data[surface];
|
|
2114
|
+
if (!Array.isArray(value) || typeof value[0] !== "number" || typeof value[1] !== "string") continue;
|
|
2115
|
+
const count = value[0];
|
|
2116
|
+
const token = value[1];
|
|
2117
|
+
if (!Number.isFinite(count) || count <= 0 || token.length === 0 || token === surface) continue;
|
|
2118
|
+
entries.set(surface, { token, count: Math.floor(count) });
|
|
2119
|
+
track(surface);
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
|
|
1755
2125
|
// src/core/partition/utils.ts
|
|
1756
2126
|
function getOrCreateFieldNameIndex(table, fieldName) {
|
|
1757
2127
|
const existing = table.indexMap.get(fieldName);
|
|
@@ -1796,6 +2166,7 @@ function tokenizeOptions(options) {
|
|
|
1796
2166
|
return {
|
|
1797
2167
|
stem: true,
|
|
1798
2168
|
removeStopWords: true,
|
|
2169
|
+
collectSurfaces: options?.collectSurfaces === true,
|
|
1799
2170
|
stopWordOverride: options?.stopWordOverride,
|
|
1800
2171
|
customTokenizer: options?.customTokenizer
|
|
1801
2172
|
};
|
|
@@ -1881,1197 +2252,1241 @@ function computeFacets(state, docIds, config, schema) {
|
|
|
1881
2252
|
return result;
|
|
1882
2253
|
}
|
|
1883
2254
|
|
|
1884
|
-
// src/
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
let result = bitsets[0];
|
|
1898
|
-
for (let i = 1; i < bitsets.length; i++) {
|
|
1899
|
-
result = bitsetOr(result, bitsets[i]);
|
|
1900
|
-
}
|
|
1901
|
-
return result;
|
|
1902
|
-
}
|
|
1903
|
-
function applyNotBitset(excluded, capacity) {
|
|
1904
|
-
return bitsetNot(excluded, capacity);
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
// src/filters/operators/shared.ts
|
|
1908
|
-
var METERS_PER_KM = 1e3;
|
|
1909
|
-
var METERS_PER_MI = 1609.344;
|
|
1910
|
-
function convertToMeters(distance, unit) {
|
|
1911
|
-
if (unit === "km") return distance * METERS_PER_KM;
|
|
1912
|
-
if (unit === "mi") return distance * METERS_PER_MI;
|
|
1913
|
-
return distance;
|
|
1914
|
-
}
|
|
1915
|
-
function matchesNumericComparison(value, filter) {
|
|
1916
|
-
if (filter.eq !== void 0 && value !== filter.eq) return false;
|
|
1917
|
-
if (filter.ne !== void 0 && value === filter.ne) return false;
|
|
1918
|
-
if (filter.gt !== void 0 && !(value > filter.gt)) return false;
|
|
1919
|
-
if (filter.lt !== void 0 && !(value < filter.lt)) return false;
|
|
1920
|
-
if (filter.gte !== void 0 && !(value >= filter.gte)) return false;
|
|
1921
|
-
if (filter.lte !== void 0 && !(value <= filter.lte)) return false;
|
|
1922
|
-
if (filter.between !== void 0 && !(value >= filter.between[0] && value <= filter.between[1])) return false;
|
|
1923
|
-
return true;
|
|
2255
|
+
// src/geo/haversine.ts
|
|
2256
|
+
var EARTH_RADIUS_METERS = 63710088e-1;
|
|
2257
|
+
var DEG_TO_RAD = Math.PI / 180;
|
|
2258
|
+
function haversineDistance(lat1, lon1, lat2, lon2) {
|
|
2259
|
+
const phi1 = lat1 * DEG_TO_RAD;
|
|
2260
|
+
const phi2 = lat2 * DEG_TO_RAD;
|
|
2261
|
+
const deltaPhi = (lat2 - lat1) * DEG_TO_RAD;
|
|
2262
|
+
const deltaLambda = (lon2 - lon1) * DEG_TO_RAD;
|
|
2263
|
+
const halfDeltaPhi = Math.sin(deltaPhi / 2);
|
|
2264
|
+
const halfDeltaLambda = Math.sin(deltaLambda / 2);
|
|
2265
|
+
const a = halfDeltaPhi * halfDeltaPhi + Math.cos(phi1) * Math.cos(phi2) * halfDeltaLambda * halfDeltaLambda;
|
|
2266
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
2267
|
+
return EARTH_RADIUS_METERS * c;
|
|
1924
2268
|
}
|
|
1925
2269
|
|
|
1926
|
-
// src/
|
|
1927
|
-
function
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
const
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
bitsetSet(result, id);
|
|
2270
|
+
// src/geo/polygon.ts
|
|
2271
|
+
function isPointInPolygon(lat, lon, polygon) {
|
|
2272
|
+
if (polygon.length < 3) return false;
|
|
2273
|
+
let inside = false;
|
|
2274
|
+
const n = polygon.length;
|
|
2275
|
+
for (let i = 0, j = n - 1; i < n; j = i++) {
|
|
2276
|
+
const lonI = polygon[i].lon;
|
|
2277
|
+
const latI = polygon[i].lat;
|
|
2278
|
+
const lonJ = polygon[j].lon;
|
|
2279
|
+
const latJ = polygon[j].lat;
|
|
2280
|
+
if (lonI > lon !== lonJ > lon) {
|
|
2281
|
+
const slope = (latJ - latI) / (lonJ - lonI);
|
|
2282
|
+
const intersectLat = latI + slope * (lon - lonI);
|
|
2283
|
+
if (lat < intersectLat) {
|
|
2284
|
+
inside = !inside;
|
|
1942
2285
|
}
|
|
1943
|
-
word &= word - 1;
|
|
1944
2286
|
}
|
|
1945
2287
|
}
|
|
1946
|
-
return
|
|
2288
|
+
return inside;
|
|
1947
2289
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
}
|
|
1994
|
-
function applyLteBitset(value, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
1995
|
-
if (fieldIndex?.type === "numeric") {
|
|
1996
|
-
return fieldIndex.index.lteBitset(value, capacity);
|
|
1997
|
-
}
|
|
1998
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "number" && v <= value);
|
|
1999
|
-
}
|
|
2000
|
-
function applyBetweenBitset(range, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
2001
|
-
if (fieldIndex?.type === "numeric") {
|
|
2002
|
-
return fieldIndex.index.betweenBitset(range[0], range[1], capacity);
|
|
2003
|
-
}
|
|
2004
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "number" && v >= range[0] && v <= range[1]);
|
|
2005
|
-
}
|
|
2006
|
-
function applyInBitset(values, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
2007
|
-
if (fieldIndex?.type === "enum") {
|
|
2008
|
-
return fieldIndex.index.getDocIdsInBitset(values, capacity);
|
|
2009
|
-
}
|
|
2010
|
-
const valSet = new Set(values);
|
|
2011
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "string" && valSet.has(v));
|
|
2012
|
-
}
|
|
2013
|
-
function applyNinBitset(values, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
2014
|
-
if (fieldIndex?.type === "enum") {
|
|
2015
|
-
const all = fieldIndex.index.allDocIdsBitset(capacity);
|
|
2016
|
-
const matched = fieldIndex.index.getDocIdsInBitset(values, capacity);
|
|
2017
|
-
return bitsetAnd(all, bitsetNot(matched, capacity));
|
|
2290
|
+
|
|
2291
|
+
// src/geo/vincenty.ts
|
|
2292
|
+
var WGS84_A = 6378137;
|
|
2293
|
+
var WGS84_F = 1 / 298.257223563;
|
|
2294
|
+
var WGS84_B = WGS84_A * (1 - WGS84_F);
|
|
2295
|
+
var DEG_TO_RAD2 = Math.PI / 180;
|
|
2296
|
+
var MAX_ITERATIONS = 200;
|
|
2297
|
+
var CONVERGENCE_THRESHOLD = 1e-12;
|
|
2298
|
+
function vincentyDistance(lat1, lon1, lat2, lon2) {
|
|
2299
|
+
const phi1 = lat1 * DEG_TO_RAD2;
|
|
2300
|
+
const phi2 = lat2 * DEG_TO_RAD2;
|
|
2301
|
+
const L = (lon2 - lon1) * DEG_TO_RAD2;
|
|
2302
|
+
const U1 = Math.atan((1 - WGS84_F) * Math.tan(phi1));
|
|
2303
|
+
const U2 = Math.atan((1 - WGS84_F) * Math.tan(phi2));
|
|
2304
|
+
const sinU1 = Math.sin(U1);
|
|
2305
|
+
const cosU1 = Math.cos(U1);
|
|
2306
|
+
const sinU2 = Math.sin(U2);
|
|
2307
|
+
const cosU2 = Math.cos(U2);
|
|
2308
|
+
let lambda = L;
|
|
2309
|
+
let prevLambda;
|
|
2310
|
+
let sinSigma = 0;
|
|
2311
|
+
let cosSigma = 0;
|
|
2312
|
+
let sigma = 0;
|
|
2313
|
+
let sinAlpha = 0;
|
|
2314
|
+
let cos2Alpha = 0;
|
|
2315
|
+
let cos2SigmaM = 0;
|
|
2316
|
+
let iterations = MAX_ITERATIONS;
|
|
2317
|
+
do {
|
|
2318
|
+
const sinLambda = Math.sin(lambda);
|
|
2319
|
+
const cosLambda = Math.cos(lambda);
|
|
2320
|
+
const term1 = cosU2 * sinLambda;
|
|
2321
|
+
const term2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
|
|
2322
|
+
sinSigma = Math.sqrt(term1 * term1 + term2 * term2);
|
|
2323
|
+
if (sinSigma === 0) return 0;
|
|
2324
|
+
cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
|
|
2325
|
+
sigma = Math.atan2(sinSigma, cosSigma);
|
|
2326
|
+
sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
|
|
2327
|
+
cos2Alpha = 1 - sinAlpha * sinAlpha;
|
|
2328
|
+
cos2SigmaM = cos2Alpha === 0 ? 0 : cosSigma - 2 * sinU1 * sinU2 / cos2Alpha;
|
|
2329
|
+
const C = WGS84_F / 16 * cos2Alpha * (4 + WGS84_F * (4 - 3 * cos2Alpha));
|
|
2330
|
+
prevLambda = lambda;
|
|
2331
|
+
lambda = L + (1 - C) * WGS84_F * sinAlpha * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
|
|
2332
|
+
} while (Math.abs(lambda - prevLambda) > CONVERGENCE_THRESHOLD && --iterations > 0);
|
|
2333
|
+
if (iterations === 0) {
|
|
2334
|
+
return haversineDistance(lat1, lon1, lat2, lon2);
|
|
2018
2335
|
}
|
|
2019
|
-
const
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
(v) => v !== void 0 && v !== null && typeof v === "string" && !valSet.has(v)
|
|
2025
|
-
);
|
|
2026
|
-
}
|
|
2027
|
-
function applyStartsWithBitset(prefix, allDocsBitset, capacity, getValue) {
|
|
2028
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "string" && v.startsWith(prefix));
|
|
2336
|
+
const uSq = cos2Alpha * (WGS84_A * WGS84_A - WGS84_B * WGS84_B) / (WGS84_B * WGS84_B);
|
|
2337
|
+
const A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
|
2338
|
+
const B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
|
2339
|
+
const deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
|
|
2340
|
+
return WGS84_B * A * (sigma - deltaSigma);
|
|
2029
2341
|
}
|
|
2030
|
-
|
|
2031
|
-
|
|
2342
|
+
|
|
2343
|
+
// src/geo/geo-index.ts
|
|
2344
|
+
function createGeoIndex() {
|
|
2345
|
+
const entries = [];
|
|
2346
|
+
return {
|
|
2347
|
+
get entries() {
|
|
2348
|
+
return entries;
|
|
2349
|
+
},
|
|
2350
|
+
insert(internalId, lat, lon) {
|
|
2351
|
+
entries.push({ lat, lon, docId: internalId });
|
|
2352
|
+
},
|
|
2353
|
+
remove(internalId) {
|
|
2354
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
2355
|
+
if (entries[i].docId === internalId) {
|
|
2356
|
+
entries.splice(i, 1);
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
},
|
|
2361
|
+
radiusQuery(lat, lon, distanceMeters, inside, highPrecision) {
|
|
2362
|
+
const result = /* @__PURE__ */ new Set();
|
|
2363
|
+
const distanceFn = highPrecision ? vincentyDistance : haversineDistance;
|
|
2364
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2365
|
+
const entry = entries[i];
|
|
2366
|
+
const dist = distanceFn(lat, lon, entry.lat, entry.lon);
|
|
2367
|
+
const withinRadius = dist <= distanceMeters;
|
|
2368
|
+
if (inside ? withinRadius : !withinRadius) {
|
|
2369
|
+
result.add(entry.docId);
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
return result;
|
|
2373
|
+
},
|
|
2374
|
+
polygonQuery(points, inside) {
|
|
2375
|
+
const result = /* @__PURE__ */ new Set();
|
|
2376
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2377
|
+
const entry = entries[i];
|
|
2378
|
+
const withinPolygon = isPointInPolygon(entry.lat, entry.lon, points);
|
|
2379
|
+
if (inside ? withinPolygon : !withinPolygon) {
|
|
2380
|
+
result.add(entry.docId);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
return result;
|
|
2384
|
+
},
|
|
2385
|
+
clear() {
|
|
2386
|
+
entries.length = 0;
|
|
2387
|
+
},
|
|
2388
|
+
serialize() {
|
|
2389
|
+
return entries.map((e) => ({ ...e }));
|
|
2390
|
+
},
|
|
2391
|
+
deserialize(data) {
|
|
2392
|
+
entries.length = 0;
|
|
2393
|
+
for (const entry of data) {
|
|
2394
|
+
entries.push({ lat: entry.lat, lon: entry.lon, docId: entry.docId });
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
};
|
|
2032
2398
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2399
|
+
|
|
2400
|
+
// src/core/field-index/boolean.ts
|
|
2401
|
+
function createBooleanIndex() {
|
|
2402
|
+
const trueDocs = /* @__PURE__ */ new Set();
|
|
2403
|
+
const falseDocs = /* @__PURE__ */ new Set();
|
|
2404
|
+
return {
|
|
2405
|
+
insert(internalId, value) {
|
|
2406
|
+
if (value) trueDocs.add(internalId);
|
|
2407
|
+
else falseDocs.add(internalId);
|
|
2408
|
+
},
|
|
2409
|
+
remove(internalId, value) {
|
|
2410
|
+
if (value) trueDocs.delete(internalId);
|
|
2411
|
+
else falseDocs.delete(internalId);
|
|
2412
|
+
},
|
|
2413
|
+
queryEq(value) {
|
|
2414
|
+
return new Set(value ? trueDocs : falseDocs);
|
|
2415
|
+
},
|
|
2416
|
+
queryNe(value) {
|
|
2417
|
+
return new Set(value ? falseDocs : trueDocs);
|
|
2418
|
+
},
|
|
2419
|
+
getAllDocIds() {
|
|
2420
|
+
const all = new Set(trueDocs);
|
|
2421
|
+
for (const id of falseDocs) all.add(id);
|
|
2422
|
+
return all;
|
|
2423
|
+
},
|
|
2424
|
+
queryEqBitset(value, capacity) {
|
|
2425
|
+
const source = value ? trueDocs : falseDocs;
|
|
2426
|
+
const bs = createBitSet(capacity);
|
|
2427
|
+
for (const id of source) {
|
|
2428
|
+
bitsetSet(bs, id);
|
|
2429
|
+
}
|
|
2430
|
+
return bs;
|
|
2431
|
+
},
|
|
2432
|
+
getAllDocIdsBitset(capacity) {
|
|
2433
|
+
const bs = createBitSet(capacity);
|
|
2434
|
+
for (const id of trueDocs) bitsetSet(bs, id);
|
|
2435
|
+
for (const id of falseDocs) bitsetSet(bs, id);
|
|
2436
|
+
return bs;
|
|
2437
|
+
},
|
|
2438
|
+
count() {
|
|
2439
|
+
return trueDocs.size + falseDocs.size;
|
|
2440
|
+
},
|
|
2441
|
+
clear() {
|
|
2442
|
+
trueDocs.clear();
|
|
2443
|
+
falseDocs.clear();
|
|
2444
|
+
},
|
|
2445
|
+
serialize() {
|
|
2446
|
+
return {
|
|
2447
|
+
trueDocs: Array.from(trueDocs),
|
|
2448
|
+
falseDocs: Array.from(falseDocs)
|
|
2449
|
+
};
|
|
2450
|
+
},
|
|
2451
|
+
deserialize(data) {
|
|
2452
|
+
trueDocs.clear();
|
|
2453
|
+
falseDocs.clear();
|
|
2454
|
+
for (const id of data.trueDocs) trueDocs.add(id);
|
|
2455
|
+
for (const id of data.falseDocs) falseDocs.add(id);
|
|
2039
2456
|
}
|
|
2040
|
-
|
|
2041
|
-
});
|
|
2457
|
+
};
|
|
2042
2458
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2459
|
+
|
|
2460
|
+
// src/core/field-index/enum.ts
|
|
2461
|
+
function createEnumIndex() {
|
|
2462
|
+
const valueMap = /* @__PURE__ */ new Map();
|
|
2463
|
+
function allDocs() {
|
|
2464
|
+
const result = /* @__PURE__ */ new Set();
|
|
2465
|
+
for (const docSet of valueMap.values()) {
|
|
2466
|
+
for (const id of docSet) result.add(id);
|
|
2467
|
+
}
|
|
2468
|
+
return result;
|
|
2469
|
+
}
|
|
2470
|
+
return {
|
|
2471
|
+
insert(internalId, value) {
|
|
2472
|
+
let docSet = valueMap.get(value);
|
|
2473
|
+
if (!docSet) {
|
|
2474
|
+
docSet = /* @__PURE__ */ new Set();
|
|
2475
|
+
valueMap.set(value, docSet);
|
|
2476
|
+
}
|
|
2477
|
+
docSet.add(internalId);
|
|
2478
|
+
},
|
|
2479
|
+
remove(internalId, value) {
|
|
2480
|
+
const docSet = valueMap.get(value);
|
|
2481
|
+
if (!docSet) return;
|
|
2482
|
+
docSet.delete(internalId);
|
|
2483
|
+
if (docSet.size === 0) valueMap.delete(value);
|
|
2484
|
+
},
|
|
2485
|
+
queryEq(value) {
|
|
2486
|
+
const docSet = valueMap.get(value);
|
|
2487
|
+
return docSet ? new Set(docSet) : /* @__PURE__ */ new Set();
|
|
2488
|
+
},
|
|
2489
|
+
queryNe(value) {
|
|
2490
|
+
const excluded = valueMap.get(value);
|
|
2491
|
+
const result = allDocs();
|
|
2492
|
+
if (excluded) {
|
|
2493
|
+
for (const id of excluded) result.delete(id);
|
|
2494
|
+
}
|
|
2495
|
+
return result;
|
|
2496
|
+
},
|
|
2497
|
+
queryIn(values) {
|
|
2498
|
+
const result = /* @__PURE__ */ new Set();
|
|
2499
|
+
for (const val of values) {
|
|
2500
|
+
const docSet = valueMap.get(val);
|
|
2501
|
+
if (docSet) {
|
|
2502
|
+
for (const id of docSet) result.add(id);
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
return result;
|
|
2506
|
+
},
|
|
2507
|
+
queryNin(values) {
|
|
2508
|
+
const excluded = this.queryIn(values);
|
|
2509
|
+
const result = allDocs();
|
|
2510
|
+
for (const id of excluded) result.delete(id);
|
|
2511
|
+
return result;
|
|
2512
|
+
},
|
|
2513
|
+
getAllDocIds() {
|
|
2514
|
+
return allDocs();
|
|
2515
|
+
},
|
|
2516
|
+
queryEqBitset(value, capacity) {
|
|
2517
|
+
const bs = createBitSet(capacity);
|
|
2518
|
+
const docSet = valueMap.get(value);
|
|
2519
|
+
if (docSet) {
|
|
2520
|
+
for (const id of docSet) bitsetSet(bs, id);
|
|
2521
|
+
}
|
|
2522
|
+
return bs;
|
|
2523
|
+
},
|
|
2524
|
+
queryInBitset(values, capacity) {
|
|
2525
|
+
const bs = createBitSet(capacity);
|
|
2526
|
+
for (const val of values) {
|
|
2527
|
+
const docSet = valueMap.get(val);
|
|
2528
|
+
if (docSet) {
|
|
2529
|
+
for (const id of docSet) bitsetSet(bs, id);
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
return bs;
|
|
2533
|
+
},
|
|
2534
|
+
getAllDocIdsBitset(capacity) {
|
|
2535
|
+
const bs = createBitSet(capacity);
|
|
2536
|
+
for (const docSet of valueMap.values()) {
|
|
2537
|
+
for (const id of docSet) bitsetSet(bs, id);
|
|
2538
|
+
}
|
|
2539
|
+
return bs;
|
|
2540
|
+
},
|
|
2541
|
+
count() {
|
|
2542
|
+
let total = 0;
|
|
2543
|
+
for (const docSet of valueMap.values()) total += docSet.size;
|
|
2544
|
+
return total;
|
|
2545
|
+
},
|
|
2546
|
+
clear() {
|
|
2547
|
+
valueMap.clear();
|
|
2548
|
+
},
|
|
2549
|
+
serialize() {
|
|
2550
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
2551
|
+
for (const [value, docSet] of valueMap) {
|
|
2552
|
+
result[value] = Array.from(docSet);
|
|
2553
|
+
}
|
|
2554
|
+
return result;
|
|
2555
|
+
},
|
|
2556
|
+
deserialize(data) {
|
|
2557
|
+
valueMap.clear();
|
|
2558
|
+
for (const value of Object.keys(data)) {
|
|
2559
|
+
valueMap.set(value, new Set(data[value]));
|
|
2560
|
+
}
|
|
2049
2561
|
}
|
|
2050
|
-
|
|
2051
|
-
});
|
|
2052
|
-
}
|
|
2053
|
-
function applySizeBitset(sizeFilter, allDocsBitset, capacity, getValue) {
|
|
2054
|
-
return scanToBitset(
|
|
2055
|
-
allDocsBitset,
|
|
2056
|
-
capacity,
|
|
2057
|
-
getValue,
|
|
2058
|
-
(v) => Array.isArray(v) && matchesNumericComparison(v.length, sizeFilter)
|
|
2059
|
-
);
|
|
2060
|
-
}
|
|
2061
|
-
function applyExistsBitset(allDocsBitset, capacity, getValue) {
|
|
2062
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => v !== void 0 && v !== null);
|
|
2063
|
-
}
|
|
2064
|
-
function applyNotExistsBitset(allDocsBitset, capacity, getValue) {
|
|
2065
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => v === void 0 || v === null);
|
|
2066
|
-
}
|
|
2067
|
-
function applyIsEmptyBitset(allDocsBitset, capacity, getValue) {
|
|
2068
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => {
|
|
2069
|
-
if (v === void 0 || v === null) return true;
|
|
2070
|
-
if (typeof v === "string" && v === "") return true;
|
|
2071
|
-
if (Array.isArray(v) && v.length === 0) return true;
|
|
2072
|
-
return false;
|
|
2073
|
-
});
|
|
2074
|
-
}
|
|
2075
|
-
function applyIsNotEmptyBitset(allDocsBitset, capacity, getValue) {
|
|
2076
|
-
return scanToBitset(allDocsBitset, capacity, getValue, (v) => {
|
|
2077
|
-
if (v === void 0 || v === null) return false;
|
|
2078
|
-
if (typeof v === "string" && v === "") return false;
|
|
2079
|
-
if (Array.isArray(v) && v.length === 0) return false;
|
|
2080
|
-
return true;
|
|
2081
|
-
});
|
|
2082
|
-
}
|
|
2083
|
-
function applyGeoRadiusBitset(filter, geoIndex, capacity) {
|
|
2084
|
-
const distanceMeters = convertToMeters(filter.distance, filter.unit);
|
|
2085
|
-
const setResult = geoIndex.radiusQuery(
|
|
2086
|
-
filter.lat,
|
|
2087
|
-
filter.lon,
|
|
2088
|
-
distanceMeters,
|
|
2089
|
-
filter.inside ?? true,
|
|
2090
|
-
filter.highPrecision ?? false
|
|
2091
|
-
);
|
|
2092
|
-
return bitsetFromSet(setResult, capacity);
|
|
2093
|
-
}
|
|
2094
|
-
function applyGeoPolygonBitset(filter, geoIndex, capacity) {
|
|
2095
|
-
const setResult = geoIndex.polygonQuery(filter.points, filter.inside ?? true);
|
|
2096
|
-
return bitsetFromSet(setResult, capacity);
|
|
2562
|
+
};
|
|
2097
2563
|
}
|
|
2098
2564
|
|
|
2099
|
-
// src/
|
|
2100
|
-
function
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2565
|
+
// src/core/field-index/numeric.ts
|
|
2566
|
+
function lowerBound(entries, value) {
|
|
2567
|
+
let lo = 0;
|
|
2568
|
+
let hi = entries.length;
|
|
2569
|
+
while (lo < hi) {
|
|
2570
|
+
const mid = lo + hi >>> 1;
|
|
2571
|
+
if (entries[mid].value < value) lo = mid + 1;
|
|
2572
|
+
else hi = mid;
|
|
2106
2573
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2574
|
+
return lo;
|
|
2575
|
+
}
|
|
2576
|
+
function upperBound(entries, value) {
|
|
2577
|
+
let lo = 0;
|
|
2578
|
+
let hi = entries.length;
|
|
2579
|
+
while (lo < hi) {
|
|
2580
|
+
const mid = lo + hi >>> 1;
|
|
2581
|
+
if (entries[mid].value <= value) lo = mid + 1;
|
|
2582
|
+
else hi = mid;
|
|
2110
2583
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2584
|
+
return lo;
|
|
2585
|
+
}
|
|
2586
|
+
function collectDocIds(entries, from, to) {
|
|
2587
|
+
const result = /* @__PURE__ */ new Set();
|
|
2588
|
+
for (let i = from; i < to; i++) {
|
|
2589
|
+
result.add(entries[i].docId);
|
|
2114
2590
|
}
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2591
|
+
return result;
|
|
2592
|
+
}
|
|
2593
|
+
function collectDocIdsBitset(entries, from, to, capacity) {
|
|
2594
|
+
const bs = createBitSet(capacity);
|
|
2595
|
+
for (let i = from; i < to; i++) {
|
|
2596
|
+
bitsetSet(bs, entries[i].docId);
|
|
2119
2597
|
}
|
|
2120
|
-
|
|
2121
|
-
if (bitsets.length === 1) return bitsets[0];
|
|
2122
|
-
return applyAndBitset(bitsets);
|
|
2598
|
+
return bs;
|
|
2123
2599
|
}
|
|
2124
|
-
function
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
const getAllDocsBitset = () => {
|
|
2132
|
-
if (allDocsBitset === null) {
|
|
2133
|
-
allDocsBitset = context.allDocIdsBitset;
|
|
2600
|
+
function createNumericIndex() {
|
|
2601
|
+
let entries = [];
|
|
2602
|
+
let sorted = true;
|
|
2603
|
+
function ensureSorted() {
|
|
2604
|
+
if (!sorted) {
|
|
2605
|
+
entries.sort((a, b) => a.value - b.value);
|
|
2606
|
+
sorted = true;
|
|
2134
2607
|
}
|
|
2135
|
-
return allDocsBitset;
|
|
2136
|
-
};
|
|
2137
|
-
if ("radius" in f && f.radius) {
|
|
2138
|
-
const geoIndex = resolveGeoIndex(fieldPath, fieldIndex);
|
|
2139
|
-
bitsets.push(applyGeoRadiusBitset(filter.radius, geoIndex, capacity));
|
|
2140
|
-
}
|
|
2141
|
-
if ("polygon" in f && f.polygon) {
|
|
2142
|
-
const geoIndex = resolveGeoIndex(fieldPath, fieldIndex);
|
|
2143
|
-
bitsets.push(applyGeoPolygonBitset(filter.polygon, geoIndex, capacity));
|
|
2144
|
-
}
|
|
2145
|
-
if ("eq" in f && f.eq !== void 0) {
|
|
2146
|
-
bitsets.push(applyEqBitset(f.eq, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2147
|
-
}
|
|
2148
|
-
if ("ne" in f && f.ne !== void 0) {
|
|
2149
|
-
bitsets.push(applyNeBitset(f.ne, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2150
|
-
}
|
|
2151
|
-
if ("gt" in f && f.gt !== void 0) {
|
|
2152
|
-
bitsets.push(applyGtBitset(f.gt, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2153
|
-
}
|
|
2154
|
-
if ("lt" in f && f.lt !== void 0) {
|
|
2155
|
-
bitsets.push(applyLtBitset(f.lt, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2156
|
-
}
|
|
2157
|
-
if ("gte" in f && f.gte !== void 0) {
|
|
2158
|
-
bitsets.push(applyGteBitset(f.gte, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2159
|
-
}
|
|
2160
|
-
if ("lte" in f && f.lte !== void 0) {
|
|
2161
|
-
bitsets.push(applyLteBitset(f.lte, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2162
|
-
}
|
|
2163
|
-
if ("between" in f && f.between !== void 0) {
|
|
2164
|
-
bitsets.push(applyBetweenBitset(f.between, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2165
|
-
}
|
|
2166
|
-
if ("in" in f && f.in !== void 0) {
|
|
2167
|
-
bitsets.push(applyInBitset(f.in, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2168
|
-
}
|
|
2169
|
-
if ("nin" in f && f.nin !== void 0) {
|
|
2170
|
-
bitsets.push(applyNinBitset(f.nin, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2171
|
-
}
|
|
2172
|
-
if ("startsWith" in f && f.startsWith !== void 0) {
|
|
2173
|
-
bitsets.push(applyStartsWithBitset(f.startsWith, getAllDocsBitset, capacity, getValue));
|
|
2174
|
-
}
|
|
2175
|
-
if ("endsWith" in f && f.endsWith !== void 0) {
|
|
2176
|
-
bitsets.push(applyEndsWithBitset(f.endsWith, getAllDocsBitset, capacity, getValue));
|
|
2177
|
-
}
|
|
2178
|
-
if ("containsAll" in f && f.containsAll !== void 0) {
|
|
2179
|
-
bitsets.push(
|
|
2180
|
-
applyContainsAllBitset(f.containsAll, getAllDocsBitset, capacity, getValue)
|
|
2181
|
-
);
|
|
2182
|
-
}
|
|
2183
|
-
if ("matchesAny" in f && f.matchesAny !== void 0) {
|
|
2184
|
-
bitsets.push(
|
|
2185
|
-
applyMatchesAnyBitset(f.matchesAny, getAllDocsBitset, capacity, getValue)
|
|
2186
|
-
);
|
|
2187
2608
|
}
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2609
|
+
return {
|
|
2610
|
+
insert(internalId, value) {
|
|
2611
|
+
entries.push({ value, docId: internalId });
|
|
2612
|
+
sorted = false;
|
|
2613
|
+
},
|
|
2614
|
+
remove(internalId, value) {
|
|
2615
|
+
ensureSorted();
|
|
2616
|
+
const start = lowerBound(entries, value);
|
|
2617
|
+
const end = upperBound(entries, value);
|
|
2618
|
+
for (let i = start; i < end; i++) {
|
|
2619
|
+
if (entries[i].docId === internalId) {
|
|
2620
|
+
entries.splice(i, 1);
|
|
2621
|
+
return;
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
},
|
|
2625
|
+
queryEq(value) {
|
|
2626
|
+
ensureSorted();
|
|
2627
|
+
return collectDocIds(entries, lowerBound(entries, value), upperBound(entries, value));
|
|
2628
|
+
},
|
|
2629
|
+
queryNe(value) {
|
|
2630
|
+
ensureSorted();
|
|
2631
|
+
const excluded = this.queryEq(value);
|
|
2632
|
+
const result = /* @__PURE__ */ new Set();
|
|
2633
|
+
for (const entry of entries) {
|
|
2634
|
+
if (!excluded.has(entry.docId)) result.add(entry.docId);
|
|
2635
|
+
}
|
|
2636
|
+
return result;
|
|
2637
|
+
},
|
|
2638
|
+
queryGt(value) {
|
|
2639
|
+
ensureSorted();
|
|
2640
|
+
return collectDocIds(entries, upperBound(entries, value), entries.length);
|
|
2641
|
+
},
|
|
2642
|
+
queryGte(value) {
|
|
2643
|
+
ensureSorted();
|
|
2644
|
+
return collectDocIds(entries, lowerBound(entries, value), entries.length);
|
|
2645
|
+
},
|
|
2646
|
+
queryLt(value) {
|
|
2647
|
+
ensureSorted();
|
|
2648
|
+
return collectDocIds(entries, 0, lowerBound(entries, value));
|
|
2649
|
+
},
|
|
2650
|
+
queryLte(value) {
|
|
2651
|
+
ensureSorted();
|
|
2652
|
+
return collectDocIds(entries, 0, upperBound(entries, value));
|
|
2653
|
+
},
|
|
2654
|
+
queryBetween(min, max) {
|
|
2655
|
+
ensureSorted();
|
|
2656
|
+
return collectDocIds(entries, lowerBound(entries, min), upperBound(entries, max));
|
|
2657
|
+
},
|
|
2658
|
+
getAllDocIds() {
|
|
2659
|
+
return collectDocIds(entries, 0, entries.length);
|
|
2660
|
+
},
|
|
2661
|
+
queryEqBitset(value, capacity) {
|
|
2662
|
+
ensureSorted();
|
|
2663
|
+
return collectDocIdsBitset(entries, lowerBound(entries, value), upperBound(entries, value), capacity);
|
|
2664
|
+
},
|
|
2665
|
+
queryGtBitset(value, capacity) {
|
|
2666
|
+
ensureSorted();
|
|
2667
|
+
return collectDocIdsBitset(entries, upperBound(entries, value), entries.length, capacity);
|
|
2668
|
+
},
|
|
2669
|
+
queryGteBitset(value, capacity) {
|
|
2670
|
+
ensureSorted();
|
|
2671
|
+
return collectDocIdsBitset(entries, lowerBound(entries, value), entries.length, capacity);
|
|
2672
|
+
},
|
|
2673
|
+
queryLtBitset(value, capacity) {
|
|
2674
|
+
ensureSorted();
|
|
2675
|
+
return collectDocIdsBitset(entries, 0, lowerBound(entries, value), capacity);
|
|
2676
|
+
},
|
|
2677
|
+
queryLteBitset(value, capacity) {
|
|
2678
|
+
ensureSorted();
|
|
2679
|
+
return collectDocIdsBitset(entries, 0, upperBound(entries, value), capacity);
|
|
2680
|
+
},
|
|
2681
|
+
queryBetweenBitset(min, max, capacity) {
|
|
2682
|
+
ensureSorted();
|
|
2683
|
+
return collectDocIdsBitset(entries, lowerBound(entries, min), upperBound(entries, max), capacity);
|
|
2684
|
+
},
|
|
2685
|
+
getAllDocIdsBitset(capacity) {
|
|
2686
|
+
return collectDocIdsBitset(entries, 0, entries.length, capacity);
|
|
2687
|
+
},
|
|
2688
|
+
count() {
|
|
2689
|
+
return entries.length;
|
|
2690
|
+
},
|
|
2691
|
+
clear() {
|
|
2692
|
+
entries = [];
|
|
2693
|
+
sorted = true;
|
|
2694
|
+
},
|
|
2695
|
+
serialize() {
|
|
2696
|
+
ensureSorted();
|
|
2697
|
+
return entries.slice();
|
|
2698
|
+
},
|
|
2699
|
+
deserialize(data) {
|
|
2700
|
+
entries = data.slice();
|
|
2701
|
+
sorted = true;
|
|
2702
|
+
}
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
// src/core/partition/indexing.ts
|
|
2707
|
+
function ensureFieldIndex(state, fieldPath, fieldType) {
|
|
2708
|
+
if ((fieldType === "number" || fieldType === "number[]") && !state.numericIndexes.has(fieldPath)) {
|
|
2709
|
+
state.numericIndexes.set(fieldPath, createNumericIndex());
|
|
2710
|
+
} else if ((fieldType === "boolean" || fieldType === "boolean[]") && !state.booleanIndexes.has(fieldPath)) {
|
|
2711
|
+
state.booleanIndexes.set(fieldPath, createBooleanIndex());
|
|
2712
|
+
} else if ((fieldType === "enum" || fieldType === "enum[]") && !state.enumIndexes.has(fieldPath)) {
|
|
2713
|
+
state.enumIndexes.set(fieldPath, createEnumIndex());
|
|
2714
|
+
} else if (fieldType === "geopoint" && !state.geoIndexes.has(fieldPath)) {
|
|
2715
|
+
state.geoIndexes.set(fieldPath, createGeoIndex());
|
|
2195
2716
|
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2717
|
+
}
|
|
2718
|
+
function getOrCreateNumericIndex(state, fieldPath) {
|
|
2719
|
+
let idx = state.numericIndexes.get(fieldPath);
|
|
2720
|
+
if (!idx) {
|
|
2721
|
+
idx = createNumericIndex();
|
|
2722
|
+
state.numericIndexes.set(fieldPath, idx);
|
|
2200
2723
|
}
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2724
|
+
return idx;
|
|
2725
|
+
}
|
|
2726
|
+
function getOrCreateBooleanIndex(state, fieldPath) {
|
|
2727
|
+
let idx = state.booleanIndexes.get(fieldPath);
|
|
2728
|
+
if (!idx) {
|
|
2729
|
+
idx = createBooleanIndex();
|
|
2730
|
+
state.booleanIndexes.set(fieldPath, idx);
|
|
2205
2731
|
}
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2732
|
+
return idx;
|
|
2733
|
+
}
|
|
2734
|
+
function resolveInternalId(state, docId) {
|
|
2735
|
+
const internalId = state.docStore.getInternalId(docId);
|
|
2736
|
+
if (internalId === void 0) {
|
|
2737
|
+
throw new Error(`Internal ID not found for document "${docId}"`);
|
|
2210
2738
|
}
|
|
2211
|
-
|
|
2212
|
-
if (bitsets.length === 1) return bitsets[0];
|
|
2213
|
-
return applyAndBitset(bitsets);
|
|
2739
|
+
return internalId;
|
|
2214
2740
|
}
|
|
2215
|
-
function
|
|
2216
|
-
if (
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
);
|
|
2741
|
+
function countSurface(counts, surface, token) {
|
|
2742
|
+
if (surface === void 0 || surface.length === 0) return;
|
|
2743
|
+
const existing = counts.get(surface);
|
|
2744
|
+
if (existing) {
|
|
2745
|
+
existing.count++;
|
|
2746
|
+
} else {
|
|
2747
|
+
counts.set(surface, { token, count: 1 });
|
|
2222
2748
|
}
|
|
2223
|
-
return fieldIndex.index;
|
|
2224
2749
|
}
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
for (const [fieldPath, fieldType] of Object.entries(flat)) {
|
|
2232
|
-
if (fieldType === "number" || fieldType === "number[]") {
|
|
2233
|
-
const numIdx = state.numericIndexes.get(fieldPath);
|
|
2234
|
-
if (numIdx) {
|
|
2235
|
-
fieldIndexes[fieldPath] = {
|
|
2236
|
-
type: "numeric",
|
|
2237
|
-
index: {
|
|
2238
|
-
eq: (v) => numIdx.queryEq(v),
|
|
2239
|
-
gt: (v) => numIdx.queryGt(v),
|
|
2240
|
-
gte: (v) => numIdx.queryGte(v),
|
|
2241
|
-
lt: (v) => numIdx.queryLt(v),
|
|
2242
|
-
lte: (v) => numIdx.queryLte(v),
|
|
2243
|
-
between: (min, max) => numIdx.queryBetween(min, max),
|
|
2244
|
-
allDocIds: () => numIdx.getAllDocIds(),
|
|
2245
|
-
eqBitset: (v, cap) => numIdx.queryEqBitset(v, cap),
|
|
2246
|
-
gtBitset: (v, cap) => numIdx.queryGtBitset(v, cap),
|
|
2247
|
-
gteBitset: (v, cap) => numIdx.queryGteBitset(v, cap),
|
|
2248
|
-
ltBitset: (v, cap) => numIdx.queryLtBitset(v, cap),
|
|
2249
|
-
lteBitset: (v, cap) => numIdx.queryLteBitset(v, cap),
|
|
2250
|
-
betweenBitset: (min, max, cap) => numIdx.queryBetweenBitset(min, max, cap),
|
|
2251
|
-
allDocIdsBitset: (cap) => numIdx.getAllDocIdsBitset(cap)
|
|
2252
|
-
}
|
|
2253
|
-
};
|
|
2254
|
-
}
|
|
2255
|
-
} else if (fieldType === "boolean" || fieldType === "boolean[]") {
|
|
2256
|
-
const boolIdx = state.booleanIndexes.get(fieldPath);
|
|
2257
|
-
if (boolIdx) {
|
|
2258
|
-
fieldIndexes[fieldPath] = {
|
|
2259
|
-
type: "boolean",
|
|
2260
|
-
index: {
|
|
2261
|
-
getTrue: () => boolIdx.queryEq(true),
|
|
2262
|
-
getFalse: () => boolIdx.queryEq(false),
|
|
2263
|
-
allDocIds: () => boolIdx.getAllDocIds(),
|
|
2264
|
-
getTrueBitset: (cap) => boolIdx.queryEqBitset(true, cap),
|
|
2265
|
-
getFalseBitset: (cap) => boolIdx.queryEqBitset(false, cap),
|
|
2266
|
-
allDocIdsBitset: (cap) => boolIdx.getAllDocIdsBitset(cap)
|
|
2267
|
-
}
|
|
2268
|
-
};
|
|
2269
|
-
}
|
|
2270
|
-
} else if (fieldType === "enum" || fieldType === "enum[]") {
|
|
2271
|
-
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
2272
|
-
if (enumIdx) {
|
|
2273
|
-
fieldIndexes[fieldPath] = {
|
|
2274
|
-
type: "enum",
|
|
2275
|
-
index: {
|
|
2276
|
-
getDocIds: (v) => enumIdx.queryEq(v),
|
|
2277
|
-
allDocIds: () => enumIdx.getAllDocIds(),
|
|
2278
|
-
getDocIdsBitset: (v, cap) => enumIdx.queryEqBitset(v, cap),
|
|
2279
|
-
getDocIdsInBitset: (values, cap) => enumIdx.queryInBitset(values, cap),
|
|
2280
|
-
allDocIdsBitset: (cap) => enumIdx.getAllDocIdsBitset(cap)
|
|
2281
|
-
}
|
|
2282
|
-
};
|
|
2283
|
-
}
|
|
2284
|
-
} else if (fieldType === "geopoint") {
|
|
2285
|
-
const geoIdx = state.geoIndexes.get(fieldPath);
|
|
2286
|
-
if (geoIdx) {
|
|
2287
|
-
fieldIndexes[fieldPath] = {
|
|
2288
|
-
type: "geopoint",
|
|
2289
|
-
index: geoIdx
|
|
2290
|
-
};
|
|
2291
|
-
}
|
|
2750
|
+
function applySurfaceCounts(state, counts, direction) {
|
|
2751
|
+
for (const [surface, entry] of counts) {
|
|
2752
|
+
if (direction === 1) {
|
|
2753
|
+
state.surfaceRegistry.add(surface, entry.token, entry.count);
|
|
2754
|
+
} else {
|
|
2755
|
+
state.surfaceRegistry.subtract(surface, entry.count);
|
|
2292
2756
|
}
|
|
2293
2757
|
}
|
|
2294
|
-
let cachedAllDocIds = null;
|
|
2295
|
-
let cachedAllDocIdsBitset = null;
|
|
2296
|
-
return {
|
|
2297
|
-
fieldIndexes,
|
|
2298
|
-
getFieldValue: (internalId, fieldPath) => getFieldValueByInternalId(state.docStore, internalId, fieldPath),
|
|
2299
|
-
get allDocIds() {
|
|
2300
|
-
if (!cachedAllDocIds) {
|
|
2301
|
-
cachedAllDocIds = getAllInternalDocIds(state.docStore);
|
|
2302
|
-
}
|
|
2303
|
-
return cachedAllDocIds;
|
|
2304
|
-
},
|
|
2305
|
-
capacity,
|
|
2306
|
-
get allDocIdsBitset() {
|
|
2307
|
-
if (!cachedAllDocIdsBitset) {
|
|
2308
|
-
cachedAllDocIdsBitset = bitsetFromSet(this.allDocIds, capacity);
|
|
2309
|
-
}
|
|
2310
|
-
return cachedAllDocIdsBitset;
|
|
2311
|
-
}
|
|
2312
|
-
};
|
|
2313
2758
|
}
|
|
2314
|
-
function
|
|
2315
|
-
const
|
|
2316
|
-
const
|
|
2317
|
-
const
|
|
2318
|
-
const
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
externalResult.add(externalId);
|
|
2759
|
+
function indexStringField(state, internalId, fieldPath, text, language, options, fieldLengths, tokensByField) {
|
|
2760
|
+
const fieldTokenList = [];
|
|
2761
|
+
const fieldNameIndex = getOrCreateFieldNameIndex(state.fieldNameTable, fieldPath);
|
|
2762
|
+
const opts = tokenizeOptions(options);
|
|
2763
|
+
const surfaceCounts = /* @__PURE__ */ new Map();
|
|
2764
|
+
if (state.trackPositions) {
|
|
2765
|
+
const tokenFreqs = /* @__PURE__ */ new Map();
|
|
2766
|
+
for (const t of tokenizeIterator(text, language, opts)) {
|
|
2767
|
+
const existing = tokenFreqs.get(t.token);
|
|
2768
|
+
if (existing) {
|
|
2769
|
+
existing.count++;
|
|
2770
|
+
existing.positions.push(t.position);
|
|
2771
|
+
} else {
|
|
2772
|
+
tokenFreqs.set(t.token, { count: 1, positions: [t.position] });
|
|
2329
2773
|
}
|
|
2330
|
-
|
|
2774
|
+
fieldTokenList.push(t.token);
|
|
2775
|
+
countSurface(surfaceCounts, t.surface, t.token);
|
|
2776
|
+
}
|
|
2777
|
+
for (const [token, freq] of tokenFreqs) {
|
|
2778
|
+
state.invertedIdx.insert(token, internalId, freq.count, fieldNameIndex, freq.positions);
|
|
2779
|
+
}
|
|
2780
|
+
} else {
|
|
2781
|
+
const tokenCounts = /* @__PURE__ */ new Map();
|
|
2782
|
+
for (const t of tokenizeIterator(text, language, opts)) {
|
|
2783
|
+
tokenCounts.set(t.token, (tokenCounts.get(t.token) ?? 0) + 1);
|
|
2784
|
+
fieldTokenList.push(t.token);
|
|
2785
|
+
countSurface(surfaceCounts, t.surface, t.token);
|
|
2786
|
+
}
|
|
2787
|
+
for (const [token, count] of tokenCounts) {
|
|
2788
|
+
state.invertedIdx.insert(token, internalId, count, fieldNameIndex, null);
|
|
2331
2789
|
}
|
|
2332
2790
|
}
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
const context = buildFilterContext(state, schema);
|
|
2337
|
-
return evaluateFilters(filters, context);
|
|
2338
|
-
}
|
|
2339
|
-
|
|
2340
|
-
// src/geo/haversine.ts
|
|
2341
|
-
var EARTH_RADIUS_METERS = 63710088e-1;
|
|
2342
|
-
var DEG_TO_RAD = Math.PI / 180;
|
|
2343
|
-
function haversineDistance(lat1, lon1, lat2, lon2) {
|
|
2344
|
-
const phi1 = lat1 * DEG_TO_RAD;
|
|
2345
|
-
const phi2 = lat2 * DEG_TO_RAD;
|
|
2346
|
-
const deltaPhi = (lat2 - lat1) * DEG_TO_RAD;
|
|
2347
|
-
const deltaLambda = (lon2 - lon1) * DEG_TO_RAD;
|
|
2348
|
-
const halfDeltaPhi = Math.sin(deltaPhi / 2);
|
|
2349
|
-
const halfDeltaLambda = Math.sin(deltaLambda / 2);
|
|
2350
|
-
const a = halfDeltaPhi * halfDeltaPhi + Math.cos(phi1) * Math.cos(phi2) * halfDeltaLambda * halfDeltaLambda;
|
|
2351
|
-
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
2352
|
-
return EARTH_RADIUS_METERS * c;
|
|
2791
|
+
applySurfaceCounts(state, surfaceCounts, 1);
|
|
2792
|
+
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2793
|
+
tokensByField[fieldPath] = fieldTokenList;
|
|
2353
2794
|
}
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
const
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2795
|
+
function indexStringArrayField(state, internalId, fieldPath, arr, language, options, fieldLengths, tokensByField) {
|
|
2796
|
+
const fieldTokenList = [];
|
|
2797
|
+
const fieldNameIndex = getOrCreateFieldNameIndex(state.fieldNameTable, fieldPath);
|
|
2798
|
+
const opts = tokenizeOptions(options);
|
|
2799
|
+
const surfaceCounts = /* @__PURE__ */ new Map();
|
|
2800
|
+
if (state.trackPositions) {
|
|
2801
|
+
const tokenFreqs = /* @__PURE__ */ new Map();
|
|
2802
|
+
let positionOffset = 0;
|
|
2803
|
+
for (const item of arr) {
|
|
2804
|
+
let itemTokenCount = 0;
|
|
2805
|
+
for (const t of tokenizeIterator(item, language, opts)) {
|
|
2806
|
+
const existing = tokenFreqs.get(t.token);
|
|
2807
|
+
if (existing) {
|
|
2808
|
+
existing.count++;
|
|
2809
|
+
existing.positions.push(positionOffset + t.position);
|
|
2810
|
+
} else {
|
|
2811
|
+
tokenFreqs.set(t.token, { count: 1, positions: [positionOffset + t.position] });
|
|
2812
|
+
}
|
|
2813
|
+
fieldTokenList.push(t.token);
|
|
2814
|
+
countSurface(surfaceCounts, t.surface, t.token);
|
|
2815
|
+
itemTokenCount++;
|
|
2816
|
+
}
|
|
2817
|
+
positionOffset += itemTokenCount;
|
|
2818
|
+
}
|
|
2819
|
+
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2820
|
+
for (const [token, freq] of tokenFreqs) {
|
|
2821
|
+
state.invertedIdx.insert(token, internalId, freq.count, fieldNameIndex, freq.positions);
|
|
2822
|
+
}
|
|
2823
|
+
} else {
|
|
2824
|
+
const tokenCounts = /* @__PURE__ */ new Map();
|
|
2825
|
+
for (const item of arr) {
|
|
2826
|
+
for (const t of tokenizeIterator(item, language, opts)) {
|
|
2827
|
+
tokenCounts.set(t.token, (tokenCounts.get(t.token) ?? 0) + 1);
|
|
2828
|
+
fieldTokenList.push(t.token);
|
|
2829
|
+
countSurface(surfaceCounts, t.surface, t.token);
|
|
2370
2830
|
}
|
|
2371
2831
|
}
|
|
2832
|
+
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2833
|
+
for (const [token, count] of tokenCounts) {
|
|
2834
|
+
state.invertedIdx.insert(token, internalId, count, fieldNameIndex, null);
|
|
2835
|
+
}
|
|
2372
2836
|
}
|
|
2373
|
-
|
|
2837
|
+
applySurfaceCounts(state, surfaceCounts, 1);
|
|
2838
|
+
tokensByField[fieldPath] = fieldTokenList;
|
|
2374
2839
|
}
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
if (
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
} while (Math.abs(lambda - prevLambda) > CONVERGENCE_THRESHOLD && --iterations > 0);
|
|
2418
|
-
if (iterations === 0) {
|
|
2419
|
-
return haversineDistance(lat1, lon1, lat2, lon2);
|
|
2840
|
+
function indexDocument(state, docId, document, flatSchema, language, options) {
|
|
2841
|
+
const fieldLengths = {};
|
|
2842
|
+
const tokensByField = {};
|
|
2843
|
+
const internalId = resolveInternalId(state, docId);
|
|
2844
|
+
for (const [fieldPath, fieldType] of Object.entries(flatSchema)) {
|
|
2845
|
+
const value = getNestedValue(document, fieldPath);
|
|
2846
|
+
if (value === void 0 || value === null) continue;
|
|
2847
|
+
ensureFieldIndex(state, fieldPath, fieldType);
|
|
2848
|
+
if (fieldType === "string") {
|
|
2849
|
+
indexStringField(state, internalId, fieldPath, value, language, options, fieldLengths, tokensByField);
|
|
2850
|
+
} else if (fieldType === "number") {
|
|
2851
|
+
getOrCreateNumericIndex(state, fieldPath).insert(internalId, value);
|
|
2852
|
+
} else if (fieldType === "boolean") {
|
|
2853
|
+
getOrCreateBooleanIndex(state, fieldPath).insert(internalId, value);
|
|
2854
|
+
} else if (fieldType === "enum") {
|
|
2855
|
+
state.enumIndexes.get(fieldPath)?.insert(internalId, value);
|
|
2856
|
+
} else if (fieldType === "geopoint") {
|
|
2857
|
+
const geo = value;
|
|
2858
|
+
state.geoIndexes.get(fieldPath)?.insert(internalId, geo.lat, geo.lon);
|
|
2859
|
+
} else if (fieldType === "string[]") {
|
|
2860
|
+
indexStringArrayField(
|
|
2861
|
+
state,
|
|
2862
|
+
internalId,
|
|
2863
|
+
fieldPath,
|
|
2864
|
+
value,
|
|
2865
|
+
language,
|
|
2866
|
+
options,
|
|
2867
|
+
fieldLengths,
|
|
2868
|
+
tokensByField
|
|
2869
|
+
);
|
|
2870
|
+
} else if (fieldType === "number[]") {
|
|
2871
|
+
const numIdx = getOrCreateNumericIndex(state, fieldPath);
|
|
2872
|
+
for (const num of value) numIdx.insert(internalId, num);
|
|
2873
|
+
} else if (fieldType === "boolean[]") {
|
|
2874
|
+
const boolIdx = getOrCreateBooleanIndex(state, fieldPath);
|
|
2875
|
+
for (const b of value) boolIdx.insert(internalId, b);
|
|
2876
|
+
} else if (fieldType === "enum[]") {
|
|
2877
|
+
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
2878
|
+
if (enumIdx) {
|
|
2879
|
+
for (const e of value) enumIdx.insert(internalId, e);
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2420
2882
|
}
|
|
2421
|
-
|
|
2422
|
-
const A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
|
2423
|
-
const B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
|
2424
|
-
const deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
|
|
2425
|
-
return WGS84_B * A * (sigma - deltaSigma);
|
|
2883
|
+
return { fieldLengths, tokensByField };
|
|
2426
2884
|
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
const
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2885
|
+
function removeFromIndexes(state, docId, storedDoc, flatSchema, language, options) {
|
|
2886
|
+
const fieldLengths = {};
|
|
2887
|
+
const tokensByField = {};
|
|
2888
|
+
const fields = storedDoc.fields;
|
|
2889
|
+
const internalId = resolveInternalId(state, docId);
|
|
2890
|
+
const opts = tokenizeOptions(options);
|
|
2891
|
+
for (const [fieldPath, fieldType] of Object.entries(flatSchema)) {
|
|
2892
|
+
const value = getNestedValue(fields, fieldPath);
|
|
2893
|
+
if (value === void 0 || value === null) continue;
|
|
2894
|
+
if (fieldType === "string") {
|
|
2895
|
+
const result = tokenize(value, language, opts);
|
|
2896
|
+
fieldLengths[fieldPath] = result.tokens.length;
|
|
2897
|
+
const uniqueTokens = /* @__PURE__ */ new Set();
|
|
2898
|
+
const fieldTokenList = [];
|
|
2899
|
+
const surfaceCounts = /* @__PURE__ */ new Map();
|
|
2900
|
+
for (let i = 0; i < result.tokens.length; i++) {
|
|
2901
|
+
const t = result.tokens[i];
|
|
2902
|
+
uniqueTokens.add(t.token);
|
|
2903
|
+
fieldTokenList.push(t.token);
|
|
2904
|
+
countSurface(surfaceCounts, result.surfaces?.[i], t.token);
|
|
2444
2905
|
}
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2906
|
+
for (const token of uniqueTokens) state.invertedIdx.remove(token, internalId);
|
|
2907
|
+
applySurfaceCounts(state, surfaceCounts, -1);
|
|
2908
|
+
tokensByField[fieldPath] = fieldTokenList;
|
|
2909
|
+
} else if (fieldType === "number") {
|
|
2910
|
+
state.numericIndexes.get(fieldPath)?.remove(internalId, value);
|
|
2911
|
+
} else if (fieldType === "boolean") {
|
|
2912
|
+
state.booleanIndexes.get(fieldPath)?.remove(internalId, value);
|
|
2913
|
+
} else if (fieldType === "enum") {
|
|
2914
|
+
state.enumIndexes.get(fieldPath)?.remove(internalId, value);
|
|
2915
|
+
} else if (fieldType === "geopoint") {
|
|
2916
|
+
state.geoIndexes.get(fieldPath)?.remove(internalId);
|
|
2917
|
+
} else if (fieldType === "string[]") {
|
|
2918
|
+
const arr = value;
|
|
2919
|
+
const uniqueTokens = /* @__PURE__ */ new Set();
|
|
2920
|
+
const fieldTokenList = [];
|
|
2921
|
+
const surfaceCounts = /* @__PURE__ */ new Map();
|
|
2922
|
+
for (const item of arr) {
|
|
2923
|
+
const result = tokenize(item, language, opts);
|
|
2924
|
+
for (let i = 0; i < result.tokens.length; i++) {
|
|
2925
|
+
const t = result.tokens[i];
|
|
2926
|
+
uniqueTokens.add(t.token);
|
|
2927
|
+
fieldTokenList.push(t.token);
|
|
2928
|
+
countSurface(surfaceCounts, result.surfaces?.[i], t.token);
|
|
2455
2929
|
}
|
|
2456
2930
|
}
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
result.add(entry.docId);
|
|
2466
|
-
}
|
|
2931
|
+
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2932
|
+
for (const token of uniqueTokens) state.invertedIdx.remove(token, internalId);
|
|
2933
|
+
applySurfaceCounts(state, surfaceCounts, -1);
|
|
2934
|
+
tokensByField[fieldPath] = fieldTokenList;
|
|
2935
|
+
} else if (fieldType === "number[]") {
|
|
2936
|
+
const numIdx = state.numericIndexes.get(fieldPath);
|
|
2937
|
+
if (numIdx) {
|
|
2938
|
+
for (const num of value) numIdx.remove(internalId, num);
|
|
2467
2939
|
}
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
},
|
|
2473
|
-
serialize() {
|
|
2474
|
-
return entries.map((e) => ({ ...e }));
|
|
2475
|
-
},
|
|
2476
|
-
deserialize(data) {
|
|
2477
|
-
entries.length = 0;
|
|
2478
|
-
for (const entry of data) {
|
|
2479
|
-
entries.push({ lat: entry.lat, lon: entry.lon, docId: entry.docId });
|
|
2940
|
+
} else if (fieldType === "boolean[]") {
|
|
2941
|
+
const boolIdx = state.booleanIndexes.get(fieldPath);
|
|
2942
|
+
if (boolIdx) {
|
|
2943
|
+
for (const b of value) boolIdx.remove(internalId, b);
|
|
2480
2944
|
}
|
|
2481
|
-
}
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
// src/core/field-index/boolean.ts
|
|
2486
|
-
function createBooleanIndex() {
|
|
2487
|
-
const trueDocs = /* @__PURE__ */ new Set();
|
|
2488
|
-
const falseDocs = /* @__PURE__ */ new Set();
|
|
2489
|
-
return {
|
|
2490
|
-
insert(internalId, value) {
|
|
2491
|
-
if (value) trueDocs.add(internalId);
|
|
2492
|
-
else falseDocs.add(internalId);
|
|
2493
|
-
},
|
|
2494
|
-
remove(internalId, value) {
|
|
2495
|
-
if (value) trueDocs.delete(internalId);
|
|
2496
|
-
else falseDocs.delete(internalId);
|
|
2497
|
-
},
|
|
2498
|
-
queryEq(value) {
|
|
2499
|
-
return new Set(value ? trueDocs : falseDocs);
|
|
2500
|
-
},
|
|
2501
|
-
queryNe(value) {
|
|
2502
|
-
return new Set(value ? falseDocs : trueDocs);
|
|
2503
|
-
},
|
|
2504
|
-
getAllDocIds() {
|
|
2505
|
-
const all = new Set(trueDocs);
|
|
2506
|
-
for (const id of falseDocs) all.add(id);
|
|
2507
|
-
return all;
|
|
2508
|
-
},
|
|
2509
|
-
queryEqBitset(value, capacity) {
|
|
2510
|
-
const source = value ? trueDocs : falseDocs;
|
|
2511
|
-
const bs = createBitSet(capacity);
|
|
2512
|
-
for (const id of source) {
|
|
2513
|
-
bitsetSet(bs, id);
|
|
2945
|
+
} else if (fieldType === "enum[]") {
|
|
2946
|
+
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
2947
|
+
if (enumIdx) {
|
|
2948
|
+
for (const e of value) enumIdx.remove(internalId, e);
|
|
2514
2949
|
}
|
|
2515
|
-
return bs;
|
|
2516
|
-
},
|
|
2517
|
-
getAllDocIdsBitset(capacity) {
|
|
2518
|
-
const bs = createBitSet(capacity);
|
|
2519
|
-
for (const id of trueDocs) bitsetSet(bs, id);
|
|
2520
|
-
for (const id of falseDocs) bitsetSet(bs, id);
|
|
2521
|
-
return bs;
|
|
2522
|
-
},
|
|
2523
|
-
count() {
|
|
2524
|
-
return trueDocs.size + falseDocs.size;
|
|
2525
|
-
},
|
|
2526
|
-
clear() {
|
|
2527
|
-
trueDocs.clear();
|
|
2528
|
-
falseDocs.clear();
|
|
2529
|
-
},
|
|
2530
|
-
serialize() {
|
|
2531
|
-
return {
|
|
2532
|
-
trueDocs: Array.from(trueDocs),
|
|
2533
|
-
falseDocs: Array.from(falseDocs)
|
|
2534
|
-
};
|
|
2535
|
-
},
|
|
2536
|
-
deserialize(data) {
|
|
2537
|
-
trueDocs.clear();
|
|
2538
|
-
falseDocs.clear();
|
|
2539
|
-
for (const id of data.trueDocs) trueDocs.add(id);
|
|
2540
|
-
for (const id of data.falseDocs) falseDocs.add(id);
|
|
2541
2950
|
}
|
|
2542
|
-
}
|
|
2951
|
+
}
|
|
2952
|
+
return { fieldLengths, tokensByField };
|
|
2543
2953
|
}
|
|
2544
2954
|
|
|
2545
|
-
// src/core/field-
|
|
2546
|
-
function
|
|
2547
|
-
const
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
for (const docSet of valueMap.values()) {
|
|
2551
|
-
for (const id of docSet) result.add(id);
|
|
2552
|
-
}
|
|
2553
|
-
return result;
|
|
2955
|
+
// src/core/partition/field-updates.ts
|
|
2956
|
+
function resolveInternalId2(state, docId) {
|
|
2957
|
+
const internalId = state.docStore.getInternalId(docId);
|
|
2958
|
+
if (internalId === void 0) {
|
|
2959
|
+
throw new Error(`Internal ID not found for document "${docId}"`);
|
|
2554
2960
|
}
|
|
2555
|
-
return
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2961
|
+
return internalId;
|
|
2962
|
+
}
|
|
2963
|
+
function updateFieldIndexOnly(state, docId, oldFields, newDoc, flatSchema) {
|
|
2964
|
+
const internalId = resolveInternalId2(state, docId);
|
|
2965
|
+
for (const [fieldPath, fieldType] of Object.entries(flatSchema)) {
|
|
2966
|
+
if (fieldType === "string" || fieldType === "string[]") continue;
|
|
2967
|
+
const oldVal = getNestedValue(oldFields, fieldPath);
|
|
2968
|
+
const newVal = getNestedValue(newDoc, fieldPath);
|
|
2969
|
+
if (oldVal === newVal) continue;
|
|
2970
|
+
if (oldVal !== void 0 && oldVal !== null && newVal !== void 0 && newVal !== null && typeof oldVal === typeof newVal && JSON.stringify(oldVal) === JSON.stringify(newVal))
|
|
2971
|
+
continue;
|
|
2972
|
+
if (newVal !== void 0 && newVal !== null) {
|
|
2973
|
+
ensureFieldIndex(state, fieldPath, fieldType);
|
|
2974
|
+
}
|
|
2975
|
+
if (fieldType === "number") {
|
|
2976
|
+
const numIdx = state.numericIndexes.get(fieldPath);
|
|
2977
|
+
if (numIdx) {
|
|
2978
|
+
if (oldVal !== void 0 && oldVal !== null) numIdx.remove(internalId, oldVal);
|
|
2979
|
+
if (newVal !== void 0 && newVal !== null) numIdx.insert(internalId, newVal);
|
|
2561
2980
|
}
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
docSet.delete(internalId);
|
|
2568
|
-
if (docSet.size === 0) valueMap.delete(value);
|
|
2569
|
-
},
|
|
2570
|
-
queryEq(value) {
|
|
2571
|
-
const docSet = valueMap.get(value);
|
|
2572
|
-
return docSet ? new Set(docSet) : /* @__PURE__ */ new Set();
|
|
2573
|
-
},
|
|
2574
|
-
queryNe(value) {
|
|
2575
|
-
const excluded = valueMap.get(value);
|
|
2576
|
-
const result = allDocs();
|
|
2577
|
-
if (excluded) {
|
|
2578
|
-
for (const id of excluded) result.delete(id);
|
|
2981
|
+
} else if (fieldType === "boolean") {
|
|
2982
|
+
const boolIdx = state.booleanIndexes.get(fieldPath);
|
|
2983
|
+
if (boolIdx) {
|
|
2984
|
+
if (oldVal !== void 0 && oldVal !== null) boolIdx.remove(internalId, oldVal);
|
|
2985
|
+
if (newVal !== void 0 && newVal !== null) boolIdx.insert(internalId, newVal);
|
|
2579
2986
|
}
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
const docSet = valueMap.get(val);
|
|
2586
|
-
if (docSet) {
|
|
2587
|
-
for (const id of docSet) result.add(id);
|
|
2588
|
-
}
|
|
2987
|
+
} else if (fieldType === "enum") {
|
|
2988
|
+
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
2989
|
+
if (enumIdx) {
|
|
2990
|
+
if (oldVal !== void 0 && oldVal !== null) enumIdx.remove(internalId, oldVal);
|
|
2991
|
+
if (newVal !== void 0 && newVal !== null) enumIdx.insert(internalId, newVal);
|
|
2589
2992
|
}
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
getAllDocIds() {
|
|
2599
|
-
return allDocs();
|
|
2600
|
-
},
|
|
2601
|
-
queryEqBitset(value, capacity) {
|
|
2602
|
-
const bs = createBitSet(capacity);
|
|
2603
|
-
const docSet = valueMap.get(value);
|
|
2604
|
-
if (docSet) {
|
|
2605
|
-
for (const id of docSet) bitsetSet(bs, id);
|
|
2993
|
+
} else if (fieldType === "geopoint") {
|
|
2994
|
+
const geoIdx = state.geoIndexes.get(fieldPath);
|
|
2995
|
+
if (geoIdx) {
|
|
2996
|
+
if (oldVal !== void 0 && oldVal !== null) geoIdx.remove(internalId);
|
|
2997
|
+
if (newVal !== void 0 && newVal !== null) {
|
|
2998
|
+
const geo = newVal;
|
|
2999
|
+
geoIdx.insert(internalId, geo.lat, geo.lon);
|
|
3000
|
+
}
|
|
2606
3001
|
}
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
if (
|
|
2614
|
-
for (const
|
|
3002
|
+
} else if (fieldType === "number[]") {
|
|
3003
|
+
const numIdx = state.numericIndexes.get(fieldPath);
|
|
3004
|
+
if (numIdx) {
|
|
3005
|
+
if (oldVal !== void 0 && oldVal !== null) {
|
|
3006
|
+
for (const n of oldVal) numIdx.remove(internalId, n);
|
|
3007
|
+
}
|
|
3008
|
+
if (newVal !== void 0 && newVal !== null) {
|
|
3009
|
+
for (const n of newVal) numIdx.insert(internalId, n);
|
|
2615
3010
|
}
|
|
2616
3011
|
}
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
3012
|
+
} else if (fieldType === "boolean[]") {
|
|
3013
|
+
const boolIdx = state.booleanIndexes.get(fieldPath);
|
|
3014
|
+
if (boolIdx) {
|
|
3015
|
+
if (oldVal !== void 0 && oldVal !== null) {
|
|
3016
|
+
for (const b of oldVal) boolIdx.remove(internalId, b);
|
|
3017
|
+
}
|
|
3018
|
+
if (newVal !== void 0 && newVal !== null) {
|
|
3019
|
+
for (const b of newVal) boolIdx.insert(internalId, b);
|
|
3020
|
+
}
|
|
2623
3021
|
}
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
},
|
|
2634
|
-
serialize() {
|
|
2635
|
-
const result = /* @__PURE__ */ Object.create(null);
|
|
2636
|
-
for (const [value, docSet] of valueMap) {
|
|
2637
|
-
result[value] = Array.from(docSet);
|
|
3022
|
+
} else if (fieldType === "enum[]") {
|
|
3023
|
+
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
3024
|
+
if (enumIdx) {
|
|
3025
|
+
if (oldVal !== void 0 && oldVal !== null) {
|
|
3026
|
+
for (const e of oldVal) enumIdx.remove(internalId, e);
|
|
3027
|
+
}
|
|
3028
|
+
if (newVal !== void 0 && newVal !== null) {
|
|
3029
|
+
for (const e of newVal) enumIdx.insert(internalId, e);
|
|
3030
|
+
}
|
|
2638
3031
|
}
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
// src/filters/combinators.ts
|
|
3037
|
+
function applyAndBitset(bitsets) {
|
|
3038
|
+
if (bitsets.length === 0) return new Uint32Array(0);
|
|
3039
|
+
if (bitsets.length === 1) return bitsets[0];
|
|
3040
|
+
let result = bitsets[0];
|
|
3041
|
+
for (let i = 1; i < bitsets.length; i++) {
|
|
3042
|
+
result = bitsetAnd(result, bitsets[i]);
|
|
3043
|
+
}
|
|
3044
|
+
return result;
|
|
3045
|
+
}
|
|
3046
|
+
function applyOrBitset(bitsets) {
|
|
3047
|
+
if (bitsets.length === 0) return new Uint32Array(0);
|
|
3048
|
+
if (bitsets.length === 1) return bitsets[0];
|
|
3049
|
+
let result = bitsets[0];
|
|
3050
|
+
for (let i = 1; i < bitsets.length; i++) {
|
|
3051
|
+
result = bitsetOr(result, bitsets[i]);
|
|
3052
|
+
}
|
|
3053
|
+
return result;
|
|
3054
|
+
}
|
|
3055
|
+
function applyNotBitset(excluded, capacity) {
|
|
3056
|
+
return bitsetNot(excluded, capacity);
|
|
3057
|
+
}
|
|
3058
|
+
|
|
3059
|
+
// src/filters/operators/shared.ts
|
|
3060
|
+
var METERS_PER_KM = 1e3;
|
|
3061
|
+
var METERS_PER_MI = 1609.344;
|
|
3062
|
+
function convertToMeters(distance, unit) {
|
|
3063
|
+
if (unit === "km") return distance * METERS_PER_KM;
|
|
3064
|
+
if (unit === "mi") return distance * METERS_PER_MI;
|
|
3065
|
+
return distance;
|
|
3066
|
+
}
|
|
3067
|
+
function matchesNumericComparison(value, filter) {
|
|
3068
|
+
if (filter.eq !== void 0 && value !== filter.eq) return false;
|
|
3069
|
+
if (filter.ne !== void 0 && value === filter.ne) return false;
|
|
3070
|
+
if (filter.gt !== void 0 && !(value > filter.gt)) return false;
|
|
3071
|
+
if (filter.lt !== void 0 && !(value < filter.lt)) return false;
|
|
3072
|
+
if (filter.gte !== void 0 && !(value >= filter.gte)) return false;
|
|
3073
|
+
if (filter.lte !== void 0 && !(value <= filter.lte)) return false;
|
|
3074
|
+
if (filter.between !== void 0 && !(value >= filter.between[0] && value <= filter.between[1])) return false;
|
|
3075
|
+
return true;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
// src/filters/operators/bitset.ts
|
|
3079
|
+
function resolveBitset(bs) {
|
|
3080
|
+
return typeof bs === "function" ? bs() : bs;
|
|
3081
|
+
}
|
|
3082
|
+
function scanToBitset(docIds, capacity, getValue, predicate) {
|
|
3083
|
+
const resolved = resolveBitset(docIds);
|
|
3084
|
+
const result = createBitSet(capacity);
|
|
3085
|
+
for (let wi = 0; wi < resolved.length; wi++) {
|
|
3086
|
+
let word = resolved[wi];
|
|
3087
|
+
if (word === 0) continue;
|
|
3088
|
+
const base = wi << 5;
|
|
3089
|
+
while (word !== 0) {
|
|
3090
|
+
const tz = Math.clz32(word & -word) ^ 31;
|
|
3091
|
+
const id = base + tz;
|
|
3092
|
+
if (predicate(getValue(id))) {
|
|
3093
|
+
bitsetSet(result, id);
|
|
2645
3094
|
}
|
|
3095
|
+
word &= word - 1;
|
|
2646
3096
|
}
|
|
2647
|
-
}
|
|
3097
|
+
}
|
|
3098
|
+
return result;
|
|
3099
|
+
}
|
|
3100
|
+
function applyEqBitset(value, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3101
|
+
if (fieldIndex?.type === "numeric" && typeof value === "number") {
|
|
3102
|
+
return fieldIndex.index.eqBitset(value, capacity);
|
|
3103
|
+
}
|
|
3104
|
+
if (fieldIndex?.type === "boolean" && typeof value === "boolean") {
|
|
3105
|
+
return value ? fieldIndex.index.getTrueBitset(capacity) : fieldIndex.index.getFalseBitset(capacity);
|
|
3106
|
+
}
|
|
3107
|
+
if (fieldIndex?.type === "enum" && typeof value === "string") {
|
|
3108
|
+
return fieldIndex.index.getDocIdsBitset(value, capacity);
|
|
3109
|
+
}
|
|
3110
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => v === value);
|
|
2648
3111
|
}
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
while (lo < hi) {
|
|
2655
|
-
const mid = lo + hi >>> 1;
|
|
2656
|
-
if (entries[mid].value < value) lo = mid + 1;
|
|
2657
|
-
else hi = mid;
|
|
3112
|
+
function applyNeBitset(value, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3113
|
+
if (fieldIndex?.type === "numeric" && typeof value === "number") {
|
|
3114
|
+
const all = fieldIndex.index.allDocIdsBitset(capacity);
|
|
3115
|
+
const eq = fieldIndex.index.eqBitset(value, capacity);
|
|
3116
|
+
return bitsetAnd(all, bitsetNot(eq, capacity));
|
|
2658
3117
|
}
|
|
2659
|
-
|
|
3118
|
+
if (fieldIndex?.type === "boolean" && typeof value === "boolean") {
|
|
3119
|
+
return value ? fieldIndex.index.getFalseBitset(capacity) : fieldIndex.index.getTrueBitset(capacity);
|
|
3120
|
+
}
|
|
3121
|
+
if (fieldIndex?.type === "enum" && typeof value === "string") {
|
|
3122
|
+
const all = fieldIndex.index.allDocIdsBitset(capacity);
|
|
3123
|
+
const eq = fieldIndex.index.getDocIdsBitset(value, capacity);
|
|
3124
|
+
return bitsetAnd(all, bitsetNot(eq, capacity));
|
|
3125
|
+
}
|
|
3126
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => v !== void 0 && v !== null && v !== value);
|
|
2660
3127
|
}
|
|
2661
|
-
function
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
while (lo < hi) {
|
|
2665
|
-
const mid = lo + hi >>> 1;
|
|
2666
|
-
if (entries[mid].value <= value) lo = mid + 1;
|
|
2667
|
-
else hi = mid;
|
|
3128
|
+
function applyGtBitset(value, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3129
|
+
if (fieldIndex?.type === "numeric") {
|
|
3130
|
+
return fieldIndex.index.gtBitset(value, capacity);
|
|
2668
3131
|
}
|
|
2669
|
-
return
|
|
3132
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "number" && v > value);
|
|
2670
3133
|
}
|
|
2671
|
-
function
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
result.add(entries[i].docId);
|
|
3134
|
+
function applyLtBitset(value, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3135
|
+
if (fieldIndex?.type === "numeric") {
|
|
3136
|
+
return fieldIndex.index.ltBitset(value, capacity);
|
|
2675
3137
|
}
|
|
2676
|
-
return
|
|
3138
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "number" && v < value);
|
|
2677
3139
|
}
|
|
2678
|
-
function
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
bitsetSet(bs, entries[i].docId);
|
|
3140
|
+
function applyGteBitset(value, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3141
|
+
if (fieldIndex?.type === "numeric") {
|
|
3142
|
+
return fieldIndex.index.gteBitset(value, capacity);
|
|
2682
3143
|
}
|
|
2683
|
-
return
|
|
3144
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "number" && v >= value);
|
|
2684
3145
|
}
|
|
2685
|
-
function
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
function ensureSorted() {
|
|
2689
|
-
if (!sorted) {
|
|
2690
|
-
entries.sort((a, b) => a.value - b.value);
|
|
2691
|
-
sorted = true;
|
|
2692
|
-
}
|
|
3146
|
+
function applyLteBitset(value, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3147
|
+
if (fieldIndex?.type === "numeric") {
|
|
3148
|
+
return fieldIndex.index.lteBitset(value, capacity);
|
|
2693
3149
|
}
|
|
2694
|
-
return
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
queryLte(value) {
|
|
2736
|
-
ensureSorted();
|
|
2737
|
-
return collectDocIds(entries, 0, upperBound(entries, value));
|
|
2738
|
-
},
|
|
2739
|
-
queryBetween(min, max) {
|
|
2740
|
-
ensureSorted();
|
|
2741
|
-
return collectDocIds(entries, lowerBound(entries, min), upperBound(entries, max));
|
|
2742
|
-
},
|
|
2743
|
-
getAllDocIds() {
|
|
2744
|
-
return collectDocIds(entries, 0, entries.length);
|
|
2745
|
-
},
|
|
2746
|
-
queryEqBitset(value, capacity) {
|
|
2747
|
-
ensureSorted();
|
|
2748
|
-
return collectDocIdsBitset(entries, lowerBound(entries, value), upperBound(entries, value), capacity);
|
|
2749
|
-
},
|
|
2750
|
-
queryGtBitset(value, capacity) {
|
|
2751
|
-
ensureSorted();
|
|
2752
|
-
return collectDocIdsBitset(entries, upperBound(entries, value), entries.length, capacity);
|
|
2753
|
-
},
|
|
2754
|
-
queryGteBitset(value, capacity) {
|
|
2755
|
-
ensureSorted();
|
|
2756
|
-
return collectDocIdsBitset(entries, lowerBound(entries, value), entries.length, capacity);
|
|
2757
|
-
},
|
|
2758
|
-
queryLtBitset(value, capacity) {
|
|
2759
|
-
ensureSorted();
|
|
2760
|
-
return collectDocIdsBitset(entries, 0, lowerBound(entries, value), capacity);
|
|
2761
|
-
},
|
|
2762
|
-
queryLteBitset(value, capacity) {
|
|
2763
|
-
ensureSorted();
|
|
2764
|
-
return collectDocIdsBitset(entries, 0, upperBound(entries, value), capacity);
|
|
2765
|
-
},
|
|
2766
|
-
queryBetweenBitset(min, max, capacity) {
|
|
2767
|
-
ensureSorted();
|
|
2768
|
-
return collectDocIdsBitset(entries, lowerBound(entries, min), upperBound(entries, max), capacity);
|
|
2769
|
-
},
|
|
2770
|
-
getAllDocIdsBitset(capacity) {
|
|
2771
|
-
return collectDocIdsBitset(entries, 0, entries.length, capacity);
|
|
2772
|
-
},
|
|
2773
|
-
count() {
|
|
2774
|
-
return entries.length;
|
|
2775
|
-
},
|
|
2776
|
-
clear() {
|
|
2777
|
-
entries = [];
|
|
2778
|
-
sorted = true;
|
|
2779
|
-
},
|
|
2780
|
-
serialize() {
|
|
2781
|
-
ensureSorted();
|
|
2782
|
-
return entries.slice();
|
|
2783
|
-
},
|
|
2784
|
-
deserialize(data) {
|
|
2785
|
-
entries = data.slice();
|
|
2786
|
-
sorted = true;
|
|
3150
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "number" && v <= value);
|
|
3151
|
+
}
|
|
3152
|
+
function applyBetweenBitset(range, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3153
|
+
if (fieldIndex?.type === "numeric") {
|
|
3154
|
+
return fieldIndex.index.betweenBitset(range[0], range[1], capacity);
|
|
3155
|
+
}
|
|
3156
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "number" && v >= range[0] && v <= range[1]);
|
|
3157
|
+
}
|
|
3158
|
+
function applyInBitset(values, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3159
|
+
if (fieldIndex?.type === "enum") {
|
|
3160
|
+
return fieldIndex.index.getDocIdsInBitset(values, capacity);
|
|
3161
|
+
}
|
|
3162
|
+
const valSet = new Set(values);
|
|
3163
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "string" && valSet.has(v));
|
|
3164
|
+
}
|
|
3165
|
+
function applyNinBitset(values, allDocsBitset, capacity, getValue, fieldIndex) {
|
|
3166
|
+
if (fieldIndex?.type === "enum") {
|
|
3167
|
+
const all = fieldIndex.index.allDocIdsBitset(capacity);
|
|
3168
|
+
const matched = fieldIndex.index.getDocIdsInBitset(values, capacity);
|
|
3169
|
+
return bitsetAnd(all, bitsetNot(matched, capacity));
|
|
3170
|
+
}
|
|
3171
|
+
const valSet = new Set(values);
|
|
3172
|
+
return scanToBitset(
|
|
3173
|
+
allDocsBitset,
|
|
3174
|
+
capacity,
|
|
3175
|
+
getValue,
|
|
3176
|
+
(v) => v !== void 0 && v !== null && typeof v === "string" && !valSet.has(v)
|
|
3177
|
+
);
|
|
3178
|
+
}
|
|
3179
|
+
function applyStartsWithBitset(prefix, allDocsBitset, capacity, getValue) {
|
|
3180
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "string" && v.startsWith(prefix));
|
|
3181
|
+
}
|
|
3182
|
+
function applyEndsWithBitset(suffix, allDocsBitset, capacity, getValue) {
|
|
3183
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => typeof v === "string" && v.endsWith(suffix));
|
|
3184
|
+
}
|
|
3185
|
+
function applyContainsAllBitset(values, allDocsBitset, capacity, getValue) {
|
|
3186
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => {
|
|
3187
|
+
if (!Array.isArray(v)) return false;
|
|
3188
|
+
const arr = v;
|
|
3189
|
+
for (const val of values) {
|
|
3190
|
+
if (!arr.includes(val)) return false;
|
|
2787
3191
|
}
|
|
2788
|
-
|
|
3192
|
+
return true;
|
|
3193
|
+
});
|
|
3194
|
+
}
|
|
3195
|
+
function applyMatchesAnyBitset(values, allDocsBitset, capacity, getValue) {
|
|
3196
|
+
const valSet = new Set(values);
|
|
3197
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => {
|
|
3198
|
+
if (!Array.isArray(v)) return false;
|
|
3199
|
+
for (const item of v) {
|
|
3200
|
+
if (valSet.has(item)) return true;
|
|
3201
|
+
}
|
|
3202
|
+
return false;
|
|
3203
|
+
});
|
|
3204
|
+
}
|
|
3205
|
+
function applySizeBitset(sizeFilter, allDocsBitset, capacity, getValue) {
|
|
3206
|
+
return scanToBitset(
|
|
3207
|
+
allDocsBitset,
|
|
3208
|
+
capacity,
|
|
3209
|
+
getValue,
|
|
3210
|
+
(v) => Array.isArray(v) && matchesNumericComparison(v.length, sizeFilter)
|
|
3211
|
+
);
|
|
3212
|
+
}
|
|
3213
|
+
function applyExistsBitset(allDocsBitset, capacity, getValue) {
|
|
3214
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => v !== void 0 && v !== null);
|
|
3215
|
+
}
|
|
3216
|
+
function applyNotExistsBitset(allDocsBitset, capacity, getValue) {
|
|
3217
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => v === void 0 || v === null);
|
|
3218
|
+
}
|
|
3219
|
+
function applyIsEmptyBitset(allDocsBitset, capacity, getValue) {
|
|
3220
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => {
|
|
3221
|
+
if (v === void 0 || v === null) return true;
|
|
3222
|
+
if (typeof v === "string" && v === "") return true;
|
|
3223
|
+
if (Array.isArray(v) && v.length === 0) return true;
|
|
3224
|
+
return false;
|
|
3225
|
+
});
|
|
3226
|
+
}
|
|
3227
|
+
function applyIsNotEmptyBitset(allDocsBitset, capacity, getValue) {
|
|
3228
|
+
return scanToBitset(allDocsBitset, capacity, getValue, (v) => {
|
|
3229
|
+
if (v === void 0 || v === null) return false;
|
|
3230
|
+
if (typeof v === "string" && v === "") return false;
|
|
3231
|
+
if (Array.isArray(v) && v.length === 0) return false;
|
|
3232
|
+
return true;
|
|
3233
|
+
});
|
|
3234
|
+
}
|
|
3235
|
+
function applyGeoRadiusBitset(filter, geoIndex, capacity) {
|
|
3236
|
+
const distanceMeters = convertToMeters(filter.distance, filter.unit);
|
|
3237
|
+
const setResult = geoIndex.radiusQuery(
|
|
3238
|
+
filter.lat,
|
|
3239
|
+
filter.lon,
|
|
3240
|
+
distanceMeters,
|
|
3241
|
+
filter.inside ?? true,
|
|
3242
|
+
filter.highPrecision ?? false
|
|
3243
|
+
);
|
|
3244
|
+
return bitsetFromSet(setResult, capacity);
|
|
3245
|
+
}
|
|
3246
|
+
function applyGeoPolygonBitset(filter, geoIndex, capacity) {
|
|
3247
|
+
const setResult = geoIndex.polygonQuery(filter.points, filter.inside ?? true);
|
|
3248
|
+
return bitsetFromSet(setResult, capacity);
|
|
2789
3249
|
}
|
|
2790
3250
|
|
|
2791
|
-
// src/
|
|
2792
|
-
function
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
state.enumIndexes.set(fieldPath, createEnumIndex());
|
|
2799
|
-
} else if (fieldType === "geopoint" && !state.geoIndexes.has(fieldPath)) {
|
|
2800
|
-
state.geoIndexes.set(fieldPath, createGeoIndex());
|
|
3251
|
+
// src/filters/evaluator.ts
|
|
3252
|
+
function evaluateFilters(expression, context) {
|
|
3253
|
+
const bitsets = [];
|
|
3254
|
+
if (expression.fields) {
|
|
3255
|
+
for (const [fieldPath, filter] of Object.entries(expression.fields)) {
|
|
3256
|
+
bitsets.push(evaluateFieldFilter(fieldPath, filter, context));
|
|
3257
|
+
}
|
|
2801
3258
|
}
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
if (!idx) {
|
|
2806
|
-
idx = createNumericIndex();
|
|
2807
|
-
state.numericIndexes.set(fieldPath, idx);
|
|
3259
|
+
if (expression.and?.length) {
|
|
3260
|
+
const andBitsets = expression.and.map((expr) => evaluateFilters(expr, context));
|
|
3261
|
+
bitsets.push(applyAndBitset(andBitsets));
|
|
2808
3262
|
}
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
let idx = state.booleanIndexes.get(fieldPath);
|
|
2813
|
-
if (!idx) {
|
|
2814
|
-
idx = createBooleanIndex();
|
|
2815
|
-
state.booleanIndexes.set(fieldPath, idx);
|
|
3263
|
+
if (expression.or?.length) {
|
|
3264
|
+
const orBitsets = expression.or.map((expr) => evaluateFilters(expr, context));
|
|
3265
|
+
bitsets.push(applyOrBitset(orBitsets));
|
|
2816
3266
|
}
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
if (internalId === void 0) {
|
|
2822
|
-
throw new Error(`Internal ID not found for document "${docId}"`);
|
|
3267
|
+
if (expression.not) {
|
|
3268
|
+
const excluded = evaluateFilters(expression.not, context);
|
|
3269
|
+
const universe = context.allDocIdsBitset;
|
|
3270
|
+
bitsets.push(applyAndBitset([universe, applyNotBitset(excluded, context.capacity)]));
|
|
2823
3271
|
}
|
|
2824
|
-
return
|
|
3272
|
+
if (bitsets.length === 0) return context.allDocIdsBitset;
|
|
3273
|
+
if (bitsets.length === 1) return bitsets[0];
|
|
3274
|
+
return applyAndBitset(bitsets);
|
|
2825
3275
|
}
|
|
2826
|
-
function
|
|
2827
|
-
const
|
|
2828
|
-
const
|
|
2829
|
-
const
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
existing.positions.push(t.position);
|
|
2837
|
-
} else {
|
|
2838
|
-
tokenFreqs.set(t.token, { count: 1, positions: [t.position] });
|
|
2839
|
-
}
|
|
2840
|
-
fieldTokenList.push(t.token);
|
|
2841
|
-
}
|
|
2842
|
-
for (const [token, freq] of tokenFreqs) {
|
|
2843
|
-
state.invertedIdx.insert(token, internalId, freq.count, fieldNameIndex, freq.positions);
|
|
2844
|
-
}
|
|
2845
|
-
} else {
|
|
2846
|
-
const tokenCounts = /* @__PURE__ */ new Map();
|
|
2847
|
-
for (const t of tokenizeIterator(text, language, opts)) {
|
|
2848
|
-
tokenCounts.set(t.token, (tokenCounts.get(t.token) ?? 0) + 1);
|
|
2849
|
-
fieldTokenList.push(t.token);
|
|
2850
|
-
}
|
|
2851
|
-
for (const [token, count] of tokenCounts) {
|
|
2852
|
-
state.invertedIdx.insert(token, internalId, count, fieldNameIndex, null);
|
|
3276
|
+
function evaluateFieldFilter(fieldPath, filter, context) {
|
|
3277
|
+
const fieldIndex = context.fieldIndexes[fieldPath];
|
|
3278
|
+
const getValue = (internalId) => context.getFieldValue(internalId, fieldPath);
|
|
3279
|
+
const f = filter;
|
|
3280
|
+
const bitsets = [];
|
|
3281
|
+
const { capacity } = context;
|
|
3282
|
+
let allDocsBitset = null;
|
|
3283
|
+
const getAllDocsBitset = () => {
|
|
3284
|
+
if (allDocsBitset === null) {
|
|
3285
|
+
allDocsBitset = context.allDocIdsBitset;
|
|
2853
3286
|
}
|
|
3287
|
+
return allDocsBitset;
|
|
3288
|
+
};
|
|
3289
|
+
if ("radius" in f && f.radius) {
|
|
3290
|
+
const geoIndex = resolveGeoIndex(fieldPath, fieldIndex);
|
|
3291
|
+
bitsets.push(applyGeoRadiusBitset(filter.radius, geoIndex, capacity));
|
|
2854
3292
|
}
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
function indexStringArrayField(state, internalId, fieldPath, arr, language, options, fieldLengths, tokensByField) {
|
|
2859
|
-
const fieldTokenList = [];
|
|
2860
|
-
const fieldNameIndex = getOrCreateFieldNameIndex(state.fieldNameTable, fieldPath);
|
|
2861
|
-
const opts = tokenizeOptions(options);
|
|
2862
|
-
if (state.trackPositions) {
|
|
2863
|
-
const tokenFreqs = /* @__PURE__ */ new Map();
|
|
2864
|
-
let positionOffset = 0;
|
|
2865
|
-
for (const item of arr) {
|
|
2866
|
-
let itemTokenCount = 0;
|
|
2867
|
-
for (const t of tokenizeIterator(item, language, opts)) {
|
|
2868
|
-
const existing = tokenFreqs.get(t.token);
|
|
2869
|
-
if (existing) {
|
|
2870
|
-
existing.count++;
|
|
2871
|
-
existing.positions.push(positionOffset + t.position);
|
|
2872
|
-
} else {
|
|
2873
|
-
tokenFreqs.set(t.token, { count: 1, positions: [positionOffset + t.position] });
|
|
2874
|
-
}
|
|
2875
|
-
fieldTokenList.push(t.token);
|
|
2876
|
-
itemTokenCount++;
|
|
2877
|
-
}
|
|
2878
|
-
positionOffset += itemTokenCount;
|
|
2879
|
-
}
|
|
2880
|
-
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2881
|
-
for (const [token, freq] of tokenFreqs) {
|
|
2882
|
-
state.invertedIdx.insert(token, internalId, freq.count, fieldNameIndex, freq.positions);
|
|
2883
|
-
}
|
|
2884
|
-
} else {
|
|
2885
|
-
const tokenCounts = /* @__PURE__ */ new Map();
|
|
2886
|
-
for (const item of arr) {
|
|
2887
|
-
for (const t of tokenizeIterator(item, language, opts)) {
|
|
2888
|
-
tokenCounts.set(t.token, (tokenCounts.get(t.token) ?? 0) + 1);
|
|
2889
|
-
fieldTokenList.push(t.token);
|
|
2890
|
-
}
|
|
2891
|
-
}
|
|
2892
|
-
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2893
|
-
for (const [token, count] of tokenCounts) {
|
|
2894
|
-
state.invertedIdx.insert(token, internalId, count, fieldNameIndex, null);
|
|
2895
|
-
}
|
|
3293
|
+
if ("polygon" in f && f.polygon) {
|
|
3294
|
+
const geoIndex = resolveGeoIndex(fieldPath, fieldIndex);
|
|
3295
|
+
bitsets.push(applyGeoPolygonBitset(filter.polygon, geoIndex, capacity));
|
|
2896
3296
|
}
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
function indexDocument(state, docId, document, flatSchema, language, options) {
|
|
2900
|
-
const fieldLengths = {};
|
|
2901
|
-
const tokensByField = {};
|
|
2902
|
-
const internalId = resolveInternalId(state, docId);
|
|
2903
|
-
for (const [fieldPath, fieldType] of Object.entries(flatSchema)) {
|
|
2904
|
-
const value = getNestedValue(document, fieldPath);
|
|
2905
|
-
if (value === void 0 || value === null) continue;
|
|
2906
|
-
ensureFieldIndex(state, fieldPath, fieldType);
|
|
2907
|
-
if (fieldType === "string") {
|
|
2908
|
-
indexStringField(state, internalId, fieldPath, value, language, options, fieldLengths, tokensByField);
|
|
2909
|
-
} else if (fieldType === "number") {
|
|
2910
|
-
getOrCreateNumericIndex(state, fieldPath).insert(internalId, value);
|
|
2911
|
-
} else if (fieldType === "boolean") {
|
|
2912
|
-
getOrCreateBooleanIndex(state, fieldPath).insert(internalId, value);
|
|
2913
|
-
} else if (fieldType === "enum") {
|
|
2914
|
-
state.enumIndexes.get(fieldPath)?.insert(internalId, value);
|
|
2915
|
-
} else if (fieldType === "geopoint") {
|
|
2916
|
-
const geo = value;
|
|
2917
|
-
state.geoIndexes.get(fieldPath)?.insert(internalId, geo.lat, geo.lon);
|
|
2918
|
-
} else if (fieldType === "string[]") {
|
|
2919
|
-
indexStringArrayField(
|
|
2920
|
-
state,
|
|
2921
|
-
internalId,
|
|
2922
|
-
fieldPath,
|
|
2923
|
-
value,
|
|
2924
|
-
language,
|
|
2925
|
-
options,
|
|
2926
|
-
fieldLengths,
|
|
2927
|
-
tokensByField
|
|
2928
|
-
);
|
|
2929
|
-
} else if (fieldType === "number[]") {
|
|
2930
|
-
const numIdx = getOrCreateNumericIndex(state, fieldPath);
|
|
2931
|
-
for (const num of value) numIdx.insert(internalId, num);
|
|
2932
|
-
} else if (fieldType === "boolean[]") {
|
|
2933
|
-
const boolIdx = getOrCreateBooleanIndex(state, fieldPath);
|
|
2934
|
-
for (const b of value) boolIdx.insert(internalId, b);
|
|
2935
|
-
} else if (fieldType === "enum[]") {
|
|
2936
|
-
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
2937
|
-
if (enumIdx) {
|
|
2938
|
-
for (const e of value) enumIdx.insert(internalId, e);
|
|
2939
|
-
}
|
|
2940
|
-
}
|
|
3297
|
+
if ("eq" in f && f.eq !== void 0) {
|
|
3298
|
+
bitsets.push(applyEqBitset(f.eq, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
2941
3299
|
}
|
|
2942
|
-
|
|
3300
|
+
if ("ne" in f && f.ne !== void 0) {
|
|
3301
|
+
bitsets.push(applyNeBitset(f.ne, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3302
|
+
}
|
|
3303
|
+
if ("gt" in f && f.gt !== void 0) {
|
|
3304
|
+
bitsets.push(applyGtBitset(f.gt, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3305
|
+
}
|
|
3306
|
+
if ("lt" in f && f.lt !== void 0) {
|
|
3307
|
+
bitsets.push(applyLtBitset(f.lt, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3308
|
+
}
|
|
3309
|
+
if ("gte" in f && f.gte !== void 0) {
|
|
3310
|
+
bitsets.push(applyGteBitset(f.gte, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3311
|
+
}
|
|
3312
|
+
if ("lte" in f && f.lte !== void 0) {
|
|
3313
|
+
bitsets.push(applyLteBitset(f.lte, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3314
|
+
}
|
|
3315
|
+
if ("between" in f && f.between !== void 0) {
|
|
3316
|
+
bitsets.push(applyBetweenBitset(f.between, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3317
|
+
}
|
|
3318
|
+
if ("in" in f && f.in !== void 0) {
|
|
3319
|
+
bitsets.push(applyInBitset(f.in, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3320
|
+
}
|
|
3321
|
+
if ("nin" in f && f.nin !== void 0) {
|
|
3322
|
+
bitsets.push(applyNinBitset(f.nin, getAllDocsBitset, capacity, getValue, fieldIndex));
|
|
3323
|
+
}
|
|
3324
|
+
if ("startsWith" in f && f.startsWith !== void 0) {
|
|
3325
|
+
bitsets.push(applyStartsWithBitset(f.startsWith, getAllDocsBitset, capacity, getValue));
|
|
3326
|
+
}
|
|
3327
|
+
if ("endsWith" in f && f.endsWith !== void 0) {
|
|
3328
|
+
bitsets.push(applyEndsWithBitset(f.endsWith, getAllDocsBitset, capacity, getValue));
|
|
3329
|
+
}
|
|
3330
|
+
if ("containsAll" in f && f.containsAll !== void 0) {
|
|
3331
|
+
bitsets.push(
|
|
3332
|
+
applyContainsAllBitset(f.containsAll, getAllDocsBitset, capacity, getValue)
|
|
3333
|
+
);
|
|
3334
|
+
}
|
|
3335
|
+
if ("matchesAny" in f && f.matchesAny !== void 0) {
|
|
3336
|
+
bitsets.push(
|
|
3337
|
+
applyMatchesAnyBitset(f.matchesAny, getAllDocsBitset, capacity, getValue)
|
|
3338
|
+
);
|
|
3339
|
+
}
|
|
3340
|
+
if ("size" in f && f.size !== void 0) {
|
|
3341
|
+
bitsets.push(applySizeBitset(f.size, getAllDocsBitset, capacity, getValue));
|
|
3342
|
+
}
|
|
3343
|
+
if ("exists" in f && f.exists !== void 0) {
|
|
3344
|
+
bitsets.push(
|
|
3345
|
+
f.exists ? applyExistsBitset(getAllDocsBitset, capacity, getValue) : applyNotExistsBitset(getAllDocsBitset, capacity, getValue)
|
|
3346
|
+
);
|
|
3347
|
+
}
|
|
3348
|
+
if ("notExists" in f && f.notExists !== void 0) {
|
|
3349
|
+
bitsets.push(
|
|
3350
|
+
f.notExists ? applyNotExistsBitset(getAllDocsBitset, capacity, getValue) : applyExistsBitset(getAllDocsBitset, capacity, getValue)
|
|
3351
|
+
);
|
|
3352
|
+
}
|
|
3353
|
+
if ("isEmpty" in f && f.isEmpty !== void 0) {
|
|
3354
|
+
bitsets.push(
|
|
3355
|
+
f.isEmpty ? applyIsEmptyBitset(getAllDocsBitset, capacity, getValue) : applyIsNotEmptyBitset(getAllDocsBitset, capacity, getValue)
|
|
3356
|
+
);
|
|
3357
|
+
}
|
|
3358
|
+
if ("isNotEmpty" in f && f.isNotEmpty !== void 0) {
|
|
3359
|
+
bitsets.push(
|
|
3360
|
+
f.isNotEmpty ? applyIsNotEmptyBitset(getAllDocsBitset, capacity, getValue) : applyIsEmptyBitset(getAllDocsBitset, capacity, getValue)
|
|
3361
|
+
);
|
|
3362
|
+
}
|
|
3363
|
+
if (bitsets.length === 0) return context.allDocIdsBitset;
|
|
3364
|
+
if (bitsets.length === 1) return bitsets[0];
|
|
3365
|
+
return applyAndBitset(bitsets);
|
|
2943
3366
|
}
|
|
2944
|
-
function
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
if (value === void 0 || value === null) continue;
|
|
2952
|
-
if (fieldType === "string") {
|
|
2953
|
-
const result = tokenize(value, language, tokenizeOptions(options));
|
|
2954
|
-
fieldLengths[fieldPath] = result.tokens.length;
|
|
2955
|
-
const uniqueTokens = /* @__PURE__ */ new Set();
|
|
2956
|
-
const fieldTokenList = [];
|
|
2957
|
-
for (const t of result.tokens) {
|
|
2958
|
-
uniqueTokens.add(t.token);
|
|
2959
|
-
fieldTokenList.push(t.token);
|
|
2960
|
-
}
|
|
2961
|
-
for (const token of uniqueTokens) state.invertedIdx.remove(token, internalId);
|
|
2962
|
-
tokensByField[fieldPath] = fieldTokenList;
|
|
2963
|
-
} else if (fieldType === "number") {
|
|
2964
|
-
state.numericIndexes.get(fieldPath)?.remove(internalId, value);
|
|
2965
|
-
} else if (fieldType === "boolean") {
|
|
2966
|
-
state.booleanIndexes.get(fieldPath)?.remove(internalId, value);
|
|
2967
|
-
} else if (fieldType === "enum") {
|
|
2968
|
-
state.enumIndexes.get(fieldPath)?.remove(internalId, value);
|
|
2969
|
-
} else if (fieldType === "geopoint") {
|
|
2970
|
-
state.geoIndexes.get(fieldPath)?.remove(internalId);
|
|
2971
|
-
} else if (fieldType === "string[]") {
|
|
2972
|
-
const arr = value;
|
|
2973
|
-
const uniqueTokens = /* @__PURE__ */ new Set();
|
|
2974
|
-
const fieldTokenList = [];
|
|
2975
|
-
for (const item of arr) {
|
|
2976
|
-
const result = tokenize(item, language, tokenizeOptions(options));
|
|
2977
|
-
for (const t of result.tokens) {
|
|
2978
|
-
uniqueTokens.add(t.token);
|
|
2979
|
-
fieldTokenList.push(t.token);
|
|
2980
|
-
}
|
|
2981
|
-
}
|
|
2982
|
-
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2983
|
-
for (const token of uniqueTokens) state.invertedIdx.remove(token, internalId);
|
|
2984
|
-
tokensByField[fieldPath] = fieldTokenList;
|
|
2985
|
-
} else if (fieldType === "number[]") {
|
|
2986
|
-
const numIdx = state.numericIndexes.get(fieldPath);
|
|
2987
|
-
if (numIdx) {
|
|
2988
|
-
for (const num of value) numIdx.remove(internalId, num);
|
|
2989
|
-
}
|
|
2990
|
-
} else if (fieldType === "boolean[]") {
|
|
2991
|
-
const boolIdx = state.booleanIndexes.get(fieldPath);
|
|
2992
|
-
if (boolIdx) {
|
|
2993
|
-
for (const b of value) boolIdx.remove(internalId, b);
|
|
2994
|
-
}
|
|
2995
|
-
} else if (fieldType === "enum[]") {
|
|
2996
|
-
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
2997
|
-
if (enumIdx) {
|
|
2998
|
-
for (const e of value) enumIdx.remove(internalId, e);
|
|
2999
|
-
}
|
|
3000
|
-
}
|
|
3367
|
+
function resolveGeoIndex(fieldPath, fieldIndex) {
|
|
3368
|
+
if (fieldIndex?.type !== "geopoint") {
|
|
3369
|
+
throw new NarsilError(
|
|
3370
|
+
ErrorCodes.SEARCH_INVALID_FILTER,
|
|
3371
|
+
`Field "${fieldPath}" requires a geopoint index for geo filters`,
|
|
3372
|
+
{ fieldPath }
|
|
3373
|
+
);
|
|
3001
3374
|
}
|
|
3002
|
-
return
|
|
3375
|
+
return fieldIndex.index;
|
|
3003
3376
|
}
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
if (
|
|
3012
|
-
continue;
|
|
3013
|
-
if (newVal !== void 0 && newVal !== null) {
|
|
3014
|
-
ensureFieldIndex(state, fieldPath, fieldType);
|
|
3015
|
-
}
|
|
3016
|
-
if (fieldType === "number") {
|
|
3377
|
+
|
|
3378
|
+
// src/core/partition/filters.ts
|
|
3379
|
+
function buildFilterContext(state, schema) {
|
|
3380
|
+
const flat = getFlatSchema(state, schema);
|
|
3381
|
+
const fieldIndexes = {};
|
|
3382
|
+
const capacity = state.docStore.internalIdCapacity();
|
|
3383
|
+
for (const [fieldPath, fieldType] of Object.entries(flat)) {
|
|
3384
|
+
if (fieldType === "number" || fieldType === "number[]") {
|
|
3017
3385
|
const numIdx = state.numericIndexes.get(fieldPath);
|
|
3018
3386
|
if (numIdx) {
|
|
3019
|
-
|
|
3020
|
-
|
|
3387
|
+
fieldIndexes[fieldPath] = {
|
|
3388
|
+
type: "numeric",
|
|
3389
|
+
index: {
|
|
3390
|
+
eq: (v) => numIdx.queryEq(v),
|
|
3391
|
+
gt: (v) => numIdx.queryGt(v),
|
|
3392
|
+
gte: (v) => numIdx.queryGte(v),
|
|
3393
|
+
lt: (v) => numIdx.queryLt(v),
|
|
3394
|
+
lte: (v) => numIdx.queryLte(v),
|
|
3395
|
+
between: (min, max) => numIdx.queryBetween(min, max),
|
|
3396
|
+
allDocIds: () => numIdx.getAllDocIds(),
|
|
3397
|
+
eqBitset: (v, cap) => numIdx.queryEqBitset(v, cap),
|
|
3398
|
+
gtBitset: (v, cap) => numIdx.queryGtBitset(v, cap),
|
|
3399
|
+
gteBitset: (v, cap) => numIdx.queryGteBitset(v, cap),
|
|
3400
|
+
ltBitset: (v, cap) => numIdx.queryLtBitset(v, cap),
|
|
3401
|
+
lteBitset: (v, cap) => numIdx.queryLteBitset(v, cap),
|
|
3402
|
+
betweenBitset: (min, max, cap) => numIdx.queryBetweenBitset(min, max, cap),
|
|
3403
|
+
allDocIdsBitset: (cap) => numIdx.getAllDocIdsBitset(cap)
|
|
3404
|
+
}
|
|
3405
|
+
};
|
|
3021
3406
|
}
|
|
3022
|
-
} else if (fieldType === "boolean") {
|
|
3407
|
+
} else if (fieldType === "boolean" || fieldType === "boolean[]") {
|
|
3023
3408
|
const boolIdx = state.booleanIndexes.get(fieldPath);
|
|
3024
3409
|
if (boolIdx) {
|
|
3025
|
-
|
|
3026
|
-
|
|
3410
|
+
fieldIndexes[fieldPath] = {
|
|
3411
|
+
type: "boolean",
|
|
3412
|
+
index: {
|
|
3413
|
+
getTrue: () => boolIdx.queryEq(true),
|
|
3414
|
+
getFalse: () => boolIdx.queryEq(false),
|
|
3415
|
+
allDocIds: () => boolIdx.getAllDocIds(),
|
|
3416
|
+
getTrueBitset: (cap) => boolIdx.queryEqBitset(true, cap),
|
|
3417
|
+
getFalseBitset: (cap) => boolIdx.queryEqBitset(false, cap),
|
|
3418
|
+
allDocIdsBitset: (cap) => boolIdx.getAllDocIdsBitset(cap)
|
|
3419
|
+
}
|
|
3420
|
+
};
|
|
3027
3421
|
}
|
|
3028
|
-
} else if (fieldType === "enum") {
|
|
3422
|
+
} else if (fieldType === "enum" || fieldType === "enum[]") {
|
|
3029
3423
|
const enumIdx = state.enumIndexes.get(fieldPath);
|
|
3030
3424
|
if (enumIdx) {
|
|
3031
|
-
|
|
3032
|
-
|
|
3425
|
+
fieldIndexes[fieldPath] = {
|
|
3426
|
+
type: "enum",
|
|
3427
|
+
index: {
|
|
3428
|
+
getDocIds: (v) => enumIdx.queryEq(v),
|
|
3429
|
+
allDocIds: () => enumIdx.getAllDocIds(),
|
|
3430
|
+
getDocIdsBitset: (v, cap) => enumIdx.queryEqBitset(v, cap),
|
|
3431
|
+
getDocIdsInBitset: (values, cap) => enumIdx.queryInBitset(values, cap),
|
|
3432
|
+
allDocIdsBitset: (cap) => enumIdx.getAllDocIdsBitset(cap)
|
|
3433
|
+
}
|
|
3434
|
+
};
|
|
3033
3435
|
}
|
|
3034
3436
|
} else if (fieldType === "geopoint") {
|
|
3035
3437
|
const geoIdx = state.geoIndexes.get(fieldPath);
|
|
3036
3438
|
if (geoIdx) {
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
}
|
|
3439
|
+
fieldIndexes[fieldPath] = {
|
|
3440
|
+
type: "geopoint",
|
|
3441
|
+
index: geoIdx
|
|
3442
|
+
};
|
|
3042
3443
|
}
|
|
3043
|
-
}
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
let cachedAllDocIds = null;
|
|
3447
|
+
let cachedAllDocIdsBitset = null;
|
|
3448
|
+
return {
|
|
3449
|
+
fieldIndexes,
|
|
3450
|
+
getFieldValue: (internalId, fieldPath) => getFieldValueByInternalId(state.docStore, internalId, fieldPath),
|
|
3451
|
+
get allDocIds() {
|
|
3452
|
+
if (!cachedAllDocIds) {
|
|
3453
|
+
cachedAllDocIds = getAllInternalDocIds(state.docStore);
|
|
3052
3454
|
}
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
if (newVal !== void 0 && newVal !== null) {
|
|
3060
|
-
for (const b of newVal) boolIdx.insert(internalId, b);
|
|
3061
|
-
}
|
|
3455
|
+
return cachedAllDocIds;
|
|
3456
|
+
},
|
|
3457
|
+
capacity,
|
|
3458
|
+
get allDocIdsBitset() {
|
|
3459
|
+
if (!cachedAllDocIdsBitset) {
|
|
3460
|
+
cachedAllDocIdsBitset = bitsetFromSet(this.allDocIds, capacity);
|
|
3062
3461
|
}
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3462
|
+
return cachedAllDocIdsBitset;
|
|
3463
|
+
}
|
|
3464
|
+
};
|
|
3465
|
+
}
|
|
3466
|
+
function applyPartitionFilters(state, filters, schema) {
|
|
3467
|
+
const context = buildFilterContext(state, schema);
|
|
3468
|
+
const resultBitset = evaluateFilters(filters, context);
|
|
3469
|
+
const resolver = state.docStore.resolver();
|
|
3470
|
+
const externalResult = /* @__PURE__ */ new Set();
|
|
3471
|
+
for (let wi = 0; wi < resultBitset.length; wi++) {
|
|
3472
|
+
let word = resultBitset[wi];
|
|
3473
|
+
if (word === 0) continue;
|
|
3474
|
+
const base = wi << 5;
|
|
3475
|
+
while (word !== 0) {
|
|
3476
|
+
const tz = Math.clz32(word & -word) ^ 31;
|
|
3477
|
+
const internalId = base + tz;
|
|
3478
|
+
const externalId = resolver.toExternal(internalId);
|
|
3479
|
+
if (externalId !== void 0) {
|
|
3480
|
+
externalResult.add(externalId);
|
|
3072
3481
|
}
|
|
3482
|
+
word &= word - 1;
|
|
3073
3483
|
}
|
|
3074
3484
|
}
|
|
3485
|
+
return externalResult;
|
|
3486
|
+
}
|
|
3487
|
+
function applyPartitionFiltersBitset(state, filters, schema) {
|
|
3488
|
+
const context = buildFilterContext(state, schema);
|
|
3489
|
+
return evaluateFilters(filters, context);
|
|
3075
3490
|
}
|
|
3076
3491
|
|
|
3077
3492
|
// src/core/scorer.ts
|
|
@@ -3129,6 +3544,7 @@ function accumulateTermScore(docScores, internalId, termScore, collect, fieldNam
|
|
|
3129
3544
|
function searchFulltext(state, params) {
|
|
3130
3545
|
const {
|
|
3131
3546
|
queryTokens,
|
|
3547
|
+
prefixExpansion,
|
|
3132
3548
|
fields,
|
|
3133
3549
|
boost,
|
|
3134
3550
|
tolerance = 0,
|
|
@@ -3153,9 +3569,132 @@ function searchFulltext(state, params) {
|
|
|
3153
3569
|
const useIntersection = termMatch === "all" && queryTokens.length > 1;
|
|
3154
3570
|
const fieldNames = state.fieldNameTable.names;
|
|
3155
3571
|
const resolver = state.docStore.resolver();
|
|
3572
|
+
function resolveFieldLength(internalId, fieldName, avgLen) {
|
|
3573
|
+
let cachedLengths = fieldLengthCache.get(internalId);
|
|
3574
|
+
if (cachedLengths === void 0) {
|
|
3575
|
+
const externalId = resolver.toExternal(internalId);
|
|
3576
|
+
const storedDoc = externalId !== void 0 ? state.docStore.get(externalId) : void 0;
|
|
3577
|
+
cachedLengths = storedDoc?.fieldLengths ?? null;
|
|
3578
|
+
fieldLengthCache.set(internalId, cachedLengths);
|
|
3579
|
+
}
|
|
3580
|
+
return cachedLengths?.[fieldName] ?? avgLen;
|
|
3581
|
+
}
|
|
3582
|
+
function resolvePrefixMatches(token, expansionTerms) {
|
|
3583
|
+
const found = [];
|
|
3584
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3585
|
+
for (const term of [token, ...expansionTerms]) {
|
|
3586
|
+
if (seen.has(term)) continue;
|
|
3587
|
+
seen.add(term);
|
|
3588
|
+
const postingList = state.invertedIdx.lookup(term);
|
|
3589
|
+
if (!postingList) continue;
|
|
3590
|
+
const docFreq = globalStats ? globalDocFreqs[term] ?? postingList.docIdSet.size : postingList.docIdSet.size;
|
|
3591
|
+
found.push({ token: term, postingList, docFreq });
|
|
3592
|
+
}
|
|
3593
|
+
if (found.length === 0) return [];
|
|
3594
|
+
let blendedDf = 0;
|
|
3595
|
+
for (const f of found) {
|
|
3596
|
+
if (f.docFreq > blendedDf) blendedDf = f.docFreq;
|
|
3597
|
+
}
|
|
3598
|
+
const blendedIdf = computeIDF(blendedDf, totalDocs);
|
|
3599
|
+
return found.map((f) => ({
|
|
3600
|
+
token: f.token,
|
|
3601
|
+
factor: Math.min(1, token.length / f.token.length),
|
|
3602
|
+
postingList: f.postingList,
|
|
3603
|
+
docFreq: blendedDf,
|
|
3604
|
+
idf: blendedIdf
|
|
3605
|
+
}));
|
|
3606
|
+
}
|
|
3607
|
+
function computePrefixContributions(matches, collect) {
|
|
3608
|
+
const best = /* @__PURE__ */ new Map();
|
|
3609
|
+
for (const match of matches) {
|
|
3610
|
+
const perTerm = /* @__PURE__ */ new Map();
|
|
3611
|
+
const list = match.postingList;
|
|
3612
|
+
const hasDeleted = list.deletedDocs.size > 0;
|
|
3613
|
+
for (let pi = 0; pi < list.length; pi++) {
|
|
3614
|
+
const internalId = list.docIds[pi];
|
|
3615
|
+
if (hasDeleted && list.deletedDocs.has(internalId)) continue;
|
|
3616
|
+
if (filterBitset && !bitsetHas(filterBitset, internalId)) continue;
|
|
3617
|
+
const fieldName = fieldNames[list.fieldNameIndices[pi]];
|
|
3618
|
+
if (fields && !fields.includes(fieldName)) continue;
|
|
3619
|
+
const termFrequency = list.termFrequencies[pi];
|
|
3620
|
+
const fieldBoost = boost?.[fieldName] ?? 1;
|
|
3621
|
+
const avgLen = avgFieldLengths[fieldName] ?? 1;
|
|
3622
|
+
const actualFieldLength = resolveFieldLength(internalId, fieldName, avgLen);
|
|
3623
|
+
const termScore = scoreFn(termFrequency, match.docFreq, totalDocs, actualFieldLength, avgLen, bm25Params) * fieldBoost * match.factor;
|
|
3624
|
+
const existing = perTerm.get(internalId);
|
|
3625
|
+
if (existing) {
|
|
3626
|
+
existing.score += termScore;
|
|
3627
|
+
if (collect) {
|
|
3628
|
+
existing.termFrequencies[`${fieldName}:${match.token}`] = termFrequency;
|
|
3629
|
+
existing.fieldLengths[fieldName] = actualFieldLength;
|
|
3630
|
+
}
|
|
3631
|
+
} else if (collect) {
|
|
3632
|
+
perTerm.set(internalId, {
|
|
3633
|
+
score: termScore,
|
|
3634
|
+
token: match.token,
|
|
3635
|
+
idf: match.idf,
|
|
3636
|
+
termFrequencies: { [`${fieldName}:${match.token}`]: termFrequency },
|
|
3637
|
+
fieldLengths: { [fieldName]: actualFieldLength }
|
|
3638
|
+
});
|
|
3639
|
+
} else {
|
|
3640
|
+
perTerm.set(internalId, {
|
|
3641
|
+
score: termScore,
|
|
3642
|
+
token: match.token,
|
|
3643
|
+
idf: match.idf,
|
|
3644
|
+
termFrequencies: EMPTY_COMPONENTS,
|
|
3645
|
+
fieldLengths: EMPTY_COMPONENTS
|
|
3646
|
+
});
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
for (const [internalId, contribution] of perTerm) {
|
|
3650
|
+
const current = best.get(internalId);
|
|
3651
|
+
if (!current || contribution.score > current.score) {
|
|
3652
|
+
best.set(internalId, contribution);
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3656
|
+
return best;
|
|
3657
|
+
}
|
|
3658
|
+
function mergePrefixContribution(internalId, contribution, collect) {
|
|
3659
|
+
const existing = docScores.get(internalId);
|
|
3660
|
+
if (existing) {
|
|
3661
|
+
existing.score += contribution.score;
|
|
3662
|
+
if (collect) {
|
|
3663
|
+
Object.assign(existing.termFrequencies, contribution.termFrequencies);
|
|
3664
|
+
Object.assign(existing.fieldLengths, contribution.fieldLengths);
|
|
3665
|
+
existing.idf[contribution.token] = contribution.idf;
|
|
3666
|
+
}
|
|
3667
|
+
return;
|
|
3668
|
+
}
|
|
3669
|
+
if (collect) {
|
|
3670
|
+
docScores.set(internalId, {
|
|
3671
|
+
score: contribution.score,
|
|
3672
|
+
termFrequencies: contribution.termFrequencies,
|
|
3673
|
+
fieldLengths: contribution.fieldLengths,
|
|
3674
|
+
idf: { [contribution.token]: contribution.idf }
|
|
3675
|
+
});
|
|
3676
|
+
} else {
|
|
3677
|
+
docScores.set(internalId, {
|
|
3678
|
+
score: contribution.score,
|
|
3679
|
+
termFrequencies: EMPTY_COMPONENTS,
|
|
3680
|
+
fieldLengths: EMPTY_COMPONENTS,
|
|
3681
|
+
idf: EMPTY_COMPONENTS
|
|
3682
|
+
});
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3156
3685
|
if (useIntersection) {
|
|
3157
3686
|
const resolved = [];
|
|
3687
|
+
let prefixMatches = [];
|
|
3158
3688
|
for (const qt of queryTokens) {
|
|
3689
|
+
if (prefixExpansion && qt.token === prefixExpansion.token) {
|
|
3690
|
+
prefixMatches = resolvePrefixMatches(qt.token, prefixExpansion.terms);
|
|
3691
|
+
let totalPostings2 = 0;
|
|
3692
|
+
for (const m of prefixMatches) {
|
|
3693
|
+
totalPostings2 += m.postingList.length;
|
|
3694
|
+
}
|
|
3695
|
+
resolved.push({ token: qt.token, matches: [], totalPostings: totalPostings2, isPrefix: true });
|
|
3696
|
+
continue;
|
|
3697
|
+
}
|
|
3159
3698
|
const rawMatches = exact ? (() => {
|
|
3160
3699
|
const postingList = state.invertedIdx.lookup(qt.token);
|
|
3161
3700
|
return postingList ? [{ token: qt.token, postingList }] : [];
|
|
@@ -3172,6 +3711,14 @@ function searchFulltext(state, params) {
|
|
|
3172
3711
|
}
|
|
3173
3712
|
resolved.sort((a, b) => a.totalPostings - b.totalPostings);
|
|
3174
3713
|
for (let tokenIndex = 0; tokenIndex < resolved.length; tokenIndex++) {
|
|
3714
|
+
if (resolved[tokenIndex].isPrefix) {
|
|
3715
|
+
const contributions = computePrefixContributions(prefixMatches, collectComponents);
|
|
3716
|
+
for (const [internalId, contribution] of contributions) {
|
|
3717
|
+
if (tokenIndex > 0 && !docScores.has(internalId)) continue;
|
|
3718
|
+
mergePrefixContribution(internalId, contribution, collectComponents);
|
|
3719
|
+
}
|
|
3720
|
+
continue;
|
|
3721
|
+
}
|
|
3175
3722
|
for (const match of resolved[tokenIndex].matches) {
|
|
3176
3723
|
const list = match.postingList;
|
|
3177
3724
|
const hasDeleted = list.deletedDocs.size > 0;
|
|
@@ -3211,6 +3758,16 @@ function searchFulltext(state, params) {
|
|
|
3211
3758
|
}
|
|
3212
3759
|
} else {
|
|
3213
3760
|
for (const qt of queryTokens) {
|
|
3761
|
+
if (prefixExpansion && qt.token === prefixExpansion.token) {
|
|
3762
|
+
const contributions = computePrefixContributions(
|
|
3763
|
+
resolvePrefixMatches(qt.token, prefixExpansion.terms),
|
|
3764
|
+
collectComponents
|
|
3765
|
+
);
|
|
3766
|
+
for (const [internalId, contribution] of contributions) {
|
|
3767
|
+
mergePrefixContribution(internalId, contribution, collectComponents);
|
|
3768
|
+
}
|
|
3769
|
+
continue;
|
|
3770
|
+
}
|
|
3214
3771
|
const matchingPostings = exact ? (() => {
|
|
3215
3772
|
const postingList = state.invertedIdx.lookup(qt.token);
|
|
3216
3773
|
return postingList ? [{ token: qt.token, postingList }] : [];
|
|
@@ -3397,6 +3954,7 @@ function serializePartition(state, partitionId, indexName, totalPartitions, lang
|
|
|
3397
3954
|
enum: serializedEnum,
|
|
3398
3955
|
geopoint: serializedGeo
|
|
3399
3956
|
},
|
|
3957
|
+
surfaceForms: state.surfaceRegistry.serialize(),
|
|
3400
3958
|
statistics: serializedStats
|
|
3401
3959
|
};
|
|
3402
3960
|
}
|
|
@@ -3456,6 +4014,7 @@ function deserializePartition(state, data, clearFn, schema) {
|
|
|
3456
4014
|
geoIdx.deserialize(converted);
|
|
3457
4015
|
state.geoIndexes.set(path, geoIdx);
|
|
3458
4016
|
}
|
|
4017
|
+
state.surfaceRegistry.deserialize(data.surfaceForms ?? {});
|
|
3459
4018
|
state.stats.deserialize(data.statistics);
|
|
3460
4019
|
const flatSchema = getFlatSchema(state, schema);
|
|
3461
4020
|
const serializedFields = data.schema;
|
|
@@ -3473,6 +4032,72 @@ function deserializePartition(state, data, clearFn, schema) {
|
|
|
3473
4032
|
}
|
|
3474
4033
|
}
|
|
3475
4034
|
|
|
4035
|
+
// src/core/partition/suggestions.ts
|
|
4036
|
+
function verbatimOccurrences(state, token) {
|
|
4037
|
+
const postingList = state.invertedIdx.lookup(token);
|
|
4038
|
+
if (!postingList) return 0;
|
|
4039
|
+
const derived = postingList.totalTermFrequency - state.surfaceRegistry.stemChangedTotalFor(token);
|
|
4040
|
+
return derived > 0 ? derived : 0;
|
|
4041
|
+
}
|
|
4042
|
+
function suggestDisplayTerms(state, surfacePrefix, stemmedPrefix, limit) {
|
|
4043
|
+
if (limit <= 0 || surfacePrefix.length === 0) return [];
|
|
4044
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4045
|
+
for (const candidate of state.surfaceRegistry.candidatesForPrefix(surfacePrefix)) {
|
|
4046
|
+
const postingList = state.invertedIdx.lookup(candidate.token);
|
|
4047
|
+
if (!postingList || postingList.docIdSet.size === 0) continue;
|
|
4048
|
+
let group = groups.get(candidate.token);
|
|
4049
|
+
if (!group) {
|
|
4050
|
+
group = { documentFrequency: postingList.docIdSet.size, surfaces: [] };
|
|
4051
|
+
groups.set(candidate.token, group);
|
|
4052
|
+
}
|
|
4053
|
+
group.surfaces.push({ surface: candidate.surface, occurrences: candidate.occurrences });
|
|
4054
|
+
}
|
|
4055
|
+
const termPrefixes = state.surfaceRegistry.size() === 0 && stemmedPrefix !== surfacePrefix && stemmedPrefix.length > 0 ? [surfacePrefix, stemmedPrefix] : [surfacePrefix];
|
|
4056
|
+
for (const prefix of termPrefixes) {
|
|
4057
|
+
for (const suggestion of state.invertedIdx.prefixSearch(prefix, Number.MAX_SAFE_INTEGER)) {
|
|
4058
|
+
const occurrences = verbatimOccurrences(state, suggestion.term);
|
|
4059
|
+
if (occurrences === 0) continue;
|
|
4060
|
+
let group = groups.get(suggestion.term);
|
|
4061
|
+
if (!group) {
|
|
4062
|
+
group = { documentFrequency: suggestion.documentFrequency, surfaces: [] };
|
|
4063
|
+
groups.set(suggestion.term, group);
|
|
4064
|
+
} else if (group.surfaces.some((s) => s.surface === suggestion.term)) {
|
|
4065
|
+
continue;
|
|
4066
|
+
}
|
|
4067
|
+
group.surfaces.push({ surface: suggestion.term, occurrences });
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
const results = [];
|
|
4071
|
+
for (const [token, group] of groups) {
|
|
4072
|
+
results.push({ token, documentFrequency: group.documentFrequency, surfaces: group.surfaces });
|
|
4073
|
+
}
|
|
4074
|
+
results.sort((a, b) => b.documentFrequency - a.documentFrequency || (a.token < b.token ? -1 : 1));
|
|
4075
|
+
if (results.length > limit) results.length = limit;
|
|
4076
|
+
return results;
|
|
4077
|
+
}
|
|
4078
|
+
function expandTermPrefix(state, surfacePrefix, stemmedToken, maxExpansions) {
|
|
4079
|
+
if (maxExpansions <= 0 || surfacePrefix.length === 0) return [];
|
|
4080
|
+
const dfByToken = /* @__PURE__ */ new Map();
|
|
4081
|
+
for (const candidate of state.surfaceRegistry.candidatesForPrefix(surfacePrefix)) {
|
|
4082
|
+
if (dfByToken.has(candidate.token)) continue;
|
|
4083
|
+
const postingList = state.invertedIdx.lookup(candidate.token);
|
|
4084
|
+
if (!postingList || postingList.docIdSet.size === 0) continue;
|
|
4085
|
+
dfByToken.set(candidate.token, postingList.docIdSet.size);
|
|
4086
|
+
}
|
|
4087
|
+
const termPrefixes = state.surfaceRegistry.size() === 0 && stemmedToken !== surfacePrefix && stemmedToken.length > 0 ? [surfacePrefix, stemmedToken] : [surfacePrefix];
|
|
4088
|
+
for (const prefix of termPrefixes) {
|
|
4089
|
+
for (const suggestion of state.invertedIdx.prefixSearch(prefix, Number.MAX_SAFE_INTEGER)) {
|
|
4090
|
+
if (dfByToken.has(suggestion.term)) continue;
|
|
4091
|
+
if (verbatimOccurrences(state, suggestion.term) === 0) continue;
|
|
4092
|
+
dfByToken.set(suggestion.term, suggestion.documentFrequency);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
const entries = Array.from(dfByToken.entries());
|
|
4096
|
+
entries.sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1));
|
|
4097
|
+
if (entries.length > maxExpansions) entries.length = maxExpansions;
|
|
4098
|
+
return entries.map((e) => e[0]);
|
|
4099
|
+
}
|
|
4100
|
+
|
|
3476
4101
|
// src/core/partition/wire-payload.ts
|
|
3477
4102
|
function serializePartitionToWirePayloadV2(state, partitionId, indexName, totalPartitions, language, schema) {
|
|
3478
4103
|
const flatSchema = getFlatSchema(state, schema);
|
|
@@ -3569,6 +4194,7 @@ function serializePartitionToWirePayloadV2(state, partitionId, indexName, totalP
|
|
|
3569
4194
|
enum: wireEnum,
|
|
3570
4195
|
geopoint: wireGeo
|
|
3571
4196
|
},
|
|
4197
|
+
surface_forms: state.surfaceRegistry.serialize(),
|
|
3572
4198
|
statistics: {
|
|
3573
4199
|
total_documents: serializedStats.totalDocuments,
|
|
3574
4200
|
total_field_lengths: serializedStats.totalFieldLengths,
|
|
@@ -3585,6 +4211,7 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
3585
4211
|
invertedIdx: createInvertedIndex(fieldNameTable),
|
|
3586
4212
|
docStore: createDocumentStore(),
|
|
3587
4213
|
stats: createPartitionStats(),
|
|
4214
|
+
surfaceRegistry: createSurfaceRegistry(),
|
|
3588
4215
|
numericIndexes: /* @__PURE__ */ new Map(),
|
|
3589
4216
|
booleanIndexes: /* @__PURE__ */ new Map(),
|
|
3590
4217
|
enumIndexes: /* @__PURE__ */ new Map(),
|
|
@@ -3597,6 +4224,7 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
3597
4224
|
function clearAll() {
|
|
3598
4225
|
state.invertedIdx.clear();
|
|
3599
4226
|
state.docStore.clear();
|
|
4227
|
+
state.surfaceRegistry.clear();
|
|
3600
4228
|
for (const idx of state.numericIndexes.values()) idx.clear();
|
|
3601
4229
|
for (const idx of state.booleanIndexes.values()) idx.clear();
|
|
3602
4230
|
for (const idx of state.enumIndexes.values()) idx.clear();
|
|
@@ -3747,6 +4375,8 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
3747
4375
|
}
|
|
3748
4376
|
bytes += totalPostings * POSTING_ENTRY_SIZE;
|
|
3749
4377
|
bytes += termCount * PER_TERM_OVERHEAD;
|
|
4378
|
+
const SURFACE_ENTRY_OVERHEAD = 140;
|
|
4379
|
+
bytes += state.surfaceRegistry.size() * SURFACE_ENTRY_OVERHEAD;
|
|
3750
4380
|
const FIELD_ENTRY_OVERHEAD = 42;
|
|
3751
4381
|
bytes += docCount * state.numericIndexes.size * FIELD_ENTRY_OVERHEAD;
|
|
3752
4382
|
bytes += docCount * state.booleanIndexes.size * FIELD_ENTRY_OVERHEAD;
|
|
@@ -3766,8 +4396,11 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
3766
4396
|
computeFacets(docIds, config, schema) {
|
|
3767
4397
|
return computeFacets(state, docIds, config, schema);
|
|
3768
4398
|
},
|
|
3769
|
-
suggestTerms(
|
|
3770
|
-
return state
|
|
4399
|
+
suggestTerms(surfacePrefix, stemmedPrefix, limit) {
|
|
4400
|
+
return suggestDisplayTerms(state, surfacePrefix, stemmedPrefix, limit);
|
|
4401
|
+
},
|
|
4402
|
+
expandTermPrefix(surfacePrefix, stemmedToken, maxExpansions) {
|
|
4403
|
+
return expandTermPrefix(state, surfacePrefix, stemmedToken, maxExpansions);
|
|
3771
4404
|
},
|
|
3772
4405
|
serialize(indexName, totalPartitions, language, schema) {
|
|
3773
4406
|
return serializePartition(state, partitionId, indexName, totalPartitions, language, schema);
|
|
@@ -3822,13 +4455,15 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
3822
4455
|
function resolveInsertOptions(options) {
|
|
3823
4456
|
const applyStrict = config.strict === true;
|
|
3824
4457
|
const applyAnalyzer = config.stopWords !== void 0 || config.tokenizer !== void 0;
|
|
3825
|
-
|
|
4458
|
+
const applySurfaces = config.surfaceForms === true;
|
|
4459
|
+
if (!applyStrict && !applyAnalyzer && !applySurfaces) return options;
|
|
3826
4460
|
const resolved = { ...options };
|
|
3827
4461
|
if (applyStrict) resolved.strict = true;
|
|
3828
4462
|
if (applyAnalyzer) {
|
|
3829
4463
|
resolved.stopWordOverride = options?.stopWordOverride ?? config.stopWords;
|
|
3830
4464
|
resolved.customTokenizer = options?.customTokenizer ?? config.tokenizer;
|
|
3831
4465
|
}
|
|
4466
|
+
if (applySurfaces) resolved.collectSurfaces = true;
|
|
3832
4467
|
return resolved;
|
|
3833
4468
|
}
|
|
3834
4469
|
function rebuildDocPartitionMap() {
|
|
@@ -3925,7 +4560,7 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
3925
4560
|
if (pid === void 0) {
|
|
3926
4561
|
throw new NarsilError(ErrorCodes.DOC_NOT_FOUND, `Document "${docId}" not found in any partition`, { docId });
|
|
3927
4562
|
}
|
|
3928
|
-
partitions[pid].remove(docId, config.schema, language);
|
|
4563
|
+
partitions[pid].remove(docId, config.schema, language, resolveInsertOptions());
|
|
3929
4564
|
docPartitionMap.delete(docId);
|
|
3930
4565
|
},
|
|
3931
4566
|
beginBatchRemove() {
|
|
@@ -5341,4 +5976,4 @@ function createDirectExecutor() {
|
|
|
5341
5976
|
};
|
|
5342
5977
|
}
|
|
5343
5978
|
|
|
5344
|
-
export { MAX_NESTING_DEPTH, clearNormalizationCache, configureNormalizationCache, createDirectExecutor, createPartitionIndex, createPartitionManager, createPartitionRouter, createVectorIndex, deserializePayloadV2, detectRuntime, extractVectorFieldsFromSchema, fanOutQuery, flattenSchema, fnv1a, getLanguage, getNestedValue, getNormalizationCacheSize, isNodeMainThread, kWayMerge, mergePartitionStats, registerLanguage, resetNormalizationCache, spawnNodeWorker, tokenize, validateRequiredFields, validateSchema, validateVectorPromotion };
|
|
5979
|
+
export { MAX_NESTING_DEPTH, clearNormalizationCache, configureNormalizationCache, createDirectExecutor, createPartitionIndex, createPartitionManager, createPartitionRouter, createVectorIndex, deserializeMetadata, deserializePayloadV1, deserializePayloadV2, detectRuntime, extractVectorFieldsFromSchema, fanOutQuery, flattenSchema, fnv1a, getLanguage, getNestedValue, getNormalizationCacheSize, isNodeMainThread, kWayMerge, mergePartitionStats, registerLanguage, resetNormalizationCache, serializeMetadata, spawnNodeWorker, tokenize, validateRequiredFields, validateSchema, validateVectorPromotion };
|