@delali/narsil 0.3.1-next.72 → 0.3.1-next.74
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 +2 -2
- package/dist/adapters/filesystem.mjs +1 -1
- package/dist/adapters/indexeddb.mjs +1 -1
- package/dist/{capabilities-D6gjjQyA.d.ts → capabilities-CAMzmkAg.d.ts} +19 -4
- package/dist/{chunk-P2ZZN32C.mjs → chunk-2E35UM3G.mjs} +2 -12
- package/dist/chunk-3DDUNI6N.mjs +48 -0
- package/dist/{chunk-KZTI25D3.mjs → chunk-4MQ5F4IL.mjs} +1 -1
- package/dist/{chunk-HVJYTKK7.mjs → chunk-BVBIQQKG.mjs} +947 -1327
- package/dist/{chunk-2X2ZQOAB.mjs → chunk-CTOSGRM7.mjs} +101 -21
- package/dist/{chunk-7QMTA7AA.mjs → chunk-CUZOX6CN.mjs} +7784 -4276
- package/dist/chunk-I23G3IZC.mjs +593 -0
- package/dist/{chunk-RV77FR2F.mjs → chunk-I64LXKO3.mjs} +0 -1
- package/dist/chunk-KEHK2O6P.mjs +13 -0
- package/dist/{chunk-CVPA5Q7R.mjs → chunk-LX4JERXI.mjs} +9 -6
- package/dist/{chunk-EDMCZLSJ.mjs → chunk-NOZUQM7J.mjs} +193 -13
- package/dist/{chunk-LCCL6EEH.mjs → chunk-PO53FV4Q.mjs} +93 -94
- package/dist/chunk-T5ZWEWVD.mjs +658 -0
- package/dist/{chunk-Y52WZWAU.mjs → chunk-TVFLHM7M.mjs} +4 -4
- package/dist/{chunk-QR4OKRVY.mjs → chunk-VKX2BPXD.mjs} +147 -642
- package/dist/{chunk-3HQPUCCT.mjs → chunk-XW25X6AU.mjs} +66 -237
- package/dist/{chunk-M6XF5HDE.mjs → chunk-Z3DQPOJQ.mjs} +127 -30
- package/dist/{client-C2TiW29y.d.ts → client-C-I70ArH.d.ts} +77 -26
- package/dist/client.d.ts +9 -9
- package/dist/client.mjs +44 -22
- package/dist/{config-BLguB-om.d.ts → config-C6Iw5rCX.d.ts} +11 -4
- package/dist/{config-C7Ip8Ife.d.ts → config-DJPH3IQB.d.ts} +11 -2
- package/dist/direct-executor-KFAGILJC.mjs +17 -0
- package/dist/distribution/coordinator/etcd.d.ts +29 -16
- package/dist/distribution/coordinator/etcd.mjs +162 -75
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution/transport/grpc.d.ts +2 -2
- package/dist/distribution/transport/grpc.mjs +22 -2
- package/dist/distribution/transport/in-memory.d.ts +2 -2
- package/dist/distribution/transport/in-memory.mjs +6 -3
- package/dist/distribution/transport/tcp.d.ts +2 -2
- package/dist/distribution/transport/tcp.mjs +40 -16
- package/dist/distribution.d.ts +9 -9
- package/dist/distribution.mjs +647 -366
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/{engine-Dm4446j1.d.ts → engine-B8eRPO7m.d.ts} +97 -188
- package/dist/index.browser.mjs +12132 -8592
- package/dist/index.d.ts +27 -8
- package/dist/index.mjs +15 -14
- package/dist/{memory-CKHTU1CL.d.ts → memory-DJEwWoCi.d.ts} +1204 -968
- package/dist/partial-words-DTIHO8G4.d.ts +19 -0
- package/dist/partial-words.d.ts +22 -0
- package/dist/partial-words.mjs +11 -0
- package/dist/pattern.mjs +1 -1
- package/dist/persistence/durability/checkpoint-worker.d.ts +57 -29
- package/dist/persistence/durability/checkpoint-worker.mjs +26 -16
- package/dist/react.d.ts +7 -7
- package/dist/react.mjs +0 -1
- package/dist/{schema-BBOCdhND.d.ts → schema-DgyDijhf.d.ts} +6 -2
- package/dist/server.d.ts +11 -11
- package/dist/server.mjs +212 -32
- package/dist/{tasks-BECd0b__.d.ts → tasks-BVmAKYBh.d.ts} +3 -3
- package/dist/{thread-IBSIZZ6W.mjs → thread-W6DPKEF6.mjs} +82 -21
- package/dist/{types-BQDlIvfS.d.ts → types-B3b68nfF.d.ts} +1 -1
- package/dist/{types-D5OwhtsQ.d.ts → types-Cb9kiY5P.d.ts} +1 -1
- package/dist/{types-BiUmaiWT.d.ts → types-ChrVy4lH.d.ts} +1 -1
- package/dist/vector/search-worker.d.ts +1 -1
- package/dist/vector/search-worker.mjs +4 -3
- package/dist/workers/entry.mjs +4 -4
- package/package.json +15 -7
- package/dist/chunk-3L4U6EJQ.mjs +0 -49
- package/dist/chunk-IFBKLBGB.mjs +0 -7
- package/dist/chunk-XZ4PAREY.mjs +0 -25
- package/dist/direct-executor-SVCHXR74.mjs +0 -14
- package/dist/serialization/crc32-worker.d.ts +0 -20
- package/dist/serialization/crc32-worker.mjs +0 -62
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getLanguage, detectRuntime } from './chunk-
|
|
3
|
-
import {
|
|
4
|
-
import { SCRATCH_SLOTS_PER_THREAD_POOL, osqRecordBytes, openSharedVectorField, osqBitsOf, createVectorStore, DISK_STORAGE_BLOCK_BYTES, createOsqQuantizer, magnitude, createHNSWIndex, nativeStoreScratchBytes, createOrdinalFilter, isTombstoned, addToOrdinalFilter, ordinalFilterValues, nativeScoresOf, toScore, removeFromOrdinalFilter, euclideanDistance, dotProduct, cosineSimilarityWithMagnitudes, ordinalFilterHas,
|
|
5
|
-
import { noteFallback } from './chunk-
|
|
6
|
-
import {
|
|
7
|
-
import { GrowableUint32, patternSearchModule } from './chunk-3HQPUCCT.mjs';
|
|
1
|
+
import { joinPatternWorkMeter, countsWithoutScores, fanOutMatchCount, fanOutQuery, sanitizeGlobalStats, computeFacets, cloneProjected, projectionKeepsField, setNestedValue, fnv1a, everyValueFacetConfig, mergeFacets, undeclaredFilterField, requireValidOperands, kWayMerge, polygonContainment, polygonBoxes, radiusBoxes, locationCode, coveringRanges, GEO_UNIT_METRES } from './chunk-VKX2BPXD.mjs';
|
|
2
|
+
import { getLanguage, detectRuntime } from './chunk-4MQ5F4IL.mjs';
|
|
3
|
+
import { MAX_DOC_ID_LENGTH } from './chunk-3DDUNI6N.mjs';
|
|
4
|
+
import { SCRATCH_SLOTS_PER_THREAD_POOL, osqRecordBytes, openSharedVectorField, osqBitsOf, createVectorStore, DISK_STORAGE_BLOCK_BYTES, createOsqQuantizer, magnitude, createHNSWIndex, nativeStoreScratchBytes, createOrdinalFilter, isTombstoned, addToOrdinalFilter, ordinalFilterValues, nativeScoresOf, toScore, removeFromOrdinalFilter, euclideanDistance, dotProduct, cosineSimilarityWithMagnitudes, ordinalFilterHas, STORE_CALIBRATION_GENERATION, entryForOrd, toDistance, sharedMemoryAvailable, requireWholeNeighbourLists, topLayerInParts, GRAPH_BUILD_CHUNKS_IN_FLIGHT_PER_WORKER, GRAPH_BUILD_DISPATCH_CHUNK, releaseLocksHeldBy, VECTOR_SEARCH_TIMEOUT_MS, VECTOR_SEARCH_LOAD_TIMEOUT_MS, VECTOR_INSERT_TIMEOUT_MS, VECTOR_SCRATCH_SLOTS } from './chunk-PO53FV4Q.mjs';
|
|
5
|
+
import { noteFallback } from './chunk-2E35UM3G.mjs';
|
|
6
|
+
import { GrowableUint32, patternSearchModule } from './chunk-XW25X6AU.mjs';
|
|
8
7
|
import { bitsetHas, createBitSet, bitsetSet, bitsetOrInto, bitsetAndNotInto, bitsetAndInto, PATTERN_RUN_CODE_POINTS, bitsetFromSet, bitsetIsEmpty, bitsetAnd, bitsetNot } from './chunk-ZKRV5M2P.mjs';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { encodePartialSpellings, countSpelling, expandTermPrefix, suggestDisplayTerms, spellingCountsOf, codePointOrder, encodeStringBlob, partialWordSearchModule, partitionDocumentFrequency } from './chunk-T5ZWEWVD.mjs';
|
|
9
|
+
import { tokenizeOptions, getNestedValue, visitTokens, textFieldsChanged, fuzzyPrefixOf, boundedLevenshtein, getFlatSchema, tokenize, getOrCreateFieldNameIndex, tokenizeIterator, getFieldValueByInternalId } from './chunk-I23G3IZC.mjs';
|
|
10
|
+
import { schemaFieldsOf, partialFieldsOf, isWordIndexedBase, validateDocument, validateDocumentStrict, encodeDocument, extractVectorFieldsFromSchema, parsedTypeOf, isListBase, VINCENTY_CONVERGENCE_THRESHOLD, EARTH_RADIUS_METERS, VINCENTY_MAX_ITERATIONS, DEG_TO_RAD } from './chunk-Z3DQPOJQ.mjs';
|
|
11
|
+
import { MAX_M, EARLIER_RELEASE_MIN_M, MIN_M } from './chunk-KEHK2O6P.mjs';
|
|
12
|
+
import { compareCodePoints, appendFoldedCodePoint, toReducedSortValue, readSortField, defaultSortMode, compareComparableValues, truncateSortString, SORT_VALUE_MAX_CODE_POINTS } from './chunk-LJYTW7GT.mjs';
|
|
13
|
+
import { NarsilError, ErrorCodes } from './chunk-I64LXKO3.mjs';
|
|
11
14
|
import { totalmem } from 'os';
|
|
12
15
|
import { getHeapStatistics } from 'v8';
|
|
13
|
-
import {
|
|
16
|
+
import { decode } from '@msgpack/msgpack';
|
|
14
17
|
|
|
15
18
|
var MEGABYTE_BYTES = 1048576;
|
|
16
19
|
var IN_MEGABYTES = /^--max-old-space-size=(\d+)$/;
|
|
@@ -118,518 +121,6 @@ function resolveIndexAnalysis(config) {
|
|
|
118
121
|
customTokenizer: typeof config.tokenizer === "string" ? getTokenizer(config.tokenizer) : config.tokenizer
|
|
119
122
|
};
|
|
120
123
|
}
|
|
121
|
-
function metadataToWire(meta) {
|
|
122
|
-
const wire = {
|
|
123
|
-
index_name: meta.indexName,
|
|
124
|
-
schema: meta.schema,
|
|
125
|
-
language: meta.language,
|
|
126
|
-
partition_count: meta.partitionCount,
|
|
127
|
-
bm25_params: meta.bm25Params,
|
|
128
|
-
created_at: meta.createdAt,
|
|
129
|
-
engine_version: meta.engineVersion
|
|
130
|
-
};
|
|
131
|
-
if (meta.vectorFields) {
|
|
132
|
-
wire.vector_fields = meta.vectorFields;
|
|
133
|
-
}
|
|
134
|
-
if (isNonNegativeInteger(meta.documentCount) && Number.isSafeInteger(meta.documentCount)) {
|
|
135
|
-
wire.document_count = meta.documentCount;
|
|
136
|
-
}
|
|
137
|
-
if (meta.embedding) {
|
|
138
|
-
wire.embedding = meta.embedding.adapter !== void 0 ? { adapter: meta.embedding.adapter, fields: meta.embedding.fields } : { fields: meta.embedding.fields };
|
|
139
|
-
}
|
|
140
|
-
if (meta.surfaceForms !== void 0) {
|
|
141
|
-
wire.surface_forms_enabled = meta.surfaceForms;
|
|
142
|
-
}
|
|
143
|
-
if (meta.analysisRevision !== void 0) {
|
|
144
|
-
wire.analysis_revision = meta.analysisRevision;
|
|
145
|
-
}
|
|
146
|
-
if (meta.tokenizer !== void 0) {
|
|
147
|
-
wire.tokenizer = meta.tokenizer;
|
|
148
|
-
}
|
|
149
|
-
if (meta.stopWords !== void 0) {
|
|
150
|
-
wire.stop_words = meta.stopWords;
|
|
151
|
-
}
|
|
152
|
-
if (meta.stopWordList !== void 0) {
|
|
153
|
-
wire.stop_word_list = meta.stopWordList;
|
|
154
|
-
}
|
|
155
|
-
if (meta.partitionLimits !== void 0) {
|
|
156
|
-
wire.partition_limits = {
|
|
157
|
-
...meta.partitionLimits.maxDocsPerPartition !== void 0 ? { max_docs_per_partition: meta.partitionLimits.maxDocsPerPartition } : {},
|
|
158
|
-
...meta.partitionLimits.maxPartitions !== void 0 ? { max_partitions: meta.partitionLimits.maxPartitions } : {},
|
|
159
|
-
...meta.partitionLimits.watermark !== void 0 ? { watermark: meta.partitionLimits.watermark } : {}
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
if (meta.defaultScoring !== void 0) {
|
|
163
|
-
wire.default_scoring = meta.defaultScoring;
|
|
164
|
-
}
|
|
165
|
-
if (meta.trackPositions !== void 0) {
|
|
166
|
-
wire.track_positions = meta.trackPositions;
|
|
167
|
-
}
|
|
168
|
-
if (meta.strict !== void 0) {
|
|
169
|
-
wire.strict = meta.strict;
|
|
170
|
-
}
|
|
171
|
-
if (meta.required !== void 0) {
|
|
172
|
-
wire.required = meta.required;
|
|
173
|
-
}
|
|
174
|
-
if (meta.vectorPromotion !== void 0) {
|
|
175
|
-
const promotion = meta.vectorPromotion;
|
|
176
|
-
wire.vector_promotion = {
|
|
177
|
-
...promotion.threshold !== void 0 ? { threshold: promotion.threshold } : {},
|
|
178
|
-
...promotion.filterThreshold !== void 0 ? { filter_threshold: promotion.filterThreshold } : {},
|
|
179
|
-
...promotion.hnswConfig !== void 0 ? {
|
|
180
|
-
hnsw_config: {
|
|
181
|
-
...promotion.hnswConfig.m !== void 0 ? { m: promotion.hnswConfig.m } : {},
|
|
182
|
-
...promotion.hnswConfig.efConstruction !== void 0 ? { ef_construction: promotion.hnswConfig.efConstruction } : {},
|
|
183
|
-
...promotion.hnswConfig.metric !== void 0 ? { metric: promotion.hnswConfig.metric } : {}
|
|
184
|
-
}
|
|
185
|
-
} : {},
|
|
186
|
-
...promotion.quantization !== void 0 ? { quantization: promotion.quantization } : {},
|
|
187
|
-
...promotion.storage !== void 0 ? { storage: promotion.storage } : {}
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
if (meta.patternValueLimit !== void 0) {
|
|
191
|
-
wire.pattern_value_limit = meta.patternValueLimit;
|
|
192
|
-
}
|
|
193
|
-
if (meta.indexUuid !== void 0) {
|
|
194
|
-
wire.index_uuid = meta.indexUuid;
|
|
195
|
-
}
|
|
196
|
-
if (meta.heldPartitions !== void 0) {
|
|
197
|
-
wire.held_partitions = meta.heldPartitions;
|
|
198
|
-
}
|
|
199
|
-
return wire;
|
|
200
|
-
}
|
|
201
|
-
function wireToMetadata(raw) {
|
|
202
|
-
const meta = {
|
|
203
|
-
indexName: raw.index_name,
|
|
204
|
-
schema: raw.schema ?? {},
|
|
205
|
-
language: raw.language ?? "english",
|
|
206
|
-
partitionCount: raw.partition_count ?? 1,
|
|
207
|
-
bm25Params: raw.bm25_params ?? { k1: 1.2, b: 0.75 },
|
|
208
|
-
createdAt: raw.created_at ?? 0,
|
|
209
|
-
engineVersion: raw.engine_version ?? "0.0.0"
|
|
210
|
-
};
|
|
211
|
-
if (raw.vector_fields) {
|
|
212
|
-
for (const [fieldPath, field] of Object.entries(raw.vector_fields)) {
|
|
213
|
-
if (!isQuantizationMode(field.quantization)) {
|
|
214
|
-
throw new NarsilError(
|
|
215
|
-
ErrorCodes.CONFIG_INVALID,
|
|
216
|
-
`Index metadata names a vector quantization "${String(field.quantization)}" for "${fieldPath}" this engine does not read`,
|
|
217
|
-
{ fieldPath, quantization: field.quantization }
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
meta.vectorFields = raw.vector_fields;
|
|
222
|
-
}
|
|
223
|
-
if (isNonNegativeInteger(raw.document_count) && Number.isSafeInteger(raw.document_count)) {
|
|
224
|
-
meta.documentCount = raw.document_count;
|
|
225
|
-
}
|
|
226
|
-
if (raw.embedding && typeof raw.embedding === "object" && typeof raw.embedding.fields === "object") {
|
|
227
|
-
meta.embedding = typeof raw.embedding.adapter === "string" ? { adapter: raw.embedding.adapter, fields: raw.embedding.fields } : { fields: raw.embedding.fields };
|
|
228
|
-
}
|
|
229
|
-
if (typeof raw.surface_forms_enabled === "boolean") {
|
|
230
|
-
meta.surfaceForms = raw.surface_forms_enabled;
|
|
231
|
-
}
|
|
232
|
-
if (typeof raw.analysis_revision === "string") {
|
|
233
|
-
meta.analysisRevision = raw.analysis_revision;
|
|
234
|
-
}
|
|
235
|
-
if (typeof raw.tokenizer === "string") {
|
|
236
|
-
meta.tokenizer = raw.tokenizer;
|
|
237
|
-
}
|
|
238
|
-
if (typeof raw.stop_words === "string") {
|
|
239
|
-
meta.stopWords = raw.stop_words;
|
|
240
|
-
}
|
|
241
|
-
if (Array.isArray(raw.stop_word_list) && raw.stop_word_list.every((word) => typeof word === "string")) {
|
|
242
|
-
meta.stopWordList = raw.stop_word_list;
|
|
243
|
-
}
|
|
244
|
-
if (raw.partition_limits && typeof raw.partition_limits === "object") {
|
|
245
|
-
const limits = {
|
|
246
|
-
...isPositiveInteger(raw.partition_limits.max_docs_per_partition) ? { maxDocsPerPartition: raw.partition_limits.max_docs_per_partition } : {},
|
|
247
|
-
...isPositiveInteger(raw.partition_limits.max_partitions) ? { maxPartitions: raw.partition_limits.max_partitions } : {},
|
|
248
|
-
...isWatermarkFraction(raw.partition_limits.watermark) ? { watermark: raw.partition_limits.watermark } : {}
|
|
249
|
-
};
|
|
250
|
-
if (Object.keys(limits).length > 0) {
|
|
251
|
-
meta.partitionLimits = limits;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
if (raw.default_scoring === "local" || raw.default_scoring === "dfs" || raw.default_scoring === "broadcast") {
|
|
255
|
-
meta.defaultScoring = raw.default_scoring;
|
|
256
|
-
}
|
|
257
|
-
if (typeof raw.track_positions === "boolean") {
|
|
258
|
-
meta.trackPositions = raw.track_positions;
|
|
259
|
-
}
|
|
260
|
-
if (typeof raw.strict === "boolean") {
|
|
261
|
-
meta.strict = raw.strict;
|
|
262
|
-
}
|
|
263
|
-
if (Array.isArray(raw.required) && raw.required.every((field) => typeof field === "string")) {
|
|
264
|
-
meta.required = raw.required;
|
|
265
|
-
}
|
|
266
|
-
if (raw.vector_promotion && typeof raw.vector_promotion === "object") {
|
|
267
|
-
const promotion = raw.vector_promotion;
|
|
268
|
-
const hnsw = promotion.hnsw_config && typeof promotion.hnsw_config === "object" ? promotion.hnsw_config : void 0;
|
|
269
|
-
const metric = hnsw?.metric;
|
|
270
|
-
const restored = {};
|
|
271
|
-
const hnswConfig = {};
|
|
272
|
-
if (isPositiveInteger(hnsw?.m)) {
|
|
273
|
-
hnswConfig.m = hnsw?.m;
|
|
274
|
-
}
|
|
275
|
-
if (isPositiveInteger(hnsw?.ef_construction)) {
|
|
276
|
-
hnswConfig.efConstruction = hnsw?.ef_construction;
|
|
277
|
-
}
|
|
278
|
-
if (metric === "cosine" || metric === "dotProduct" || metric === "euclidean") {
|
|
279
|
-
hnswConfig.metric = metric;
|
|
280
|
-
}
|
|
281
|
-
if (isPositiveInteger(promotion.threshold)) {
|
|
282
|
-
restored.threshold = promotion.threshold;
|
|
283
|
-
}
|
|
284
|
-
if (isSelectivityRatio(promotion.filter_threshold)) {
|
|
285
|
-
restored.filterThreshold = promotion.filter_threshold;
|
|
286
|
-
}
|
|
287
|
-
if (Object.keys(hnswConfig).length > 0) {
|
|
288
|
-
restored.hnswConfig = hnswConfig;
|
|
289
|
-
}
|
|
290
|
-
if (promotion.quantization !== void 0) {
|
|
291
|
-
if (!isQuantizationMode(promotion.quantization)) {
|
|
292
|
-
throw new NarsilError(
|
|
293
|
-
ErrorCodes.CONFIG_INVALID,
|
|
294
|
-
`Index metadata names a vector quantization "${String(promotion.quantization)}" this engine does not read`,
|
|
295
|
-
{ quantization: promotion.quantization }
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
restored.quantization = promotion.quantization;
|
|
299
|
-
}
|
|
300
|
-
if (promotion.storage !== void 0) {
|
|
301
|
-
if (!isStorageMode(promotion.storage)) {
|
|
302
|
-
throw new NarsilError(
|
|
303
|
-
ErrorCodes.CONFIG_INVALID,
|
|
304
|
-
`Index metadata names a vector storage "${String(promotion.storage)}" this engine does not read`,
|
|
305
|
-
{ storage: promotion.storage }
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
restored.storage = promotion.storage;
|
|
309
|
-
}
|
|
310
|
-
if (Object.keys(restored).length > 0) {
|
|
311
|
-
meta.vectorPromotion = restored;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
if (raw.pattern_value_limit !== void 0) {
|
|
315
|
-
if (!isPositiveInteger(raw.pattern_value_limit)) {
|
|
316
|
-
throw new NarsilError(
|
|
317
|
-
ErrorCodes.CONFIG_INVALID,
|
|
318
|
-
`The pattern value limit in the index metadata is ${String(raw.pattern_value_limit)}, but the limit must be a whole number of code points`,
|
|
319
|
-
{ patternValueLimit: String(raw.pattern_value_limit) }
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
meta.patternValueLimit = raw.pattern_value_limit;
|
|
323
|
-
}
|
|
324
|
-
if (typeof raw.index_uuid === "string" && raw.index_uuid.length > 0) {
|
|
325
|
-
meta.indexUuid = raw.index_uuid;
|
|
326
|
-
}
|
|
327
|
-
if (Array.isArray(raw.held_partitions) && raw.held_partitions.every(isNonNegativeInteger)) {
|
|
328
|
-
meta.heldPartitions = raw.held_partitions;
|
|
329
|
-
}
|
|
330
|
-
return meta;
|
|
331
|
-
}
|
|
332
|
-
function isNonNegativeInteger(value) {
|
|
333
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
334
|
-
}
|
|
335
|
-
function isPositiveInteger(value) {
|
|
336
|
-
return typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
337
|
-
}
|
|
338
|
-
function isSelectivityRatio(value) {
|
|
339
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
|
|
340
|
-
}
|
|
341
|
-
function isWatermarkFraction(value) {
|
|
342
|
-
return typeof value === "number" && value > 0 && value <= 1;
|
|
343
|
-
}
|
|
344
|
-
function serializeMetadata(meta) {
|
|
345
|
-
const wire = metadataToWire(meta);
|
|
346
|
-
return encode(wire);
|
|
347
|
-
}
|
|
348
|
-
function deserializeMetadata(data) {
|
|
349
|
-
const raw = decode(data);
|
|
350
|
-
return wireToMetadata(raw);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// src/serialization/stored-vector-values.ts
|
|
354
|
-
function dropStoredVectorValues(documents, schema) {
|
|
355
|
-
const vectorFieldPaths = [];
|
|
356
|
-
for (const [fieldPath, fieldType] of Object.entries(schema)) {
|
|
357
|
-
if (typeof fieldType === "string" && VECTOR_PATTERN.test(fieldType)) {
|
|
358
|
-
vectorFieldPaths.push(fieldPath);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
if (vectorFieldPaths.length === 0) {
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
for (const document of Object.values(documents)) {
|
|
365
|
-
for (const fieldPath of vectorFieldPaths) {
|
|
366
|
-
removeFieldAtPath(document.fields, fieldPath);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
function removeFieldAtPath(fields, fieldPath) {
|
|
371
|
-
if (!fieldPath.includes(".")) {
|
|
372
|
-
delete fields[fieldPath];
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
const segments = fieldPath.split(".");
|
|
376
|
-
let current = fields;
|
|
377
|
-
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
378
|
-
const next = current[segments[i]];
|
|
379
|
-
if (next === null || typeof next !== "object") {
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
current = next;
|
|
383
|
-
}
|
|
384
|
-
delete current[segments[segments.length - 1]];
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// src/serialization/payload-v1/partition.ts
|
|
388
|
-
function sanitizeSurfaceForms(raw) {
|
|
389
|
-
if (raw === void 0 || raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
390
|
-
const result = /* @__PURE__ */ Object.create(null);
|
|
391
|
-
let count = 0;
|
|
392
|
-
for (const [surface, value] of Object.entries(raw)) {
|
|
393
|
-
if (typeof value === "number") {
|
|
394
|
-
result[surface] = value;
|
|
395
|
-
count++;
|
|
396
|
-
} else if (Array.isArray(value) && typeof value[0] === "number" && typeof value[1] === "string") {
|
|
397
|
-
result[surface] = [value[0], value[1]];
|
|
398
|
-
count++;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
return count > 0 ? result : void 0;
|
|
402
|
-
}
|
|
403
|
-
function patternIndexesToWire(pattern) {
|
|
404
|
-
if (pattern === void 0) return {};
|
|
405
|
-
const wire = /* @__PURE__ */ Object.create(null);
|
|
406
|
-
for (const [field, index] of Object.entries(pattern)) wire[field] = { doc_ids: index.docIds, runs: index.runs };
|
|
407
|
-
return { pattern: wire };
|
|
408
|
-
}
|
|
409
|
-
function isWireRecord(value) {
|
|
410
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
411
|
-
}
|
|
412
|
-
function corruptPatternEntry(field) {
|
|
413
|
-
return new NarsilError(
|
|
414
|
-
ErrorCodes.PERSISTENCE_LOAD_FAILED,
|
|
415
|
-
`The pattern entry of field "${field}" in this partition must hold a list of document IDs and a map of runs`,
|
|
416
|
-
{ field }
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
function patternIndexesFromWire(raw) {
|
|
420
|
-
if (raw === void 0 || raw === null) return {};
|
|
421
|
-
if (!isWireRecord(raw)) {
|
|
422
|
-
throw new NarsilError(
|
|
423
|
-
ErrorCodes.PERSISTENCE_LOAD_FAILED,
|
|
424
|
-
"The pattern entry of this partition must be a map of fields"
|
|
425
|
-
);
|
|
426
|
-
}
|
|
427
|
-
const pattern = /* @__PURE__ */ Object.create(null);
|
|
428
|
-
for (const [field, index] of Object.entries(raw)) {
|
|
429
|
-
if (!isWireRecord(index) || !isWireRecord(index.runs) || !Array.isArray(index.doc_ids)) {
|
|
430
|
-
throw corruptPatternEntry(field);
|
|
431
|
-
}
|
|
432
|
-
const docIds = [];
|
|
433
|
-
for (const docId of index.doc_ids) {
|
|
434
|
-
if (typeof docId !== "string") throw corruptPatternEntry(field);
|
|
435
|
-
docIds.push(docId);
|
|
436
|
-
}
|
|
437
|
-
pattern[field] = { docIds, runs: index.runs };
|
|
438
|
-
}
|
|
439
|
-
return { pattern };
|
|
440
|
-
}
|
|
441
|
-
function validateHnswMetric(value) {
|
|
442
|
-
if (value === void 0 || value === null) return void 0;
|
|
443
|
-
if (typeof value === "string" && VALID_HNSW_METRICS.has(value)) {
|
|
444
|
-
return value;
|
|
445
|
-
}
|
|
446
|
-
return void 0;
|
|
447
|
-
}
|
|
448
|
-
function wireToPartition(raw) {
|
|
449
|
-
const documents = {};
|
|
450
|
-
for (const [docId, doc] of Object.entries(raw.documents ?? {})) {
|
|
451
|
-
documents[docId] = {
|
|
452
|
-
fields: doc.fields,
|
|
453
|
-
fieldLengths: doc.field_lengths ?? {}
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
requireValidFieldTypes(raw.schema ?? {});
|
|
457
|
-
dropStoredVectorValues(documents, raw.schema ?? {});
|
|
458
|
-
const invertedIndex = {};
|
|
459
|
-
for (const [token, list] of Object.entries(raw.inverted_index ?? {})) {
|
|
460
|
-
invertedIndex[token] = {
|
|
461
|
-
docFrequency: list.doc_freq,
|
|
462
|
-
postings: (list.postings ?? []).map((p) => ({
|
|
463
|
-
docId: p.doc_id,
|
|
464
|
-
termFrequency: p.term_freq,
|
|
465
|
-
field: p.field,
|
|
466
|
-
positions: p.positions ?? []
|
|
467
|
-
}))
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
const numeric = {};
|
|
471
|
-
for (const [field, entries] of Object.entries(raw.field_indexes?.numeric ?? {})) {
|
|
472
|
-
numeric[field] = entries.map((e) => ({ value: e.value, docId: e.doc_id }));
|
|
473
|
-
}
|
|
474
|
-
const boolean = {};
|
|
475
|
-
for (const [field, idx] of Object.entries(raw.field_indexes?.boolean ?? {})) {
|
|
476
|
-
boolean[field] = { trueDocs: idx.true_docs ?? [], falseDocs: idx.false_docs ?? [] };
|
|
477
|
-
}
|
|
478
|
-
const geopoint = {};
|
|
479
|
-
for (const [field, entries] of Object.entries(raw.field_indexes?.geopoint ?? {})) {
|
|
480
|
-
geopoint[field] = entries.map((e) => ({ lat: e.lat, lon: e.lon, docId: e.doc_id }));
|
|
481
|
-
}
|
|
482
|
-
const vectorData = {};
|
|
483
|
-
for (const [field, data] of Object.entries(raw.vector_data ?? {})) {
|
|
484
|
-
vectorData[field] = {
|
|
485
|
-
dimension: data.dimension,
|
|
486
|
-
vectors: (data.vectors ?? []).map((v) => ({ docId: v.doc_id, vector: v.vector })),
|
|
487
|
-
hnswGraph: data.hnsw_graph ? {
|
|
488
|
-
entryPoint: data.hnsw_graph.entry_point,
|
|
489
|
-
maxLayer: data.hnsw_graph.max_layer,
|
|
490
|
-
m: data.hnsw_graph.m,
|
|
491
|
-
efConstruction: data.hnsw_graph.ef_construction,
|
|
492
|
-
metric: validateHnswMetric(data.hnsw_graph.metric),
|
|
493
|
-
nodes: data.hnsw_graph.nodes
|
|
494
|
-
} : null,
|
|
495
|
-
codes: data.codes ? { bits: data.codes.bits, centroid: data.codes.centroid, records: data.codes.records } : null
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
return {
|
|
499
|
-
indexName: raw.index_name,
|
|
500
|
-
partitionId: raw.partition_id,
|
|
501
|
-
totalPartitions: raw.total_partitions,
|
|
502
|
-
language: raw.language ?? "english",
|
|
503
|
-
schema: raw.schema ?? {},
|
|
504
|
-
docCount: raw.doc_count ?? 0,
|
|
505
|
-
avgDocLength: raw.avg_doc_length ?? 0,
|
|
506
|
-
documents,
|
|
507
|
-
invertedIndex,
|
|
508
|
-
fieldIndexes: {
|
|
509
|
-
numeric,
|
|
510
|
-
boolean,
|
|
511
|
-
enum: raw.field_indexes?.enum ?? {},
|
|
512
|
-
geopoint,
|
|
513
|
-
...patternIndexesFromWire(raw.field_indexes?.pattern)
|
|
514
|
-
},
|
|
515
|
-
surfaceForms: sanitizeSurfaceForms(raw.surface_forms),
|
|
516
|
-
vectorData,
|
|
517
|
-
statistics: {
|
|
518
|
-
totalDocuments: raw.statistics?.total_documents ?? 0,
|
|
519
|
-
totalFieldLengths: raw.statistics?.total_field_lengths ?? {},
|
|
520
|
-
averageFieldLengths: raw.statistics?.average_field_lengths ?? {},
|
|
521
|
-
docFrequencies: raw.statistics?.doc_frequencies ?? {}
|
|
522
|
-
}
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
function deserializePayloadV1(data) {
|
|
526
|
-
const raw = decode(data);
|
|
527
|
-
return wireToPartition(raw);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// src/serialization/payload-v2.ts
|
|
531
|
-
function encodeRawPayloadV2(wire) {
|
|
532
|
-
return encode(wire);
|
|
533
|
-
}
|
|
534
|
-
function validateHnswMetric2(value) {
|
|
535
|
-
if (value === void 0 || value === null) return void 0;
|
|
536
|
-
if (typeof value === "string" && VALID_HNSW_METRICS.has(value)) {
|
|
537
|
-
return value;
|
|
538
|
-
}
|
|
539
|
-
return void 0;
|
|
540
|
-
}
|
|
541
|
-
function storedDocumentsOf(raw) {
|
|
542
|
-
requireValidFieldTypes(raw.schema ?? {});
|
|
543
|
-
const documents = {};
|
|
544
|
-
for (const [docId, doc] of Object.entries(raw.documents ?? {})) {
|
|
545
|
-
documents[docId] = {
|
|
546
|
-
fields: doc.fields,
|
|
547
|
-
fieldLengths: doc.field_lengths ?? {}
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
dropStoredVectorValues(documents, raw.schema ?? {});
|
|
551
|
-
return documents;
|
|
552
|
-
}
|
|
553
|
-
function documentsOfPayloadV2(data) {
|
|
554
|
-
const raw = decode(data);
|
|
555
|
-
return { documents: storedDocumentsOf(raw), schema: raw.schema ?? {} };
|
|
556
|
-
}
|
|
557
|
-
function deserializePayloadV2(data) {
|
|
558
|
-
const raw = decode(data);
|
|
559
|
-
const documents = storedDocumentsOf(raw);
|
|
560
|
-
const fieldNames = raw.inverted_index?.field_names ?? [];
|
|
561
|
-
const invertedIndex = {};
|
|
562
|
-
for (const [token, list] of Object.entries(raw.inverted_index?.entries ?? {})) {
|
|
563
|
-
const count = list.ids.length;
|
|
564
|
-
const postings = new Array(count);
|
|
565
|
-
for (let i = 0; i < count; i++) {
|
|
566
|
-
postings[i] = {
|
|
567
|
-
docId: list.ids[i],
|
|
568
|
-
termFrequency: list.tf[i],
|
|
569
|
-
field: fieldNames[list.fi[i]] ?? "",
|
|
570
|
-
positions: list.pos ? list.pos[i] : []
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
invertedIndex[token] = {
|
|
574
|
-
docFrequency: list.df,
|
|
575
|
-
postings
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
const numeric = {};
|
|
579
|
-
for (const [field, entries] of Object.entries(raw.field_indexes?.numeric ?? {})) {
|
|
580
|
-
numeric[field] = entries.map((e) => ({ value: e.value, docId: e.doc_id }));
|
|
581
|
-
}
|
|
582
|
-
const boolean = {};
|
|
583
|
-
for (const [field, idx] of Object.entries(raw.field_indexes?.boolean ?? {})) {
|
|
584
|
-
boolean[field] = { trueDocs: idx.true_docs ?? [], falseDocs: idx.false_docs ?? [] };
|
|
585
|
-
}
|
|
586
|
-
const geopoint = {};
|
|
587
|
-
for (const [field, entries] of Object.entries(raw.field_indexes?.geopoint ?? {})) {
|
|
588
|
-
geopoint[field] = entries.map((e) => ({ lat: e.lat, lon: e.lon, docId: e.doc_id }));
|
|
589
|
-
}
|
|
590
|
-
const vectorData = {};
|
|
591
|
-
for (const [field, data2] of Object.entries(raw.vector_data ?? {})) {
|
|
592
|
-
vectorData[field] = {
|
|
593
|
-
dimension: data2.dimension,
|
|
594
|
-
vectors: (data2.vectors ?? []).map((v) => ({ docId: v.doc_id, vector: v.vector })),
|
|
595
|
-
hnswGraph: data2.hnsw_graph ? {
|
|
596
|
-
entryPoint: data2.hnsw_graph.entry_point,
|
|
597
|
-
maxLayer: data2.hnsw_graph.max_layer,
|
|
598
|
-
m: data2.hnsw_graph.m,
|
|
599
|
-
efConstruction: data2.hnsw_graph.ef_construction,
|
|
600
|
-
metric: validateHnswMetric2(data2.hnsw_graph.metric),
|
|
601
|
-
nodes: data2.hnsw_graph.nodes
|
|
602
|
-
} : null,
|
|
603
|
-
codes: data2.codes ? { bits: data2.codes.bits, centroid: data2.codes.centroid, records: data2.codes.records } : null
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
return {
|
|
607
|
-
indexName: raw.index_name,
|
|
608
|
-
partitionId: raw.partition_id,
|
|
609
|
-
totalPartitions: raw.total_partitions,
|
|
610
|
-
language: raw.language ?? "english",
|
|
611
|
-
schema: raw.schema ?? {},
|
|
612
|
-
docCount: raw.doc_count ?? 0,
|
|
613
|
-
avgDocLength: raw.avg_doc_length ?? 0,
|
|
614
|
-
documents,
|
|
615
|
-
invertedIndex,
|
|
616
|
-
fieldIndexes: {
|
|
617
|
-
numeric,
|
|
618
|
-
boolean,
|
|
619
|
-
enum: raw.field_indexes?.enum ?? {},
|
|
620
|
-
geopoint,
|
|
621
|
-
...patternIndexesFromWire(raw.field_indexes?.pattern)
|
|
622
|
-
},
|
|
623
|
-
surfaceForms: sanitizeSurfaceForms(raw.surface_forms),
|
|
624
|
-
vectorData,
|
|
625
|
-
statistics: {
|
|
626
|
-
totalDocuments: raw.statistics?.total_documents ?? 0,
|
|
627
|
-
totalFieldLengths: raw.statistics?.total_field_lengths ?? {},
|
|
628
|
-
averageFieldLengths: raw.statistics?.average_field_lengths ?? {},
|
|
629
|
-
docFrequencies: raw.statistics?.doc_frequencies ?? {}
|
|
630
|
-
}
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
124
|
|
|
634
125
|
// src/core/document-store.ts
|
|
635
126
|
function detachedView(view) {
|
|
@@ -889,7 +380,7 @@ function createPostingList() {
|
|
|
889
380
|
length: 0,
|
|
890
381
|
docIds: [],
|
|
891
382
|
termFrequencies: new Uint16Array(POSTING_LIST_INITIAL_CAPACITY),
|
|
892
|
-
fieldNameIndices: new
|
|
383
|
+
fieldNameIndices: new Uint16Array(POSTING_LIST_INITIAL_CAPACITY),
|
|
893
384
|
positions: null,
|
|
894
385
|
docIdSet: /* @__PURE__ */ new Set(),
|
|
895
386
|
deletedDocs: /* @__PURE__ */ new Set(),
|
|
@@ -903,7 +394,7 @@ function growTypedArrays(list) {
|
|
|
903
394
|
const newTF = new Uint16Array(newCap);
|
|
904
395
|
newTF.set(list.termFrequencies);
|
|
905
396
|
list.termFrequencies = newTF;
|
|
906
|
-
const newFNI = new
|
|
397
|
+
const newFNI = new Uint16Array(newCap);
|
|
907
398
|
newFNI.set(list.fieldNameIndices);
|
|
908
399
|
list.fieldNameIndices = newFNI;
|
|
909
400
|
}
|
|
@@ -924,8 +415,6 @@ function compactList(list) {
|
|
|
924
415
|
}
|
|
925
416
|
}
|
|
926
417
|
writeIdx++;
|
|
927
|
-
} else {
|
|
928
|
-
list.totalTermFrequency -= list.termFrequencies[i];
|
|
929
418
|
}
|
|
930
419
|
}
|
|
931
420
|
list.docIds.length = writeIdx;
|
|
@@ -950,8 +439,6 @@ function compactDocEntries(list, internalId) {
|
|
|
950
439
|
}
|
|
951
440
|
}
|
|
952
441
|
writeIdx++;
|
|
953
|
-
} else {
|
|
954
|
-
list.totalTermFrequency -= list.termFrequencies[i];
|
|
955
442
|
}
|
|
956
443
|
}
|
|
957
444
|
list.docIds.length = writeIdx;
|
|
@@ -1037,12 +524,13 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1037
524
|
}
|
|
1038
525
|
list.length++;
|
|
1039
526
|
},
|
|
1040
|
-
remove(token, internalId) {
|
|
527
|
+
remove(token, internalId, occurrences) {
|
|
1041
528
|
const list = index.get(token);
|
|
1042
529
|
if (!list || !list.docIdSet.has(internalId)) return;
|
|
1043
530
|
list.structureRevision++;
|
|
1044
531
|
list.docIdSet.delete(internalId);
|
|
1045
532
|
list.deletedDocs.add(internalId);
|
|
533
|
+
list.totalTermFrequency = Math.max(0, list.totalTermFrequency - occurrences);
|
|
1046
534
|
if (list.docIdSet.size === 0) {
|
|
1047
535
|
index.delete(token);
|
|
1048
536
|
untrackToken(token);
|
|
@@ -1075,6 +563,9 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1075
563
|
lookup(token) {
|
|
1076
564
|
return index.get(token);
|
|
1077
565
|
},
|
|
566
|
+
documentFrequency(token) {
|
|
567
|
+
return index.get(token)?.docIdSet.size ?? 0;
|
|
568
|
+
},
|
|
1078
569
|
fuzzyLookup(token, tolerance, prefixLength) {
|
|
1079
570
|
if (tolerance === 0) {
|
|
1080
571
|
const exact = index.get(token);
|
|
@@ -1148,7 +639,7 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1148
639
|
const docIdSet = /* @__PURE__ */ new Set();
|
|
1149
640
|
const docIds = new Array(count);
|
|
1150
641
|
const termFrequencies = new Uint16Array(count);
|
|
1151
|
-
const fieldNameIndices = new
|
|
642
|
+
const fieldNameIndices = new Uint16Array(count);
|
|
1152
643
|
let hasPositions = false;
|
|
1153
644
|
let validCount = 0;
|
|
1154
645
|
let totalTermFrequency = 0;
|
|
@@ -2180,6 +1671,13 @@ function resolveInternalId(state, docId) {
|
|
|
2180
1671
|
}
|
|
2181
1672
|
return internalId;
|
|
2182
1673
|
}
|
|
1674
|
+
function emptyIndexedText(fields) {
|
|
1675
|
+
const holdsPartialField = fields.some((field) => field.partial);
|
|
1676
|
+
return { fieldLengths: {}, tokensByField: {}, partialSpellings: holdsPartialField ? /* @__PURE__ */ new Map() : null };
|
|
1677
|
+
}
|
|
1678
|
+
function partialSpellingsFor(field, indexed) {
|
|
1679
|
+
return field.partial ? indexed.partialSpellings : null;
|
|
1680
|
+
}
|
|
2183
1681
|
function countSurface(counts, surface, token) {
|
|
2184
1682
|
if (surface === void 0 || surface.length === 0) return;
|
|
2185
1683
|
const existing = counts.get(surface);
|
|
@@ -2189,6 +1687,18 @@ function countSurface(counts, surface, token) {
|
|
|
2189
1687
|
counts.set(surface, { token, count: 1 });
|
|
2190
1688
|
}
|
|
2191
1689
|
}
|
|
1690
|
+
function countOccurrence(counts, spellings, surface, token) {
|
|
1691
|
+
countSurface(counts, surface, token);
|
|
1692
|
+
if (spellings !== null) countSpelling(spellings, token, surface ?? token, 1);
|
|
1693
|
+
}
|
|
1694
|
+
function addFieldOccurrences(occurrencesByToken, fieldTokens) {
|
|
1695
|
+
const fieldCounts = /* @__PURE__ */ new Map();
|
|
1696
|
+
for (const token of fieldTokens) fieldCounts.set(token, (fieldCounts.get(token) ?? 0) + 1);
|
|
1697
|
+
for (const [token, count] of fieldCounts) {
|
|
1698
|
+
const stored = count > MAX_TERM_FREQUENCY ? MAX_TERM_FREQUENCY : count;
|
|
1699
|
+
occurrencesByToken.set(token, (occurrencesByToken.get(token) ?? 0) + stored);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
2192
1702
|
function applySurfaceCounts(state, counts, direction) {
|
|
2193
1703
|
for (const [surface, entry] of counts) {
|
|
2194
1704
|
if (direction === 1) {
|
|
@@ -2198,7 +1708,7 @@ function applySurfaceCounts(state, counts, direction) {
|
|
|
2198
1708
|
}
|
|
2199
1709
|
}
|
|
2200
1710
|
}
|
|
2201
|
-
function indexStringField(state, internalId, fieldPath, text, language, options, fieldLengths, tokensByField) {
|
|
1711
|
+
function indexStringField(state, internalId, fieldPath, text, language, options, fieldLengths, tokensByField, spellings = null) {
|
|
2202
1712
|
const fieldTokenList = [];
|
|
2203
1713
|
const fieldNameIndex2 = getOrCreateFieldNameIndex(state.fieldNameTable, fieldPath);
|
|
2204
1714
|
const opts = tokenizeOptions(options);
|
|
@@ -2214,7 +1724,7 @@ function indexStringField(state, internalId, fieldPath, text, language, options,
|
|
|
2214
1724
|
tokenFreqs.set(t.token, { count: 1, positions: [t.position] });
|
|
2215
1725
|
}
|
|
2216
1726
|
fieldTokenList.push(t.token);
|
|
2217
|
-
|
|
1727
|
+
countOccurrence(surfaceCounts, spellings, t.surface, t.token);
|
|
2218
1728
|
}
|
|
2219
1729
|
for (const [token, freq] of tokenFreqs) {
|
|
2220
1730
|
state.invertedIdx.insert(token, internalId, freq.count, fieldNameIndex2, freq.positions);
|
|
@@ -2224,7 +1734,7 @@ function indexStringField(state, internalId, fieldPath, text, language, options,
|
|
|
2224
1734
|
for (const t of tokenizeIterator(text, language, opts)) {
|
|
2225
1735
|
tokenCounts.set(t.token, (tokenCounts.get(t.token) ?? 0) + 1);
|
|
2226
1736
|
fieldTokenList.push(t.token);
|
|
2227
|
-
|
|
1737
|
+
countOccurrence(surfaceCounts, spellings, t.surface, t.token);
|
|
2228
1738
|
}
|
|
2229
1739
|
for (const [token, count] of tokenCounts) {
|
|
2230
1740
|
state.invertedIdx.insert(token, internalId, count, fieldNameIndex2, null);
|
|
@@ -2234,7 +1744,7 @@ function indexStringField(state, internalId, fieldPath, text, language, options,
|
|
|
2234
1744
|
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2235
1745
|
tokensByField[fieldPath] = fieldTokenList;
|
|
2236
1746
|
}
|
|
2237
|
-
function indexStringArrayField(state, internalId, fieldPath, arr, language, options, fieldLengths, tokensByField) {
|
|
1747
|
+
function indexStringArrayField(state, internalId, fieldPath, arr, language, options, fieldLengths, tokensByField, spellings = null) {
|
|
2238
1748
|
const fieldTokenList = [];
|
|
2239
1749
|
const fieldNameIndex2 = getOrCreateFieldNameIndex(state.fieldNameTable, fieldPath);
|
|
2240
1750
|
const opts = tokenizeOptions(options);
|
|
@@ -2253,7 +1763,7 @@ function indexStringArrayField(state, internalId, fieldPath, arr, language, opti
|
|
|
2253
1763
|
tokenFreqs.set(t.token, { count: 1, positions: [positionOffset + t.position] });
|
|
2254
1764
|
}
|
|
2255
1765
|
fieldTokenList.push(t.token);
|
|
2256
|
-
|
|
1766
|
+
countOccurrence(surfaceCounts, spellings, t.surface, t.token);
|
|
2257
1767
|
itemTokenCount++;
|
|
2258
1768
|
}
|
|
2259
1769
|
positionOffset += itemTokenCount;
|
|
@@ -2268,7 +1778,7 @@ function indexStringArrayField(state, internalId, fieldPath, arr, language, opti
|
|
|
2268
1778
|
for (const t of tokenizeIterator(item, language, opts)) {
|
|
2269
1779
|
tokenCounts.set(t.token, (tokenCounts.get(t.token) ?? 0) + 1);
|
|
2270
1780
|
fieldTokenList.push(t.token);
|
|
2271
|
-
|
|
1781
|
+
countOccurrence(surfaceCounts, spellings, t.surface, t.token);
|
|
2272
1782
|
}
|
|
2273
1783
|
}
|
|
2274
1784
|
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
@@ -2280,17 +1790,28 @@ function indexStringArrayField(state, internalId, fieldPath, arr, language, opti
|
|
|
2280
1790
|
tokensByField[fieldPath] = fieldTokenList;
|
|
2281
1791
|
}
|
|
2282
1792
|
function indexDocument(state, docId, document, fields, language, options) {
|
|
2283
|
-
const
|
|
2284
|
-
const tokensByField =
|
|
1793
|
+
const indexed = emptyIndexedText(fields);
|
|
1794
|
+
const { fieldLengths, tokensByField } = indexed;
|
|
2285
1795
|
const internalId = resolveInternalId(state, docId);
|
|
2286
|
-
for (const
|
|
1796
|
+
for (const field of fields) {
|
|
1797
|
+
const { path: fieldPath, base, pattern } = field;
|
|
2287
1798
|
const value = getNestedValue(document, fieldPath);
|
|
2288
1799
|
if (value === void 0 || value === null) continue;
|
|
2289
1800
|
recordValueSize(state.sizeIndexes, internalId, fieldPath, base, value);
|
|
2290
1801
|
ensureFieldIndex(state, fieldPath, base);
|
|
2291
1802
|
if (pattern) patternIndexOf(state.patternIndexes, fieldPath).add(internalId, value);
|
|
2292
1803
|
if (base === "string") {
|
|
2293
|
-
indexStringField(
|
|
1804
|
+
indexStringField(
|
|
1805
|
+
state,
|
|
1806
|
+
internalId,
|
|
1807
|
+
fieldPath,
|
|
1808
|
+
value,
|
|
1809
|
+
language,
|
|
1810
|
+
options,
|
|
1811
|
+
fieldLengths,
|
|
1812
|
+
tokensByField,
|
|
1813
|
+
partialSpellingsFor(field, indexed)
|
|
1814
|
+
);
|
|
2294
1815
|
} else if (base === "number") {
|
|
2295
1816
|
getOrCreateNumericIndex(state, fieldPath).insert(internalId, value);
|
|
2296
1817
|
} else if (base === "boolean") {
|
|
@@ -2309,7 +1830,8 @@ function indexDocument(state, docId, document, fields, language, options) {
|
|
|
2309
1830
|
language,
|
|
2310
1831
|
options,
|
|
2311
1832
|
fieldLengths,
|
|
2312
|
-
tokensByField
|
|
1833
|
+
tokensByField,
|
|
1834
|
+
partialSpellingsFor(field, indexed)
|
|
2313
1835
|
);
|
|
2314
1836
|
} else if (base === "number[]") {
|
|
2315
1837
|
const numIdx = getOrCreateNumericIndex(state, fieldPath);
|
|
@@ -2324,15 +1846,17 @@ function indexDocument(state, docId, document, fields, language, options) {
|
|
|
2324
1846
|
}
|
|
2325
1847
|
}
|
|
2326
1848
|
}
|
|
2327
|
-
return
|
|
1849
|
+
return indexed;
|
|
2328
1850
|
}
|
|
2329
1851
|
function removeFromIndexes(state, docId, storedDoc, schemaFields, language, options) {
|
|
2330
|
-
const
|
|
2331
|
-
const tokensByField =
|
|
1852
|
+
const removed = emptyIndexedText(schemaFields);
|
|
1853
|
+
const { fieldLengths, tokensByField } = removed;
|
|
2332
1854
|
const fields = storedDoc.fields;
|
|
2333
1855
|
const internalId = resolveInternalId(state, docId);
|
|
2334
1856
|
const opts = tokenizeOptions(options);
|
|
2335
|
-
|
|
1857
|
+
const occurrencesByToken = /* @__PURE__ */ new Map();
|
|
1858
|
+
for (const field of schemaFields) {
|
|
1859
|
+
const { path: fieldPath, base, pattern } = field;
|
|
2336
1860
|
const value = getNestedValue(fields, fieldPath);
|
|
2337
1861
|
if (value === void 0 || value === null) continue;
|
|
2338
1862
|
forgetValueSize(state.sizeIndexes, internalId, fieldPath, base, value);
|
|
@@ -2340,16 +1864,15 @@ function removeFromIndexes(state, docId, storedDoc, schemaFields, language, opti
|
|
|
2340
1864
|
if (base === "string") {
|
|
2341
1865
|
const result = tokenize(value, language, opts);
|
|
2342
1866
|
fieldLengths[fieldPath] = result.tokens.length;
|
|
2343
|
-
const uniqueTokens = /* @__PURE__ */ new Set();
|
|
2344
1867
|
const fieldTokenList = [];
|
|
2345
1868
|
const surfaceCounts = /* @__PURE__ */ new Map();
|
|
1869
|
+
const spellings = partialSpellingsFor(field, removed);
|
|
2346
1870
|
for (let i = 0; i < result.tokens.length; i++) {
|
|
2347
1871
|
const t = result.tokens[i];
|
|
2348
|
-
uniqueTokens.add(t.token);
|
|
2349
1872
|
fieldTokenList.push(t.token);
|
|
2350
|
-
|
|
1873
|
+
countOccurrence(surfaceCounts, spellings, result.surfaces?.[i], t.token);
|
|
2351
1874
|
}
|
|
2352
|
-
|
|
1875
|
+
addFieldOccurrences(occurrencesByToken, fieldTokenList);
|
|
2353
1876
|
applySurfaceCounts(state, surfaceCounts, -1);
|
|
2354
1877
|
tokensByField[fieldPath] = fieldTokenList;
|
|
2355
1878
|
} else if (base === "number") {
|
|
@@ -2362,20 +1885,19 @@ function removeFromIndexes(state, docId, storedDoc, schemaFields, language, opti
|
|
|
2362
1885
|
state.geoIndexes.get(fieldPath)?.remove(internalId);
|
|
2363
1886
|
} else if (base === "string[]") {
|
|
2364
1887
|
const arr = value;
|
|
2365
|
-
const uniqueTokens = /* @__PURE__ */ new Set();
|
|
2366
1888
|
const fieldTokenList = [];
|
|
2367
1889
|
const surfaceCounts = /* @__PURE__ */ new Map();
|
|
1890
|
+
const spellings = partialSpellingsFor(field, removed);
|
|
2368
1891
|
for (const item of arr) {
|
|
2369
1892
|
const result = tokenize(item, language, opts);
|
|
2370
1893
|
for (let i = 0; i < result.tokens.length; i++) {
|
|
2371
1894
|
const t = result.tokens[i];
|
|
2372
|
-
uniqueTokens.add(t.token);
|
|
2373
1895
|
fieldTokenList.push(t.token);
|
|
2374
|
-
|
|
1896
|
+
countOccurrence(surfaceCounts, spellings, result.surfaces?.[i], t.token);
|
|
2375
1897
|
}
|
|
2376
1898
|
}
|
|
2377
1899
|
fieldLengths[fieldPath] = fieldTokenList.length;
|
|
2378
|
-
|
|
1900
|
+
addFieldOccurrences(occurrencesByToken, fieldTokenList);
|
|
2379
1901
|
applySurfaceCounts(state, surfaceCounts, -1);
|
|
2380
1902
|
tokensByField[fieldPath] = fieldTokenList;
|
|
2381
1903
|
} else if (base === "number[]") {
|
|
@@ -2395,7 +1917,8 @@ function removeFromIndexes(state, docId, storedDoc, schemaFields, language, opti
|
|
|
2395
1917
|
}
|
|
2396
1918
|
}
|
|
2397
1919
|
}
|
|
2398
|
-
|
|
1920
|
+
for (const [token, occurrences] of occurrencesByToken) state.invertedIdx.remove(token, internalId, occurrences);
|
|
1921
|
+
return removed;
|
|
2399
1922
|
}
|
|
2400
1923
|
|
|
2401
1924
|
// src/core/partition/field-updates.ts
|
|
@@ -3530,6 +3053,67 @@ function partitionFilterMatches(state, filters, schema, meter) {
|
|
|
3530
3053
|
};
|
|
3531
3054
|
}
|
|
3532
3055
|
|
|
3056
|
+
// src/core/scorer.ts
|
|
3057
|
+
var DEFAULT_K1 = 1.2;
|
|
3058
|
+
var DEFAULT_B = 0.75;
|
|
3059
|
+
function computeIDF(docFrequency, totalDocs) {
|
|
3060
|
+
if (totalDocs === 0) return 0;
|
|
3061
|
+
return Math.log((totalDocs - docFrequency + 0.5) / (docFrequency + 0.5) + 1);
|
|
3062
|
+
}
|
|
3063
|
+
function bm25PruningSound(params) {
|
|
3064
|
+
const k1 = params?.k1 ?? DEFAULT_K1;
|
|
3065
|
+
const b = params?.b ?? DEFAULT_B;
|
|
3066
|
+
return Number.isFinite(k1) && k1 >= 0 && b >= 0 && b <= 1;
|
|
3067
|
+
}
|
|
3068
|
+
function resolveBM25Params(params) {
|
|
3069
|
+
return { k1: params?.k1 ?? DEFAULT_K1, b: params?.b ?? DEFAULT_B };
|
|
3070
|
+
}
|
|
3071
|
+
function computeBM25WithIDF(termFrequency, idf, fieldLength, avgFieldLength, k1, b) {
|
|
3072
|
+
if (avgFieldLength === 0) return 0;
|
|
3073
|
+
const numerator = termFrequency * (k1 + 1);
|
|
3074
|
+
const denominator = termFrequency + k1 * (1 - b + b * fieldLength / avgFieldLength);
|
|
3075
|
+
if (denominator === 0) return 0;
|
|
3076
|
+
return idf * (numerator / denominator);
|
|
3077
|
+
}
|
|
3078
|
+
function computeBM25(termFrequency, docFrequency, totalDocs, fieldLength, avgFieldLength, params) {
|
|
3079
|
+
if (totalDocs === 0) return 0;
|
|
3080
|
+
const k1 = params?.k1 ?? DEFAULT_K1;
|
|
3081
|
+
const b = params?.b ?? DEFAULT_B;
|
|
3082
|
+
return computeBM25WithIDF(termFrequency, computeIDF(docFrequency, totalDocs), fieldLength, avgFieldLength, k1, b);
|
|
3083
|
+
}
|
|
3084
|
+
|
|
3085
|
+
// src/core/partition/field-scoring.ts
|
|
3086
|
+
function loadFieldScoring(state, fields, boost, averageFieldLengths) {
|
|
3087
|
+
const fieldNames = state.fieldNameTable.names;
|
|
3088
|
+
const scoring = {
|
|
3089
|
+
searchable: new Uint8Array(fieldNames.length),
|
|
3090
|
+
boosts: new Float64Array(fieldNames.length),
|
|
3091
|
+
averageLengths: new Float64Array(fieldNames.length),
|
|
3092
|
+
lengthColumns: new Array(fieldNames.length).fill(null)
|
|
3093
|
+
};
|
|
3094
|
+
for (let fieldIndex = 0; fieldIndex < fieldNames.length; fieldIndex++) {
|
|
3095
|
+
const fieldName = fieldNames[fieldIndex];
|
|
3096
|
+
scoring.searchable[fieldIndex] = fields === void 0 || fields.includes(fieldName) ? 1 : 0;
|
|
3097
|
+
scoring.boosts[fieldIndex] = boost?.[fieldName] ?? 1;
|
|
3098
|
+
scoring.averageLengths[fieldIndex] = averageFieldLengths[fieldName] ?? 1;
|
|
3099
|
+
scoring.lengthColumns[fieldIndex] = state.docStore.fieldLengthColumn(fieldName);
|
|
3100
|
+
}
|
|
3101
|
+
return scoring;
|
|
3102
|
+
}
|
|
3103
|
+
function fieldLengthOf(columns, fieldIndex, internalId, averageLength) {
|
|
3104
|
+
const column = fieldIndex < columns.length ? columns[fieldIndex] : null;
|
|
3105
|
+
if (column === null || internalId >= column.length) return averageLength;
|
|
3106
|
+
const stored = column[internalId];
|
|
3107
|
+
return stored > 0 ? stored : averageLength;
|
|
3108
|
+
}
|
|
3109
|
+
function bestSearchable(searchable, values) {
|
|
3110
|
+
let best = 0;
|
|
3111
|
+
for (let index = 0; index < searchable.length; index++) {
|
|
3112
|
+
if (searchable[index] === 1 && values[index] > best) best = values[index];
|
|
3113
|
+
}
|
|
3114
|
+
return best;
|
|
3115
|
+
}
|
|
3116
|
+
|
|
3533
3117
|
// src/core/partition/posting-columns.ts
|
|
3534
3118
|
function postingColumns(list) {
|
|
3535
3119
|
const deletedDocs = list.deletedDocs;
|
|
@@ -3543,39 +3127,174 @@ function postingColumns(list) {
|
|
|
3543
3127
|
};
|
|
3544
3128
|
}
|
|
3545
3129
|
|
|
3546
|
-
// src/core/partition/
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3130
|
+
// src/core/partition/scoring.ts
|
|
3131
|
+
var EMPTY_COMPONENTS = Object.freeze({});
|
|
3132
|
+
function recordComponents(components, internalId, fieldName, token, termFrequency, fieldLength, idf) {
|
|
3133
|
+
const existing = components.get(internalId);
|
|
3134
|
+
if (existing) {
|
|
3135
|
+
existing.termFrequencies[`${fieldName}:${token}`] = termFrequency;
|
|
3136
|
+
existing.fieldLengths[fieldName] = fieldLength;
|
|
3137
|
+
existing.idf[token] = idf;
|
|
3138
|
+
return;
|
|
3555
3139
|
}
|
|
3140
|
+
components.set(internalId, {
|
|
3141
|
+
termFrequencies: { [`${fieldName}:${token}`]: termFrequency },
|
|
3142
|
+
fieldLengths: { [fieldName]: fieldLength },
|
|
3143
|
+
idf: { [token]: idf }
|
|
3144
|
+
});
|
|
3556
3145
|
}
|
|
3557
|
-
function
|
|
3558
|
-
const
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3146
|
+
function mergeGroupComponents(components, internalId, contribution) {
|
|
3147
|
+
const existing = components.get(internalId);
|
|
3148
|
+
if (existing) {
|
|
3149
|
+
Object.assign(existing.termFrequencies, contribution.termFrequencies);
|
|
3150
|
+
Object.assign(existing.fieldLengths, contribution.fieldLengths);
|
|
3151
|
+
existing.idf[contribution.token] = contribution.idf;
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3154
|
+
components.set(internalId, {
|
|
3155
|
+
termFrequencies: contribution.termFrequencies,
|
|
3156
|
+
fieldLengths: contribution.fieldLengths,
|
|
3157
|
+
idf: { [contribution.token]: contribution.idf }
|
|
3158
|
+
});
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
// src/core/partition/group-scoring.ts
|
|
3162
|
+
function partialFieldMarks(fieldNames, partialFields) {
|
|
3163
|
+
const marks = new Uint8Array(fieldNames.length);
|
|
3164
|
+
if (partialFields === void 0 || partialFields.length === 0) return marks;
|
|
3165
|
+
for (let fieldIndex = 0; fieldIndex < fieldNames.length; fieldIndex++) {
|
|
3166
|
+
if (partialFields.includes(fieldNames[fieldIndex])) marks[fieldIndex] = 1;
|
|
3167
|
+
}
|
|
3168
|
+
return marks;
|
|
3169
|
+
}
|
|
3170
|
+
function termGroupOf(groups, token) {
|
|
3171
|
+
if (groups === void 0) return void 0;
|
|
3172
|
+
for (const group of groups) {
|
|
3173
|
+
if (group.token === token) return group;
|
|
3174
|
+
}
|
|
3175
|
+
return void 0;
|
|
3176
|
+
}
|
|
3177
|
+
function typoMatchesFor(index, token, group, exact, tolerance, prefixLength) {
|
|
3178
|
+
if (group !== void 0) {
|
|
3179
|
+
if (!group.typoMatches || exact || tolerance === 0) return [];
|
|
3180
|
+
return index.fuzzyLookup(token, tolerance, prefixLength).filter((match) => match.token !== token);
|
|
3181
|
+
}
|
|
3182
|
+
if (!exact) return index.fuzzyLookup(token, tolerance, prefixLength);
|
|
3183
|
+
const postingList = index.lookup(token);
|
|
3184
|
+
return postingList ? [{ token, postingList }] : [];
|
|
3185
|
+
}
|
|
3186
|
+
function resolveGroupMatches(context, group) {
|
|
3187
|
+
let groupDocumentFrequency = 0;
|
|
3188
|
+
const found = [];
|
|
3189
|
+
for (const member of group.members) {
|
|
3190
|
+
const documents = context.globalFrequency(member.token) ?? context.index.documentFrequency(member.token);
|
|
3191
|
+
if (documents > groupDocumentFrequency) groupDocumentFrequency = documents;
|
|
3192
|
+
const postingList = context.index.lookup(member.token);
|
|
3193
|
+
if (postingList === void 0) continue;
|
|
3194
|
+
found.push({ token: member.token, factor: member.factor, partialFactor: member.partialFactor, postingList });
|
|
3195
|
+
}
|
|
3196
|
+
if (found.length === 0) return [];
|
|
3197
|
+
const idf = computeIDF(groupDocumentFrequency, context.totalDocs);
|
|
3198
|
+
return found.map((entry) => ({ ...entry, idf }));
|
|
3199
|
+
}
|
|
3200
|
+
function groupPostingCount(matches) {
|
|
3201
|
+
let total = 0;
|
|
3202
|
+
for (const match of matches) total += match.postingList.length;
|
|
3203
|
+
return total;
|
|
3204
|
+
}
|
|
3205
|
+
function computeGroupContributions(context, matches, collect) {
|
|
3206
|
+
const { fields, fieldNames, filterBitset, partialMarks, k1, b } = context;
|
|
3207
|
+
const scoresAreZero = context.totalDocs === 0;
|
|
3208
|
+
const best = /* @__PURE__ */ new Map();
|
|
3209
|
+
for (const match of matches) {
|
|
3210
|
+
const perTerm = /* @__PURE__ */ new Map();
|
|
3211
|
+
const { docIds, termFrequencies, fieldNameIndices, deletedDocs, hasDeleted, count } = postingColumns(
|
|
3212
|
+
match.postingList
|
|
3213
|
+
);
|
|
3214
|
+
for (let pi = 0; pi < count; pi++) {
|
|
3215
|
+
const internalId = docIds[pi];
|
|
3216
|
+
if (hasDeleted && deletedDocs.has(internalId)) continue;
|
|
3217
|
+
if (filterBitset && !bitsetHas(filterBitset, internalId)) continue;
|
|
3218
|
+
const fieldIndex = fieldNameIndices[pi];
|
|
3219
|
+
if (fields.searchable[fieldIndex] === 0) continue;
|
|
3220
|
+
const factor = partialMarks[fieldIndex] === 1 ? match.partialFactor : match.factor;
|
|
3221
|
+
if (factor === 0) continue;
|
|
3222
|
+
const fieldName = fieldNames[fieldIndex];
|
|
3223
|
+
const termFrequency = termFrequencies[pi];
|
|
3224
|
+
const fieldBoost = fields.boosts[fieldIndex];
|
|
3225
|
+
const avgLen = fields.averageLengths[fieldIndex];
|
|
3226
|
+
const actualFieldLength = fieldLengthOf(fields.lengthColumns, fieldIndex, internalId, avgLen);
|
|
3227
|
+
const termScore = (scoresAreZero ? 0 : computeBM25WithIDF(termFrequency, match.idf, actualFieldLength, avgLen, k1, b)) * fieldBoost * factor;
|
|
3228
|
+
const existing = perTerm.get(internalId);
|
|
3229
|
+
if (existing) {
|
|
3230
|
+
existing.score += termScore;
|
|
3231
|
+
if (collect) {
|
|
3232
|
+
existing.termFrequencies[`${fieldName}:${match.token}`] = termFrequency;
|
|
3233
|
+
existing.fieldLengths[fieldName] = actualFieldLength;
|
|
3234
|
+
}
|
|
3235
|
+
} else if (collect) {
|
|
3236
|
+
perTerm.set(internalId, {
|
|
3237
|
+
score: termScore,
|
|
3238
|
+
token: match.token,
|
|
3239
|
+
idf: match.idf,
|
|
3240
|
+
termFrequencies: { [`${fieldName}:${match.token}`]: termFrequency },
|
|
3241
|
+
fieldLengths: { [fieldName]: actualFieldLength }
|
|
3242
|
+
});
|
|
3243
|
+
} else {
|
|
3244
|
+
perTerm.set(internalId, {
|
|
3245
|
+
score: termScore,
|
|
3246
|
+
token: match.token,
|
|
3247
|
+
idf: match.idf,
|
|
3248
|
+
termFrequencies: EMPTY_COMPONENTS,
|
|
3249
|
+
fieldLengths: EMPTY_COMPONENTS
|
|
3250
|
+
});
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
for (const [internalId, contribution] of perTerm) {
|
|
3254
|
+
const current = best.get(internalId);
|
|
3255
|
+
if (!current || contribution.score > current.score) {
|
|
3256
|
+
best.set(internalId, contribution);
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
return best;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
// src/core/partition/matches.ts
|
|
3264
|
+
function markPostingList(matched, list, markedFields, filterBitset) {
|
|
3265
|
+
const { docIds, fieldNameIndices, deletedDocs, hasDeleted, count } = postingColumns(list);
|
|
3266
|
+
for (let pi = 0; pi < count; pi++) {
|
|
3267
|
+
const internalId = docIds[pi];
|
|
3268
|
+
if (hasDeleted && deletedDocs.has(internalId)) continue;
|
|
3269
|
+
if (filterBitset && !bitsetHas(filterBitset, internalId)) continue;
|
|
3270
|
+
if (markedFields[fieldNameIndices[pi]] === 0) continue;
|
|
3271
|
+
bitsetSet(matched, internalId);
|
|
3272
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
function searchedFieldMarks(fieldNames, fields) {
|
|
3275
|
+
const marks = new Uint8Array(fieldNames.length);
|
|
3276
|
+
for (let fieldIndex = 0; fieldIndex < fieldNames.length; fieldIndex++) {
|
|
3277
|
+
if (fields === void 0 || fields.includes(fieldNames[fieldIndex])) marks[fieldIndex] = 1;
|
|
3278
|
+
}
|
|
3279
|
+
return marks;
|
|
3280
|
+
}
|
|
3281
|
+
function searchFulltextMatches(state, params) {
|
|
3282
|
+
const { queryTokens, termGroups, fields, tolerance = 0, prefixLength = 2, exact = false, filterBitset } = params;
|
|
3283
|
+
const fieldNames = state.fieldNameTable.names;
|
|
3284
|
+
const matched = createBitSet(state.docStore.internalIdCapacity());
|
|
3285
|
+
const searched = searchedFieldMarks(fieldNames, fields);
|
|
3286
|
+
const partial = partialFieldMarks(fieldNames, params.partialFields);
|
|
3287
|
+
const searchedPartial = searched.map((mark, fieldIndex) => mark & partial[fieldIndex]);
|
|
3288
|
+
for (const qt of queryTokens) {
|
|
3289
|
+
const group = termGroupOf(termGroups, qt.token);
|
|
3290
|
+
for (const match of typoMatchesFor(state.invertedIdx, qt.token, group, exact, tolerance, prefixLength)) {
|
|
3291
|
+
markPostingList(matched, match.postingList, searched, filterBitset);
|
|
3292
|
+
}
|
|
3293
|
+
if (group === void 0) continue;
|
|
3294
|
+
for (const member of group.members) {
|
|
3295
|
+
const postingList = state.invertedIdx.lookup(member.token);
|
|
3296
|
+
if (postingList === void 0) continue;
|
|
3297
|
+
markPostingList(matched, postingList, member.factor > 0 ? searched : searchedPartial, filterBitset);
|
|
3579
3298
|
}
|
|
3580
3299
|
}
|
|
3581
3300
|
const docStore = state.docStore;
|
|
@@ -3663,6 +3382,7 @@ function estimatePartitionBytes(state) {
|
|
|
3663
3382
|
bytes += docCount * state.geoIndexes.size * FIELD_ENTRY_OVERHEAD_BYTES;
|
|
3664
3383
|
bytes += docCount * state.sizeIndexes.size * FIELD_ENTRY_OVERHEAD_BYTES;
|
|
3665
3384
|
for (const index of state.patternIndexes.values()) bytes += index.bytes();
|
|
3385
|
+
bytes += state.partialWords.bytes();
|
|
3666
3386
|
return bytes + sortColumnBytes(state);
|
|
3667
3387
|
}
|
|
3668
3388
|
|
|
@@ -3794,10 +3514,71 @@ function mergeSegmentState(target, source) {
|
|
|
3794
3514
|
mergeFieldIndexes(target, source, idMapping);
|
|
3795
3515
|
mergeStatistics(target, source);
|
|
3796
3516
|
mergeSurfaceForms(target, source);
|
|
3517
|
+
target.partialWords.afterMerge(source.partialWords.spellings(), [...idMapping.values()]);
|
|
3797
3518
|
target.sortColumns = null;
|
|
3798
3519
|
target.scoreBuffer = null;
|
|
3799
3520
|
}
|
|
3800
3521
|
|
|
3522
|
+
// src/core/partition/partial-words/platform.ts
|
|
3523
|
+
function platformPartialWordSearch() {
|
|
3524
|
+
return partialWordSearchModule;
|
|
3525
|
+
}
|
|
3526
|
+
|
|
3527
|
+
// src/core/partition/partial-words/registry.ts
|
|
3528
|
+
var registered2 = null;
|
|
3529
|
+
function isPartialWordSearchModule(value) {
|
|
3530
|
+
return value !== null && typeof value === "object" && value.name === "partialWords" && "createGrowingSlot" in value && typeof value.createGrowingSlot === "function" && "createFrozenSlot" in value && typeof value.createFrozenSlot === "function" && "buildTable" in value && typeof value.buildTable === "function" && "expand" in value && typeof value.expand === "function";
|
|
3531
|
+
}
|
|
3532
|
+
function registerPartialWordSearch(module) {
|
|
3533
|
+
if (!isPartialWordSearchModule(module)) {
|
|
3534
|
+
throw new NarsilError(
|
|
3535
|
+
ErrorCodes.CONFIG_INVALID,
|
|
3536
|
+
'Pass registerPartialWordSearch the partialWordSearch object that "@delali/narsil/partial-words" exports'
|
|
3537
|
+
);
|
|
3538
|
+
}
|
|
3539
|
+
registered2 = module;
|
|
3540
|
+
}
|
|
3541
|
+
function availablePartialWordSearch() {
|
|
3542
|
+
return registered2 ?? platformPartialWordSearch();
|
|
3543
|
+
}
|
|
3544
|
+
function requirePartialWordSearchFor(schema) {
|
|
3545
|
+
const fields = partialFieldsOf(schema);
|
|
3546
|
+
if (fields.length === 0 || availablePartialWordSearch() !== null) return;
|
|
3547
|
+
throw new NarsilError(
|
|
3548
|
+
ErrorCodes.CONFIG_INVALID,
|
|
3549
|
+
`The type of field "${fields[0]}" includes "partial", but this bundle contains no partial-word search code. Add import { partialWordSearch } from '@delali/narsil/partial-words', then call registerPartialWordSearch(partialWordSearch) before you create or load the index`,
|
|
3550
|
+
{ field: fields[0] }
|
|
3551
|
+
);
|
|
3552
|
+
}
|
|
3553
|
+
var EMPTY_GROWING_SLOT = {
|
|
3554
|
+
readerFor: () => null,
|
|
3555
|
+
spellings: () => null,
|
|
3556
|
+
bytes: () => 0,
|
|
3557
|
+
afterDocument: () => void 0,
|
|
3558
|
+
afterMerge: () => void 0,
|
|
3559
|
+
forgetSpellings: () => void 0,
|
|
3560
|
+
clear: () => void 0
|
|
3561
|
+
};
|
|
3562
|
+
var EMPTY_FROZEN_SLOT = {
|
|
3563
|
+
readerFor: () => null,
|
|
3564
|
+
spellings: () => null,
|
|
3565
|
+
bytes: () => 0,
|
|
3566
|
+
afterRemoval: () => void 0
|
|
3567
|
+
};
|
|
3568
|
+
function createGrowingPartialWords(view) {
|
|
3569
|
+
return availablePartialWordSearch()?.createGrowingSlot(view) ?? EMPTY_GROWING_SLOT;
|
|
3570
|
+
}
|
|
3571
|
+
function createFrozenPartialWords(initial, tokenTable, documents) {
|
|
3572
|
+
return availablePartialWordSearch()?.createFrozenSlot(initial, tokenTable, documents) ?? EMPTY_FROZEN_SLOT;
|
|
3573
|
+
}
|
|
3574
|
+
function buildPartialWordTableFrom(source, tokenTable) {
|
|
3575
|
+
return availablePartialWordSearch()?.buildTable(source, tokenTable) ?? null;
|
|
3576
|
+
}
|
|
3577
|
+
function expandPartialWords(subs, analysis, requests) {
|
|
3578
|
+
const module = availablePartialWordSearch();
|
|
3579
|
+
return module === null ? requests.map(() => []) : module.expand(subs, analysis, requests);
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3801
3582
|
// src/core/partition/rebuild.ts
|
|
3802
3583
|
var EMPTY_STATS = {
|
|
3803
3584
|
totalDocuments: 0,
|
|
@@ -3853,70 +3634,10 @@ function rebuildTextIndex(state, schema, language, options) {
|
|
|
3853
3634
|
}
|
|
3854
3635
|
} finally {
|
|
3855
3636
|
state.invertedIdx.endBatch();
|
|
3637
|
+
state.partialWords.forgetSpellings();
|
|
3856
3638
|
}
|
|
3857
3639
|
}
|
|
3858
3640
|
|
|
3859
|
-
// src/core/scorer.ts
|
|
3860
|
-
var DEFAULT_K1 = 1.2;
|
|
3861
|
-
var DEFAULT_B = 0.75;
|
|
3862
|
-
function computeIDF(docFrequency, totalDocs) {
|
|
3863
|
-
if (totalDocs === 0) return 0;
|
|
3864
|
-
return Math.log((totalDocs - docFrequency + 0.5) / (docFrequency + 0.5) + 1);
|
|
3865
|
-
}
|
|
3866
|
-
function bm25PruningSound(params) {
|
|
3867
|
-
const k1 = params?.k1 ?? DEFAULT_K1;
|
|
3868
|
-
const b = params?.b ?? DEFAULT_B;
|
|
3869
|
-
return Number.isFinite(k1) && k1 >= 0 && b >= 0 && b <= 1;
|
|
3870
|
-
}
|
|
3871
|
-
function resolveBM25Params(params) {
|
|
3872
|
-
return { k1: params?.k1 ?? DEFAULT_K1, b: params?.b ?? DEFAULT_B };
|
|
3873
|
-
}
|
|
3874
|
-
function computeBM25WithIDF(termFrequency, idf, fieldLength, avgFieldLength, k1, b) {
|
|
3875
|
-
if (avgFieldLength === 0) return 0;
|
|
3876
|
-
const numerator = termFrequency * (k1 + 1);
|
|
3877
|
-
const denominator = termFrequency + k1 * (1 - b + b * fieldLength / avgFieldLength);
|
|
3878
|
-
if (denominator === 0) return 0;
|
|
3879
|
-
return idf * (numerator / denominator);
|
|
3880
|
-
}
|
|
3881
|
-
function computeBM25(termFrequency, docFrequency, totalDocs, fieldLength, avgFieldLength, params) {
|
|
3882
|
-
if (totalDocs === 0) return 0;
|
|
3883
|
-
const k1 = params?.k1 ?? DEFAULT_K1;
|
|
3884
|
-
const b = params?.b ?? DEFAULT_B;
|
|
3885
|
-
return computeBM25WithIDF(termFrequency, computeIDF(docFrequency, totalDocs), fieldLength, avgFieldLength, k1, b);
|
|
3886
|
-
}
|
|
3887
|
-
|
|
3888
|
-
// src/core/partition/field-scoring.ts
|
|
3889
|
-
function loadFieldScoring(state, fields, boost, averageFieldLengths) {
|
|
3890
|
-
const fieldNames = state.fieldNameTable.names;
|
|
3891
|
-
const scoring = {
|
|
3892
|
-
searchable: new Uint8Array(fieldNames.length),
|
|
3893
|
-
boosts: new Float64Array(fieldNames.length),
|
|
3894
|
-
averageLengths: new Float64Array(fieldNames.length),
|
|
3895
|
-
lengthColumns: new Array(fieldNames.length).fill(null)
|
|
3896
|
-
};
|
|
3897
|
-
for (let fieldIndex = 0; fieldIndex < fieldNames.length; fieldIndex++) {
|
|
3898
|
-
const fieldName = fieldNames[fieldIndex];
|
|
3899
|
-
scoring.searchable[fieldIndex] = fields === void 0 || fields.includes(fieldName) ? 1 : 0;
|
|
3900
|
-
scoring.boosts[fieldIndex] = boost?.[fieldName] ?? 1;
|
|
3901
|
-
scoring.averageLengths[fieldIndex] = averageFieldLengths[fieldName] ?? 1;
|
|
3902
|
-
scoring.lengthColumns[fieldIndex] = state.docStore.fieldLengthColumn(fieldName);
|
|
3903
|
-
}
|
|
3904
|
-
return scoring;
|
|
3905
|
-
}
|
|
3906
|
-
function fieldLengthOf(columns, fieldIndex, internalId, averageLength) {
|
|
3907
|
-
const column = fieldIndex < columns.length ? columns[fieldIndex] : null;
|
|
3908
|
-
if (column === null || internalId >= column.length) return averageLength;
|
|
3909
|
-
const stored = column[internalId];
|
|
3910
|
-
return stored > 0 ? stored : averageLength;
|
|
3911
|
-
}
|
|
3912
|
-
function bestSearchable(searchable, values) {
|
|
3913
|
-
let best = 0;
|
|
3914
|
-
for (let index = 0; index < searchable.length; index++) {
|
|
3915
|
-
if (searchable[index] === 1 && values[index] > best) best = values[index];
|
|
3916
|
-
}
|
|
3917
|
-
return best;
|
|
3918
|
-
}
|
|
3919
|
-
|
|
3920
3641
|
// src/core/partition/block-bounds.ts
|
|
3921
3642
|
var ABSENT_FIELD_LENGTH_BOUND = 0;
|
|
3922
3643
|
var boundsByList = /* @__PURE__ */ new WeakMap();
|
|
@@ -4012,37 +3733,6 @@ function blockBoundsFor(list, columns) {
|
|
|
4012
3733
|
return built;
|
|
4013
3734
|
}
|
|
4014
3735
|
|
|
4015
|
-
// src/core/partition/scoring.ts
|
|
4016
|
-
var EMPTY_COMPONENTS = Object.freeze({});
|
|
4017
|
-
function recordComponents(components, internalId, fieldName, token, termFrequency, fieldLength, idf) {
|
|
4018
|
-
const existing = components.get(internalId);
|
|
4019
|
-
if (existing) {
|
|
4020
|
-
existing.termFrequencies[`${fieldName}:${token}`] = termFrequency;
|
|
4021
|
-
existing.fieldLengths[fieldName] = fieldLength;
|
|
4022
|
-
existing.idf[token] = idf;
|
|
4023
|
-
return;
|
|
4024
|
-
}
|
|
4025
|
-
components.set(internalId, {
|
|
4026
|
-
termFrequencies: { [`${fieldName}:${token}`]: termFrequency },
|
|
4027
|
-
fieldLengths: { [fieldName]: fieldLength },
|
|
4028
|
-
idf: { [token]: idf }
|
|
4029
|
-
});
|
|
4030
|
-
}
|
|
4031
|
-
function mergePrefixComponents(components, internalId, contribution) {
|
|
4032
|
-
const existing = components.get(internalId);
|
|
4033
|
-
if (existing) {
|
|
4034
|
-
Object.assign(existing.termFrequencies, contribution.termFrequencies);
|
|
4035
|
-
Object.assign(existing.fieldLengths, contribution.fieldLengths);
|
|
4036
|
-
existing.idf[contribution.token] = contribution.idf;
|
|
4037
|
-
return;
|
|
4038
|
-
}
|
|
4039
|
-
components.set(internalId, {
|
|
4040
|
-
termFrequencies: contribution.termFrequencies,
|
|
4041
|
-
fieldLengths: contribution.fieldLengths,
|
|
4042
|
-
idf: { [contribution.token]: contribution.idf }
|
|
4043
|
-
});
|
|
4044
|
-
}
|
|
4045
|
-
|
|
4046
3736
|
// src/core/partition/top-k-heap.ts
|
|
4047
3737
|
function candidateWorse(a, b) {
|
|
4048
3738
|
if (a.score !== b.score) return a.score < b.score;
|
|
@@ -4206,7 +3896,7 @@ function topKFromBuffer(buffer, k, resolver, components) {
|
|
|
4206
3896
|
// src/core/partition/multi-term-topk.ts
|
|
4207
3897
|
function prunableMultiTermLists(params, index) {
|
|
4208
3898
|
if (params.queryTokens.length < 2) return null;
|
|
4209
|
-
if (params.
|
|
3899
|
+
if (params.termGroups !== void 0 && params.termGroups.length > 0) return null;
|
|
4210
3900
|
if (params.exact !== true && (params.tolerance ?? 0) !== 0) return null;
|
|
4211
3901
|
if (params.termMatch !== void 0 && params.termMatch !== "any") return null;
|
|
4212
3902
|
if (params.collectComponents !== false) return null;
|
|
@@ -4378,87 +4068,6 @@ function multiTermTopK(request) {
|
|
|
4378
4068
|
return { scored: pageFromBuffer(scans, buffer, selection, resolver), totalMatched };
|
|
4379
4069
|
}
|
|
4380
4070
|
|
|
4381
|
-
// src/core/partition/prefix-scoring.ts
|
|
4382
|
-
function resolvePrefixMatches(context, token, expansionTerms) {
|
|
4383
|
-
const found = [];
|
|
4384
|
-
const seen = /* @__PURE__ */ new Set();
|
|
4385
|
-
for (const term of [token, ...expansionTerms]) {
|
|
4386
|
-
if (seen.has(term)) continue;
|
|
4387
|
-
seen.add(term);
|
|
4388
|
-
const postingList = context.index.lookup(term);
|
|
4389
|
-
if (!postingList) continue;
|
|
4390
|
-
found.push({ token: term, postingList, docFreq: context.documentFrequency(term, postingList) });
|
|
4391
|
-
}
|
|
4392
|
-
if (found.length === 0) return [];
|
|
4393
|
-
let blendedDf = 0;
|
|
4394
|
-
for (const f of found) {
|
|
4395
|
-
if (f.docFreq > blendedDf) blendedDf = f.docFreq;
|
|
4396
|
-
}
|
|
4397
|
-
const blendedIdf = computeIDF(blendedDf, context.totalDocs);
|
|
4398
|
-
return found.map((f) => ({
|
|
4399
|
-
token: f.token,
|
|
4400
|
-
factor: Math.min(1, token.length / f.token.length),
|
|
4401
|
-
postingList: f.postingList,
|
|
4402
|
-
docFreq: blendedDf,
|
|
4403
|
-
idf: blendedIdf
|
|
4404
|
-
}));
|
|
4405
|
-
}
|
|
4406
|
-
function computePrefixContributions(context, matches, collect) {
|
|
4407
|
-
const { fields, fieldNames, filterBitset, k1, b } = context;
|
|
4408
|
-
const scoresAreZero = context.totalDocs === 0;
|
|
4409
|
-
const best = /* @__PURE__ */ new Map();
|
|
4410
|
-
for (const match of matches) {
|
|
4411
|
-
const perTerm = /* @__PURE__ */ new Map();
|
|
4412
|
-
const { docIds, termFrequencies, fieldNameIndices, deletedDocs, hasDeleted, count } = postingColumns(
|
|
4413
|
-
match.postingList
|
|
4414
|
-
);
|
|
4415
|
-
for (let pi = 0; pi < count; pi++) {
|
|
4416
|
-
const internalId = docIds[pi];
|
|
4417
|
-
if (hasDeleted && deletedDocs.has(internalId)) continue;
|
|
4418
|
-
if (filterBitset && !bitsetHas(filterBitset, internalId)) continue;
|
|
4419
|
-
const fieldIndex = fieldNameIndices[pi];
|
|
4420
|
-
if (fields.searchable[fieldIndex] === 0) continue;
|
|
4421
|
-
const fieldName = fieldNames[fieldIndex];
|
|
4422
|
-
const termFrequency = termFrequencies[pi];
|
|
4423
|
-
const fieldBoost = fields.boosts[fieldIndex];
|
|
4424
|
-
const avgLen = fields.averageLengths[fieldIndex];
|
|
4425
|
-
const actualFieldLength = fieldLengthOf(fields.lengthColumns, fieldIndex, internalId, avgLen);
|
|
4426
|
-
const termScore = (scoresAreZero ? 0 : computeBM25WithIDF(termFrequency, match.idf, actualFieldLength, avgLen, k1, b)) * fieldBoost * match.factor;
|
|
4427
|
-
const existing = perTerm.get(internalId);
|
|
4428
|
-
if (existing) {
|
|
4429
|
-
existing.score += termScore;
|
|
4430
|
-
if (collect) {
|
|
4431
|
-
existing.termFrequencies[`${fieldName}:${match.token}`] = termFrequency;
|
|
4432
|
-
existing.fieldLengths[fieldName] = actualFieldLength;
|
|
4433
|
-
}
|
|
4434
|
-
} else if (collect) {
|
|
4435
|
-
perTerm.set(internalId, {
|
|
4436
|
-
score: termScore,
|
|
4437
|
-
token: match.token,
|
|
4438
|
-
idf: match.idf,
|
|
4439
|
-
termFrequencies: { [`${fieldName}:${match.token}`]: termFrequency },
|
|
4440
|
-
fieldLengths: { [fieldName]: actualFieldLength }
|
|
4441
|
-
});
|
|
4442
|
-
} else {
|
|
4443
|
-
perTerm.set(internalId, {
|
|
4444
|
-
score: termScore,
|
|
4445
|
-
token: match.token,
|
|
4446
|
-
idf: match.idf,
|
|
4447
|
-
termFrequencies: EMPTY_COMPONENTS,
|
|
4448
|
-
fieldLengths: EMPTY_COMPONENTS
|
|
4449
|
-
});
|
|
4450
|
-
}
|
|
4451
|
-
}
|
|
4452
|
-
for (const [internalId, contribution] of perTerm) {
|
|
4453
|
-
const current = best.get(internalId);
|
|
4454
|
-
if (!current || contribution.score > current.score) {
|
|
4455
|
-
best.set(internalId, contribution);
|
|
4456
|
-
}
|
|
4457
|
-
}
|
|
4458
|
-
}
|
|
4459
|
-
return best;
|
|
4460
|
-
}
|
|
4461
|
-
|
|
4462
4071
|
// src/core/partition/single-term-topk.ts
|
|
4463
4072
|
function fieldsCoverEvery(fields, fieldNames) {
|
|
4464
4073
|
if (fields === void 0) return true;
|
|
@@ -4469,7 +4078,7 @@ function fieldsCoverEvery(fields, fieldNames) {
|
|
|
4469
4078
|
}
|
|
4470
4079
|
function prunableSingleTermList(params, index, fieldNames) {
|
|
4471
4080
|
if (params.queryTokens.length !== 1) return null;
|
|
4472
|
-
if (params.
|
|
4081
|
+
if (params.termGroups !== void 0 && params.termGroups.length > 0) return null;
|
|
4473
4082
|
if (params.exact !== true && (params.tolerance ?? 0) !== 0) return null;
|
|
4474
4083
|
if (params.termMatch !== void 0 && params.termMatch !== "any") return null;
|
|
4475
4084
|
if (params.collectComponents !== false) return null;
|
|
@@ -4579,15 +4188,11 @@ function singleTermTopK(request) {
|
|
|
4579
4188
|
function globalDocFreqFor(docFreqs, term, fallback) {
|
|
4580
4189
|
return Object.hasOwn(docFreqs, term) ? docFreqs[term] : fallback;
|
|
4581
4190
|
}
|
|
4582
|
-
function matchesFor(index, token, exact, tolerance, prefixLength) {
|
|
4583
|
-
if (!exact) return index.fuzzyLookup(token, tolerance, prefixLength);
|
|
4584
|
-
const postingList = index.lookup(token);
|
|
4585
|
-
return postingList ? [{ token, postingList }] : [];
|
|
4586
|
-
}
|
|
4587
4191
|
function searchFulltext(state, params) {
|
|
4588
4192
|
const {
|
|
4589
4193
|
queryTokens,
|
|
4590
|
-
|
|
4194
|
+
termGroups,
|
|
4195
|
+
partialFields,
|
|
4591
4196
|
fields,
|
|
4592
4197
|
boost,
|
|
4593
4198
|
tolerance = 0,
|
|
@@ -4619,19 +4224,75 @@ function searchFulltext(state, params) {
|
|
|
4619
4224
|
function documentFrequency(token, list) {
|
|
4620
4225
|
return globalStats ? globalDocFreqFor(globalStats.docFrequencies, token, list.docIdSet.size) : list.docIdSet.size;
|
|
4621
4226
|
}
|
|
4622
|
-
const
|
|
4227
|
+
const groupContext = {
|
|
4623
4228
|
index: state.invertedIdx,
|
|
4624
4229
|
fields: fieldScoring,
|
|
4230
|
+
partialMarks: partialFieldMarks(fieldNames, partialFields),
|
|
4625
4231
|
fieldNames,
|
|
4626
4232
|
totalDocs,
|
|
4627
4233
|
k1,
|
|
4628
4234
|
b,
|
|
4629
4235
|
filterBitset,
|
|
4630
|
-
|
|
4236
|
+
globalFrequency(token) {
|
|
4237
|
+
if (globalStats === void 0 || !Object.hasOwn(globalStats.docFrequencies, token)) return void 0;
|
|
4238
|
+
return globalStats.docFrequencies[token];
|
|
4239
|
+
}
|
|
4631
4240
|
};
|
|
4632
|
-
function
|
|
4241
|
+
function mergeGroupContribution(internalId, contribution) {
|
|
4633
4242
|
addScore(scoreBuffer, internalId, contribution.score);
|
|
4634
|
-
if (components !== null)
|
|
4243
|
+
if (components !== null) mergeGroupComponents(components, internalId, contribution);
|
|
4244
|
+
}
|
|
4245
|
+
function resolveMatch(token, postingList) {
|
|
4246
|
+
const docFreq = documentFrequency(token, postingList);
|
|
4247
|
+
return { token, docFreq, idf: computeIDF(docFreq, totalDocs), postingList };
|
|
4248
|
+
}
|
|
4249
|
+
function scorePostings(match, onlyScored) {
|
|
4250
|
+
const { docIds, termFrequencies, fieldNameIndices, deletedDocs, hasDeleted, count } = postingColumns(
|
|
4251
|
+
match.postingList
|
|
4252
|
+
);
|
|
4253
|
+
if (!onlyScored && !hasDeleted && filterBitset === void 0 && components === null) {
|
|
4254
|
+
for (let pi = 0; pi < count; pi++) {
|
|
4255
|
+
const internalId = docIds[pi];
|
|
4256
|
+
const fieldIndex = fieldNameIndices[pi];
|
|
4257
|
+
if (searchable[fieldIndex] === 0) continue;
|
|
4258
|
+
const avgLen = averageLengths[fieldIndex];
|
|
4259
|
+
const actualFieldLength = fieldLengthOf(lengthColumns, fieldIndex, internalId, avgLen);
|
|
4260
|
+
const termScore = scoresAreZero ? 0 : computeBM25WithIDF(termFrequencies[pi], match.idf, actualFieldLength, avgLen, k1, b);
|
|
4261
|
+
addScore(scoreBuffer, internalId, termScore * boosts[fieldIndex]);
|
|
4262
|
+
}
|
|
4263
|
+
return;
|
|
4264
|
+
}
|
|
4265
|
+
for (let pi = 0; pi < count; pi++) {
|
|
4266
|
+
const internalId = docIds[pi];
|
|
4267
|
+
if (hasDeleted && deletedDocs.has(internalId)) continue;
|
|
4268
|
+
if (filterBitset && !bitsetHas(filterBitset, internalId)) continue;
|
|
4269
|
+
if (onlyScored && !hasScore(scoreBuffer, internalId)) continue;
|
|
4270
|
+
const fieldIndex = fieldNameIndices[pi];
|
|
4271
|
+
if (searchable[fieldIndex] === 0) continue;
|
|
4272
|
+
const termFrequency = termFrequencies[pi];
|
|
4273
|
+
const avgLen = averageLengths[fieldIndex];
|
|
4274
|
+
const actualFieldLength = fieldLengthOf(lengthColumns, fieldIndex, internalId, avgLen);
|
|
4275
|
+
const termScore = scoresAreZero ? 0 : computeBM25WithIDF(termFrequency, match.idf, actualFieldLength, avgLen, k1, b);
|
|
4276
|
+
addScore(scoreBuffer, internalId, termScore * boosts[fieldIndex]);
|
|
4277
|
+
if (components !== null) {
|
|
4278
|
+
recordComponents(
|
|
4279
|
+
components,
|
|
4280
|
+
internalId,
|
|
4281
|
+
fieldNames[fieldIndex],
|
|
4282
|
+
match.token,
|
|
4283
|
+
termFrequency,
|
|
4284
|
+
actualFieldLength,
|
|
4285
|
+
match.idf
|
|
4286
|
+
);
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
function scoreGroup(group, onlyScored) {
|
|
4291
|
+
if (group === null) return;
|
|
4292
|
+
for (const [internalId, contribution] of computeGroupContributions(groupContext, group, collectComponents)) {
|
|
4293
|
+
if (onlyScored && !hasScore(scoreBuffer, internalId)) continue;
|
|
4294
|
+
mergeGroupContribution(internalId, contribution);
|
|
4295
|
+
}
|
|
4635
4296
|
}
|
|
4636
4297
|
const prunableList = prunableSingleTermList(params, state.invertedIdx, fieldNames);
|
|
4637
4298
|
if (prunableList !== null && maxResults !== void 0) {
|
|
@@ -4661,127 +4322,30 @@ function searchFulltext(state, params) {
|
|
|
4661
4322
|
}
|
|
4662
4323
|
if (useIntersection) {
|
|
4663
4324
|
const resolved = [];
|
|
4664
|
-
let prefixMatches = [];
|
|
4665
4325
|
for (const qt of queryTokens) {
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
for (const m of prefixMatches) {
|
|
4670
|
-
totalPostings2 += m.postingList.length;
|
|
4671
|
-
}
|
|
4672
|
-
resolved.push({ token: qt.token, matches: [], totalPostings: totalPostings2, isPrefix: true });
|
|
4673
|
-
continue;
|
|
4674
|
-
}
|
|
4675
|
-
const rawMatches = matchesFor(state.invertedIdx, qt.token, exact, tolerance, prefixLength);
|
|
4676
|
-
let totalPostings = 0;
|
|
4326
|
+
const group = termGroupOf(termGroups, qt.token);
|
|
4327
|
+
const groupMatches = group === void 0 ? null : resolveGroupMatches(groupContext, group);
|
|
4328
|
+
let totalPostings = groupMatches === null ? 0 : groupPostingCount(groupMatches);
|
|
4677
4329
|
const matches = [];
|
|
4678
|
-
for (const m of
|
|
4679
|
-
const docFreq = documentFrequency(m.token, m.postingList);
|
|
4680
|
-
const idf = computeIDF(docFreq, totalDocs);
|
|
4330
|
+
for (const m of typoMatchesFor(state.invertedIdx, qt.token, group, exact, tolerance, prefixLength)) {
|
|
4681
4331
|
totalPostings += m.postingList.length;
|
|
4682
|
-
matches.push(
|
|
4332
|
+
matches.push(resolveMatch(m.token, m.postingList));
|
|
4683
4333
|
}
|
|
4684
|
-
resolved.push({ token: qt.token, matches, totalPostings });
|
|
4334
|
+
resolved.push({ token: qt.token, matches, totalPostings, group: groupMatches });
|
|
4685
4335
|
}
|
|
4686
4336
|
resolved.sort((a, b2) => a.totalPostings - b2.totalPostings);
|
|
4687
4337
|
for (let tokenIndex = 0; tokenIndex < resolved.length; tokenIndex++) {
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
if (tokenIndex > 0 && !hasScore(scoreBuffer, internalId)) continue;
|
|
4692
|
-
mergePrefixContribution(internalId, contribution);
|
|
4693
|
-
}
|
|
4694
|
-
continue;
|
|
4695
|
-
}
|
|
4696
|
-
for (const match of resolved[tokenIndex].matches) {
|
|
4697
|
-
const { docIds, termFrequencies, fieldNameIndices, deletedDocs, hasDeleted, count } = postingColumns(
|
|
4698
|
-
match.postingList
|
|
4699
|
-
);
|
|
4700
|
-
for (let pi = 0; pi < count; pi++) {
|
|
4701
|
-
const internalId = docIds[pi];
|
|
4702
|
-
if (hasDeleted && deletedDocs.has(internalId)) continue;
|
|
4703
|
-
if (filterBitset && !bitsetHas(filterBitset, internalId)) continue;
|
|
4704
|
-
if (tokenIndex > 0 && !hasScore(scoreBuffer, internalId)) continue;
|
|
4705
|
-
const fieldIndex = fieldNameIndices[pi];
|
|
4706
|
-
if (searchable[fieldIndex] === 0) continue;
|
|
4707
|
-
const termFrequency = termFrequencies[pi];
|
|
4708
|
-
const fieldBoost = boosts[fieldIndex];
|
|
4709
|
-
const avgLen = averageLengths[fieldIndex];
|
|
4710
|
-
const actualFieldLength = fieldLengthOf(lengthColumns, fieldIndex, internalId, avgLen);
|
|
4711
|
-
let termScore = scoresAreZero ? 0 : computeBM25WithIDF(termFrequency, match.idf, actualFieldLength, avgLen, k1, b);
|
|
4712
|
-
termScore *= fieldBoost;
|
|
4713
|
-
addScore(scoreBuffer, internalId, termScore);
|
|
4714
|
-
if (components !== null) {
|
|
4715
|
-
recordComponents(
|
|
4716
|
-
components,
|
|
4717
|
-
internalId,
|
|
4718
|
-
fieldNames[fieldIndex],
|
|
4719
|
-
match.token,
|
|
4720
|
-
termFrequency,
|
|
4721
|
-
actualFieldLength,
|
|
4722
|
-
match.idf
|
|
4723
|
-
);
|
|
4724
|
-
}
|
|
4725
|
-
}
|
|
4726
|
-
}
|
|
4338
|
+
const onlyScored = tokenIndex > 0;
|
|
4339
|
+
for (const match of resolved[tokenIndex].matches) scorePostings(match, onlyScored);
|
|
4340
|
+
scoreGroup(resolved[tokenIndex].group, onlyScored);
|
|
4727
4341
|
}
|
|
4728
4342
|
} else {
|
|
4729
4343
|
for (const qt of queryTokens) {
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
resolvePrefixMatches(prefixContext, qt.token, prefixExpansion.terms),
|
|
4734
|
-
collectComponents
|
|
4735
|
-
);
|
|
4736
|
-
for (const [internalId, contribution] of contributions) {
|
|
4737
|
-
mergePrefixContribution(internalId, contribution);
|
|
4738
|
-
}
|
|
4739
|
-
continue;
|
|
4740
|
-
}
|
|
4741
|
-
const matchingPostings = matchesFor(state.invertedIdx, qt.token, exact, tolerance, prefixLength);
|
|
4742
|
-
for (const match of matchingPostings) {
|
|
4743
|
-
const idf = computeIDF(documentFrequency(match.token, match.postingList), totalDocs);
|
|
4744
|
-
const { docIds, termFrequencies, fieldNameIndices, deletedDocs, hasDeleted, count } = postingColumns(
|
|
4745
|
-
match.postingList
|
|
4746
|
-
);
|
|
4747
|
-
if (!hasDeleted && filterBitset === void 0 && components === null) {
|
|
4748
|
-
for (let pi = 0; pi < count; pi++) {
|
|
4749
|
-
const internalId = docIds[pi];
|
|
4750
|
-
const fieldIndex = fieldNameIndices[pi];
|
|
4751
|
-
if (searchable[fieldIndex] === 0) continue;
|
|
4752
|
-
const avgLen = averageLengths[fieldIndex];
|
|
4753
|
-
const actualFieldLength = fieldLengthOf(lengthColumns, fieldIndex, internalId, avgLen);
|
|
4754
|
-
const termScore = scoresAreZero ? 0 : computeBM25WithIDF(termFrequencies[pi], idf, actualFieldLength, avgLen, k1, b);
|
|
4755
|
-
addScore(scoreBuffer, internalId, termScore * boosts[fieldIndex]);
|
|
4756
|
-
}
|
|
4757
|
-
continue;
|
|
4758
|
-
}
|
|
4759
|
-
for (let pi = 0; pi < count; pi++) {
|
|
4760
|
-
const internalId = docIds[pi];
|
|
4761
|
-
if (hasDeleted && deletedDocs.has(internalId)) continue;
|
|
4762
|
-
if (filterBitset && !bitsetHas(filterBitset, internalId)) continue;
|
|
4763
|
-
const fieldIndex = fieldNameIndices[pi];
|
|
4764
|
-
if (searchable[fieldIndex] === 0) continue;
|
|
4765
|
-
const termFrequency = termFrequencies[pi];
|
|
4766
|
-
const fieldBoost = boosts[fieldIndex];
|
|
4767
|
-
const avgLen = averageLengths[fieldIndex];
|
|
4768
|
-
const actualFieldLength = fieldLengthOf(lengthColumns, fieldIndex, internalId, avgLen);
|
|
4769
|
-
let termScore = scoresAreZero ? 0 : computeBM25WithIDF(termFrequency, idf, actualFieldLength, avgLen, k1, b);
|
|
4770
|
-
termScore *= fieldBoost;
|
|
4771
|
-
addScore(scoreBuffer, internalId, termScore);
|
|
4772
|
-
if (components !== null) {
|
|
4773
|
-
recordComponents(
|
|
4774
|
-
components,
|
|
4775
|
-
internalId,
|
|
4776
|
-
fieldNames[fieldIndex],
|
|
4777
|
-
match.token,
|
|
4778
|
-
termFrequency,
|
|
4779
|
-
actualFieldLength,
|
|
4780
|
-
idf
|
|
4781
|
-
);
|
|
4782
|
-
}
|
|
4783
|
-
}
|
|
4344
|
+
const group = termGroupOf(termGroups, qt.token);
|
|
4345
|
+
for (const m of typoMatchesFor(state.invertedIdx, qt.token, group, exact, tolerance, prefixLength)) {
|
|
4346
|
+
scorePostings(resolveMatch(m.token, m.postingList), false);
|
|
4784
4347
|
}
|
|
4348
|
+
if (group !== void 0) scoreGroup(resolveGroupMatches(groupContext, group), false);
|
|
4785
4349
|
}
|
|
4786
4350
|
}
|
|
4787
4351
|
const totalMatched = scoreBuffer.touchedCount;
|
|
@@ -4931,7 +4495,7 @@ function encodeSegmentState(state) {
|
|
|
4931
4495
|
const postingOffsets = new Uint32Array(state.invertedIdx.size() + 1);
|
|
4932
4496
|
const postingDocIds = new Uint32Array(postings);
|
|
4933
4497
|
const postingFrequencies = new Uint16Array(postings);
|
|
4934
|
-
const postingFieldIndices = new
|
|
4498
|
+
const postingFieldIndices = new Uint16Array(postings);
|
|
4935
4499
|
const positionOffsets = hasPositions ? new Uint32Array(postings + 1) : null;
|
|
4936
4500
|
const positionValues = hasPositions ? new Uint32Array(positions) : null;
|
|
4937
4501
|
let postingCursor = 0;
|
|
@@ -4990,6 +4554,7 @@ function encodeSegmentState(state) {
|
|
|
4990
4554
|
totalFieldLengths: fieldLengths.totals,
|
|
4991
4555
|
docFrequencies,
|
|
4992
4556
|
surfaceForms: state.surfaceRegistry.size() === 0 ? null : state.surfaceRegistry.serialize(),
|
|
4557
|
+
partialSpellings: state.partialWords.spellings(),
|
|
4993
4558
|
...encodeFieldIndexes(state, remap)
|
|
4994
4559
|
};
|
|
4995
4560
|
}
|
|
@@ -5108,6 +4673,8 @@ function mergeSegmentPayload(target, payload, documents) {
|
|
|
5108
4673
|
target.surfaceRegistry.add(surface, value[1], value[0]);
|
|
5109
4674
|
}
|
|
5110
4675
|
}
|
|
4676
|
+
const mergedIds = Array.from({ length: payload.docIds.length }, (_, at) => ordinalBase + at);
|
|
4677
|
+
target.partialWords.afterMerge(payload.partialSpellings, mergedIds);
|
|
5111
4678
|
target.sortColumns = null;
|
|
5112
4679
|
target.scoreBuffer = null;
|
|
5113
4680
|
}
|
|
@@ -5397,179 +4964,7 @@ function deserializePartition(state, data, clearFn, schema) {
|
|
|
5397
4964
|
}
|
|
5398
4965
|
loadPatternIndexes(state, data.fieldIndexes.pattern, schema);
|
|
5399
4966
|
rebuildSizeIndexes(state, schema);
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
// src/core/partition/suggestions.ts
|
|
5403
|
-
function verbatimOccurrences(state, token) {
|
|
5404
|
-
const postingList = state.invertedIdx.lookup(token);
|
|
5405
|
-
if (!postingList) return 0;
|
|
5406
|
-
const derived = postingList.totalTermFrequency - state.surfaceRegistry.stemChangedTotalFor(token);
|
|
5407
|
-
return derived > 0 ? derived : 0;
|
|
5408
|
-
}
|
|
5409
|
-
function suggestDisplayTerms(state, surfacePrefix, stemmedPrefix, limit) {
|
|
5410
|
-
if (limit <= 0 || surfacePrefix.length === 0) return [];
|
|
5411
|
-
const groups = /* @__PURE__ */ new Map();
|
|
5412
|
-
for (const candidate of state.surfaceRegistry.candidatesForPrefix(surfacePrefix)) {
|
|
5413
|
-
const postingList = state.invertedIdx.lookup(candidate.token);
|
|
5414
|
-
if (!postingList || postingList.docIdSet.size === 0) continue;
|
|
5415
|
-
let group = groups.get(candidate.token);
|
|
5416
|
-
if (!group) {
|
|
5417
|
-
group = { documentFrequency: postingList.docIdSet.size, surfaces: [] };
|
|
5418
|
-
groups.set(candidate.token, group);
|
|
5419
|
-
}
|
|
5420
|
-
group.surfaces.push({ surface: candidate.surface, occurrences: candidate.occurrences });
|
|
5421
|
-
}
|
|
5422
|
-
const termPrefixes = state.surfaceRegistry.size() === 0 && stemmedPrefix !== surfacePrefix && stemmedPrefix.length > 0 ? [surfacePrefix, stemmedPrefix] : [surfacePrefix];
|
|
5423
|
-
for (const prefix of termPrefixes) {
|
|
5424
|
-
for (const suggestion of state.invertedIdx.prefixSearch(prefix, Number.MAX_SAFE_INTEGER)) {
|
|
5425
|
-
const occurrences = verbatimOccurrences(state, suggestion.term);
|
|
5426
|
-
if (occurrences === 0) continue;
|
|
5427
|
-
let group = groups.get(suggestion.term);
|
|
5428
|
-
if (!group) {
|
|
5429
|
-
group = { documentFrequency: suggestion.documentFrequency, surfaces: [] };
|
|
5430
|
-
groups.set(suggestion.term, group);
|
|
5431
|
-
} else if (group.surfaces.some((s) => s.surface === suggestion.term)) {
|
|
5432
|
-
continue;
|
|
5433
|
-
}
|
|
5434
|
-
group.surfaces.push({ surface: suggestion.term, occurrences });
|
|
5435
|
-
}
|
|
5436
|
-
}
|
|
5437
|
-
const results = [];
|
|
5438
|
-
for (const [token, group] of groups) {
|
|
5439
|
-
results.push({ token, documentFrequency: group.documentFrequency, surfaces: group.surfaces });
|
|
5440
|
-
}
|
|
5441
|
-
results.sort((a, b) => b.documentFrequency - a.documentFrequency || compareCodePoints(a.token, b.token));
|
|
5442
|
-
if (results.length > limit) results.length = limit;
|
|
5443
|
-
return results;
|
|
5444
|
-
}
|
|
5445
|
-
function expandTermPrefix(state, surfacePrefix, stemmedToken, maxExpansions) {
|
|
5446
|
-
if (maxExpansions <= 0 || surfacePrefix.length === 0) return [];
|
|
5447
|
-
const dfByToken = /* @__PURE__ */ new Map();
|
|
5448
|
-
for (const candidate of state.surfaceRegistry.candidatesForPrefix(surfacePrefix)) {
|
|
5449
|
-
if (dfByToken.has(candidate.token)) continue;
|
|
5450
|
-
const postingList = state.invertedIdx.lookup(candidate.token);
|
|
5451
|
-
if (!postingList || postingList.docIdSet.size === 0) continue;
|
|
5452
|
-
dfByToken.set(candidate.token, postingList.docIdSet.size);
|
|
5453
|
-
}
|
|
5454
|
-
const termPrefixes = state.surfaceRegistry.size() === 0 && stemmedToken !== surfacePrefix && stemmedToken.length > 0 ? [surfacePrefix, stemmedToken] : [surfacePrefix];
|
|
5455
|
-
for (const prefix of termPrefixes) {
|
|
5456
|
-
for (const suggestion of state.invertedIdx.prefixSearch(prefix, Number.MAX_SAFE_INTEGER)) {
|
|
5457
|
-
if (dfByToken.has(suggestion.term)) continue;
|
|
5458
|
-
if (verbatimOccurrences(state, suggestion.term) === 0) continue;
|
|
5459
|
-
dfByToken.set(suggestion.term, suggestion.documentFrequency);
|
|
5460
|
-
}
|
|
5461
|
-
}
|
|
5462
|
-
const entries = Array.from(dfByToken.entries());
|
|
5463
|
-
entries.sort((a, b) => b[1] - a[1] || compareCodePoints(a[0], b[0]));
|
|
5464
|
-
if (entries.length > maxExpansions) entries.length = maxExpansions;
|
|
5465
|
-
return entries.map((e) => e[0]);
|
|
5466
|
-
}
|
|
5467
|
-
|
|
5468
|
-
// src/core/partition/wire-payload.ts
|
|
5469
|
-
function serializePartitionToWirePayloadV2(state, partitionId, indexName, totalPartitions, language, schema) {
|
|
5470
|
-
const flatSchema = getFlatSchema(state, schema);
|
|
5471
|
-
const flatSchemaStrings = {};
|
|
5472
|
-
for (const [k, v] of Object.entries(flatSchema)) {
|
|
5473
|
-
flatSchemaStrings[k] = v;
|
|
5474
|
-
}
|
|
5475
|
-
const wireDocs = /* @__PURE__ */ Object.create(null);
|
|
5476
|
-
for (const [docId, stored] of state.docStore.all()) {
|
|
5477
|
-
wireDocs[docId] = {
|
|
5478
|
-
fields: stored.fields,
|
|
5479
|
-
field_lengths: { ...stored.fieldLengths }
|
|
5480
|
-
};
|
|
5481
|
-
}
|
|
5482
|
-
const resolver = state.docStore.resolver();
|
|
5483
|
-
const fieldNames = [...state.fieldNameTable.names];
|
|
5484
|
-
const wireEntries = /* @__PURE__ */ Object.create(null);
|
|
5485
|
-
for (const token of state.invertedIdx.tokens()) {
|
|
5486
|
-
const list = state.invertedIdx.lookup(token);
|
|
5487
|
-
if (!list) continue;
|
|
5488
|
-
const hasDeleted = list.deletedDocs.size > 0;
|
|
5489
|
-
const ids = [];
|
|
5490
|
-
const tf = [];
|
|
5491
|
-
const fi = new Uint8Array(list.length);
|
|
5492
|
-
const pos = list.positions ? [] : null;
|
|
5493
|
-
let writeIdx = 0;
|
|
5494
|
-
for (let i = 0; i < list.length; i++) {
|
|
5495
|
-
if (hasDeleted && list.deletedDocs.has(list.docIds[i])) continue;
|
|
5496
|
-
const externalId = resolver.toExternal(list.docIds[i]);
|
|
5497
|
-
if (externalId === void 0) continue;
|
|
5498
|
-
ids.push(externalId);
|
|
5499
|
-
tf.push(list.termFrequencies[i]);
|
|
5500
|
-
fi[writeIdx] = list.fieldNameIndices[i];
|
|
5501
|
-
writeIdx++;
|
|
5502
|
-
if (pos && list.positions) {
|
|
5503
|
-
pos.push(list.positions[i]);
|
|
5504
|
-
}
|
|
5505
|
-
}
|
|
5506
|
-
if (ids.length > 0) {
|
|
5507
|
-
const finalFi = writeIdx < list.length ? fi.subarray(0, writeIdx) : fi;
|
|
5508
|
-
wireEntries[token] = { df: list.docIdSet.size, ids, tf, fi: finalFi, pos };
|
|
5509
|
-
}
|
|
5510
|
-
}
|
|
5511
|
-
const wireNumeric = {};
|
|
5512
|
-
for (const [path, idx] of state.numericIndexes) {
|
|
5513
|
-
wireNumeric[path] = idx.serialize().map((e) => ({
|
|
5514
|
-
value: e.value,
|
|
5515
|
-
doc_id: resolver.toExternal(e.docId) ?? ""
|
|
5516
|
-
}));
|
|
5517
|
-
}
|
|
5518
|
-
const wireBoolean = {};
|
|
5519
|
-
for (const [path, idx] of state.booleanIndexes) {
|
|
5520
|
-
const s = idx.serialize();
|
|
5521
|
-
wireBoolean[path] = {
|
|
5522
|
-
true_docs: s.trueDocs.map((id) => resolver.toExternal(id) ?? "").filter((id) => id !== ""),
|
|
5523
|
-
false_docs: s.falseDocs.map((id) => resolver.toExternal(id) ?? "").filter((id) => id !== "")
|
|
5524
|
-
};
|
|
5525
|
-
}
|
|
5526
|
-
const wireEnum = {};
|
|
5527
|
-
for (const [path, idx] of state.enumIndexes) {
|
|
5528
|
-
const raw = idx.serialize();
|
|
5529
|
-
const converted = /* @__PURE__ */ Object.create(null);
|
|
5530
|
-
for (const [value, internalIds] of Object.entries(raw)) {
|
|
5531
|
-
converted[value] = internalIds.map((id) => resolver.toExternal(id) ?? "").filter((id) => id !== "");
|
|
5532
|
-
}
|
|
5533
|
-
wireEnum[path] = converted;
|
|
5534
|
-
}
|
|
5535
|
-
const wireGeo = {};
|
|
5536
|
-
for (const [path, idx] of state.geoIndexes) {
|
|
5537
|
-
wireGeo[path] = idx.serialize().map((e) => ({
|
|
5538
|
-
lat: e.lat,
|
|
5539
|
-
lon: e.lon,
|
|
5540
|
-
doc_id: resolver.toExternal(e.docId) ?? ""
|
|
5541
|
-
}));
|
|
5542
|
-
}
|
|
5543
|
-
const serializedStats = state.stats.serialize();
|
|
5544
|
-
return {
|
|
5545
|
-
v: 2,
|
|
5546
|
-
index_name: indexName,
|
|
5547
|
-
partition_id: partitionId,
|
|
5548
|
-
total_partitions: totalPartitions,
|
|
5549
|
-
language,
|
|
5550
|
-
schema: flatSchemaStrings,
|
|
5551
|
-
doc_count: state.docStore.count(),
|
|
5552
|
-
avg_doc_length: Object.values(serializedStats.averageFieldLengths).reduce((sum, v) => sum + v, 0),
|
|
5553
|
-
documents: wireDocs,
|
|
5554
|
-
inverted_index: {
|
|
5555
|
-
field_names: fieldNames,
|
|
5556
|
-
entries: wireEntries
|
|
5557
|
-
},
|
|
5558
|
-
field_indexes: {
|
|
5559
|
-
numeric: wireNumeric,
|
|
5560
|
-
boolean: wireBoolean,
|
|
5561
|
-
enum: wireEnum,
|
|
5562
|
-
geopoint: wireGeo,
|
|
5563
|
-
...patternIndexesToWire(serializePatternIndexes(state, schema))
|
|
5564
|
-
},
|
|
5565
|
-
surface_forms: state.surfaceRegistry.serialize(),
|
|
5566
|
-
statistics: {
|
|
5567
|
-
total_documents: serializedStats.totalDocuments,
|
|
5568
|
-
total_field_lengths: serializedStats.totalFieldLengths,
|
|
5569
|
-
average_field_lengths: serializedStats.averageFieldLengths,
|
|
5570
|
-
doc_frequencies: serializedStats.docFrequencies
|
|
5571
|
-
}
|
|
5572
|
-
};
|
|
4967
|
+
state.partialWords.forgetSpellings();
|
|
5573
4968
|
}
|
|
5574
4969
|
|
|
5575
4970
|
// src/core/partition/index.ts
|
|
@@ -5586,9 +4981,10 @@ function partitionStateOf(partition) {
|
|
|
5586
4981
|
}
|
|
5587
4982
|
function createPartitionIndex(partitionId, trackPositions = true) {
|
|
5588
4983
|
const fieldNameTable = { names: [], indexMap: /* @__PURE__ */ new Map() };
|
|
4984
|
+
const docStore = createDocumentStore();
|
|
5589
4985
|
const state = {
|
|
5590
4986
|
invertedIdx: createInvertedIndex(fieldNameTable),
|
|
5591
|
-
docStore
|
|
4987
|
+
docStore,
|
|
5592
4988
|
stats: createPartitionStats(),
|
|
5593
4989
|
surfaceRegistry: createSurfaceRegistry(),
|
|
5594
4990
|
numericIndexes: /* @__PURE__ */ new Map(),
|
|
@@ -5598,6 +4994,7 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5598
4994
|
patternIndexes: /* @__PURE__ */ new Map(),
|
|
5599
4995
|
sizeIndexes: /* @__PURE__ */ new Map(),
|
|
5600
4996
|
fieldNameTable,
|
|
4997
|
+
partialWords: createGrowingPartialWords({ docStore }),
|
|
5601
4998
|
flatSchemaCache: null,
|
|
5602
4999
|
lastSchemaRef: null,
|
|
5603
5000
|
trackPositions,
|
|
@@ -5618,6 +5015,7 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5618
5015
|
state.geoIndexes.clear();
|
|
5619
5016
|
state.patternIndexes.clear();
|
|
5620
5017
|
state.sizeIndexes.clear();
|
|
5018
|
+
state.partialWords.clear();
|
|
5621
5019
|
state.stats.deserialize({ totalDocuments: 0, totalFieldLengths: {}, averageFieldLengths: {}, docFrequencies: {} });
|
|
5622
5020
|
state.flatSchemaCache = null;
|
|
5623
5021
|
state.lastSchemaRef = null;
|
|
@@ -5646,7 +5044,7 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5646
5044
|
}
|
|
5647
5045
|
}
|
|
5648
5046
|
const internalId = state.docStore.ensureInternalId(docId);
|
|
5649
|
-
const { fieldLengths, tokensByField } = indexDocument(
|
|
5047
|
+
const { fieldLengths, tokensByField, partialSpellings } = indexDocument(
|
|
5650
5048
|
state,
|
|
5651
5049
|
docId,
|
|
5652
5050
|
document,
|
|
@@ -5660,6 +5058,7 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5660
5058
|
state.docStore.store(docId, document, fieldLengths);
|
|
5661
5059
|
}
|
|
5662
5060
|
state.stats.addDocument(fieldLengths, tokensByField);
|
|
5061
|
+
state.partialWords.afterDocument(partialFieldsOf(schema), internalId, partialSpellings, 1);
|
|
5663
5062
|
recordSortValues(state, internalId, document);
|
|
5664
5063
|
},
|
|
5665
5064
|
remove(docId, schema, language, options) {
|
|
@@ -5670,7 +5069,7 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5670
5069
|
partitionId
|
|
5671
5070
|
});
|
|
5672
5071
|
}
|
|
5673
|
-
const { fieldLengths, tokensByField } = removeFromIndexes(
|
|
5072
|
+
const { fieldLengths, tokensByField, partialSpellings } = removeFromIndexes(
|
|
5674
5073
|
state,
|
|
5675
5074
|
docId,
|
|
5676
5075
|
stored,
|
|
@@ -5681,6 +5080,9 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5681
5080
|
const internalId = state.docStore.getInternalId(docId);
|
|
5682
5081
|
state.docStore.remove(docId);
|
|
5683
5082
|
state.stats.removeDocument(fieldLengths, tokensByField);
|
|
5083
|
+
if (internalId !== void 0) {
|
|
5084
|
+
state.partialWords.afterDocument(partialFieldsOf(schema), internalId, partialSpellings, -1);
|
|
5085
|
+
}
|
|
5684
5086
|
forgetSortValues(state, internalId);
|
|
5685
5087
|
},
|
|
5686
5088
|
beginBatch() {
|
|
@@ -5716,29 +5118,19 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5716
5118
|
const fields = schemaFieldsOf(schema);
|
|
5717
5119
|
const needsTextReindex = textFieldsChanged(stored.fields, document, fields);
|
|
5718
5120
|
if (needsTextReindex) {
|
|
5719
|
-
const
|
|
5720
|
-
|
|
5721
|
-
docId,
|
|
5722
|
-
stored,
|
|
5723
|
-
fields,
|
|
5724
|
-
language,
|
|
5725
|
-
options
|
|
5726
|
-
);
|
|
5727
|
-
state.stats.removeDocument(oldFieldLengths, oldTokens);
|
|
5121
|
+
const previous = removeFromIndexes(state, docId, stored, fields, language, options);
|
|
5122
|
+
state.stats.removeDocument(previous.fieldLengths, previous.tokensByField);
|
|
5728
5123
|
const previousInternalId = state.docStore.getInternalId(docId);
|
|
5124
|
+
if (previousInternalId !== void 0) {
|
|
5125
|
+
state.partialWords.afterDocument(partialFieldsOf(schema), previousInternalId, previous.partialSpellings, -1);
|
|
5126
|
+
}
|
|
5729
5127
|
state.docStore.remove(docId);
|
|
5730
5128
|
forgetSortValues(state, previousInternalId);
|
|
5731
5129
|
const internalId = state.docStore.ensureInternalId(docId);
|
|
5732
|
-
const
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
fields,
|
|
5737
|
-
language,
|
|
5738
|
-
options
|
|
5739
|
-
);
|
|
5740
|
-
state.docStore.store(docId, document, newFieldLengths);
|
|
5741
|
-
state.stats.addDocument(newFieldLengths, newTokens);
|
|
5130
|
+
const next = indexDocument(state, docId, document, fields, language, options);
|
|
5131
|
+
state.docStore.store(docId, document, next.fieldLengths);
|
|
5132
|
+
state.stats.addDocument(next.fieldLengths, next.tokensByField);
|
|
5133
|
+
state.partialWords.afterDocument(partialFieldsOf(schema), internalId, next.partialSpellings, 1);
|
|
5742
5134
|
recordSortValues(state, internalId, document);
|
|
5743
5135
|
} else {
|
|
5744
5136
|
updateFieldIndexOnly(state, docId, stored.fields, document, fields);
|
|
@@ -5809,15 +5201,17 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
5809
5201
|
return suggestDisplayTerms(state, surfacePrefix, stemmedPrefix, limit);
|
|
5810
5202
|
},
|
|
5811
5203
|
expandTermPrefix(surfacePrefix, stemmedToken, maxExpansions) {
|
|
5812
|
-
return expandTermPrefix(state, surfacePrefix, stemmedToken, maxExpansions);
|
|
5204
|
+
return expandTermPrefix([state], surfacePrefix, stemmedToken, maxExpansions);
|
|
5205
|
+
},
|
|
5206
|
+
expandPartialWords(analysis, requests) {
|
|
5207
|
+
return expandPartialWords([state], analysis, requests);
|
|
5208
|
+
},
|
|
5209
|
+
preparePartialWords(analysis) {
|
|
5210
|
+
expandPartialWords([state], analysis, []);
|
|
5813
5211
|
},
|
|
5814
5212
|
serialize(indexName, totalPartitions, language, schema) {
|
|
5815
5213
|
return serializePartition(state, partitionId, indexName, totalPartitions, language, schema);
|
|
5816
5214
|
},
|
|
5817
|
-
serializeToBytes(indexName, totalPartitions, language, schema) {
|
|
5818
|
-
const wire = serializePartitionToWirePayloadV2(state, partitionId, indexName, totalPartitions, language, schema);
|
|
5819
|
-
return encodeRawPayloadV2(wire);
|
|
5820
|
-
},
|
|
5821
5215
|
deserialize(data, schema) {
|
|
5822
5216
|
deserializePartition(state, data, clearAll, schema);
|
|
5823
5217
|
}
|
|
@@ -5847,7 +5241,7 @@ function frozenSegmentBytes(segment) {
|
|
|
5847
5241
|
bytes += entry.docIds.byteLength + entry.latitudes.byteLength + entry.longitudes.byteLength;
|
|
5848
5242
|
}
|
|
5849
5243
|
for (const reader of segment.patternIndexes.values()) bytes += reader.bytes();
|
|
5850
|
-
return bytes;
|
|
5244
|
+
return bytes + segment.partialWords.bytes();
|
|
5851
5245
|
}
|
|
5852
5246
|
|
|
5853
5247
|
// src/core/partition/composite/compaction.ts
|
|
@@ -5982,20 +5376,19 @@ function subMatchesView(matches, layout, subIndex) {
|
|
|
5982
5376
|
|
|
5983
5377
|
// src/core/partition/composite/stats.ts
|
|
5984
5378
|
function collectCandidateTerms(subs, params) {
|
|
5985
|
-
const { queryTokens,
|
|
5379
|
+
const { queryTokens, termGroups, tolerance = 0, prefixLength = 2, exact = false } = params;
|
|
5986
5380
|
const terms = /* @__PURE__ */ new Set();
|
|
5987
5381
|
for (const qt of queryTokens) {
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
for (const
|
|
5991
|
-
continue;
|
|
5382
|
+
const group = termGroupOf(termGroups, qt.token);
|
|
5383
|
+
if (group !== void 0) {
|
|
5384
|
+
for (const member of group.members) terms.add(member.token);
|
|
5992
5385
|
}
|
|
5993
|
-
if (exact || tolerance === 0) {
|
|
5386
|
+
if (group === void 0 && (exact || tolerance === 0)) {
|
|
5994
5387
|
terms.add(qt.token);
|
|
5995
5388
|
continue;
|
|
5996
5389
|
}
|
|
5997
5390
|
for (const sub of subs) {
|
|
5998
|
-
for (const match of sub.invertedIdx
|
|
5391
|
+
for (const match of typoMatchesFor(sub.invertedIdx, qt.token, group, exact, tolerance, prefixLength)) {
|
|
5999
5392
|
terms.add(match.token);
|
|
6000
5393
|
}
|
|
6001
5394
|
}
|
|
@@ -6005,11 +5398,7 @@ function collectCandidateTerms(subs, params) {
|
|
|
6005
5398
|
function resolveQueryTermFrequencies(subs, params) {
|
|
6006
5399
|
const frequencies = /* @__PURE__ */ Object.create(null);
|
|
6007
5400
|
for (const term of collectCandidateTerms(subs, params)) {
|
|
6008
|
-
|
|
6009
|
-
for (const sub of subs) {
|
|
6010
|
-
const list = sub.invertedIdx.lookup(term);
|
|
6011
|
-
if (list !== void 0) total += list.docIdSet.size;
|
|
6012
|
-
}
|
|
5401
|
+
const total = partitionDocumentFrequency(subs, term);
|
|
6013
5402
|
if (total > 0) frequencies[term] = total;
|
|
6014
5403
|
}
|
|
6015
5404
|
return frequencies;
|
|
@@ -6195,9 +5584,10 @@ function compositeSortValues(subs, docId, fields, fieldTypes, modes) {
|
|
|
6195
5584
|
|
|
6196
5585
|
// src/core/partition/composite/suggest.ts
|
|
6197
5586
|
function compositeSuggestTerms(subs, surfacePrefix, stemmedPrefix, limit) {
|
|
5587
|
+
if (limit <= 0) return [];
|
|
6198
5588
|
const merged = /* @__PURE__ */ new Map();
|
|
6199
5589
|
for (const sub of subs) {
|
|
6200
|
-
for (const suggestion of suggestDisplayTerms(sub, surfacePrefix, stemmedPrefix,
|
|
5590
|
+
for (const suggestion of suggestDisplayTerms(sub, surfacePrefix, stemmedPrefix, Number.MAX_SAFE_INTEGER)) {
|
|
6201
5591
|
let entry = merged.get(suggestion.token);
|
|
6202
5592
|
if (entry === void 0) {
|
|
6203
5593
|
entry = { documentFrequency: 0, surfaceOccurrences: /* @__PURE__ */ new Map() };
|
|
@@ -6222,19 +5612,6 @@ function compositeSuggestTerms(subs, surfacePrefix, stemmedPrefix, limit) {
|
|
|
6222
5612
|
if (suggestions.length > limit) suggestions.length = limit;
|
|
6223
5613
|
return suggestions;
|
|
6224
5614
|
}
|
|
6225
|
-
function compositeExpandTermPrefix(subs, surfacePrefix, stemmedToken, maxExpansions) {
|
|
6226
|
-
const expansions = [];
|
|
6227
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6228
|
-
for (const sub of subs) {
|
|
6229
|
-
for (const term of expandTermPrefix(sub, surfacePrefix, stemmedToken, maxExpansions)) {
|
|
6230
|
-
if (seen.has(term)) continue;
|
|
6231
|
-
seen.add(term);
|
|
6232
|
-
expansions.push(term);
|
|
6233
|
-
if (expansions.length === maxExpansions) return expansions;
|
|
6234
|
-
}
|
|
6235
|
-
}
|
|
6236
|
-
return expansions;
|
|
6237
|
-
}
|
|
6238
5615
|
|
|
6239
5616
|
// src/core/partition/composite/index.ts
|
|
6240
5617
|
function isCompositePartition(partition) {
|
|
@@ -6340,10 +5717,6 @@ function createCompositePartition(partitionId, trackPositions = true, existingLi
|
|
|
6340
5717
|
if (frozen.length === 0) return live.serialize(indexName, totalPartitions, language, schema);
|
|
6341
5718
|
return composedScratch().serialize(indexName, totalPartitions, language, schema);
|
|
6342
5719
|
},
|
|
6343
|
-
serializeToBytes(indexName, totalPartitions, language, schema) {
|
|
6344
|
-
if (frozen.length === 0) return live.serializeToBytes(indexName, totalPartitions, language, schema);
|
|
6345
|
-
return composedScratch().serializeToBytes(indexName, totalPartitions, language, schema);
|
|
6346
|
-
},
|
|
6347
5720
|
deserialize(data, schema) {
|
|
6348
5721
|
frozen.length = 0;
|
|
6349
5722
|
invalidateDocFrequencies();
|
|
@@ -6442,7 +5815,13 @@ function createCompositePartition(partitionId, trackPositions = true, existingLi
|
|
|
6442
5815
|
return compositeSuggestTerms(subs(), surfacePrefix, stemmedPrefix, limit);
|
|
6443
5816
|
},
|
|
6444
5817
|
expandTermPrefix(surfacePrefix, stemmedToken, maxExpansions) {
|
|
6445
|
-
return
|
|
5818
|
+
return expandTermPrefix(subs(), surfacePrefix, stemmedToken, maxExpansions);
|
|
5819
|
+
},
|
|
5820
|
+
expandPartialWords(analysis, requests) {
|
|
5821
|
+
return expandPartialWords(subs(), analysis, requests);
|
|
5822
|
+
},
|
|
5823
|
+
preparePartialWords(analysis) {
|
|
5824
|
+
expandPartialWords(subs(), analysis, []);
|
|
6446
5825
|
},
|
|
6447
5826
|
get(docId, projection) {
|
|
6448
5827
|
const owner = frozenOwner(docId);
|
|
@@ -6503,6 +5882,11 @@ function createCompositePartition(partitionId, trackPositions = true, existingLi
|
|
|
6503
5882
|
}
|
|
6504
5883
|
|
|
6505
5884
|
// src/partitioning/insert-options.ts
|
|
5885
|
+
function resolvePartialWordAnalysis(config, language, analysis) {
|
|
5886
|
+
const fields = partialFieldsOf(config.schema);
|
|
5887
|
+
if (fields.length === 0) return null;
|
|
5888
|
+
return { fields, language, options: resolvePartitionInsertOptions(config, analysis) };
|
|
5889
|
+
}
|
|
6506
5890
|
function resolvePartitionInsertOptions(config, analysis, options) {
|
|
6507
5891
|
const applyStrict = config.strict === true;
|
|
6508
5892
|
const applyAnalyzer = analysis.stopWords !== void 0 || analysis.customTokenizer !== void 0;
|
|
@@ -6561,8 +5945,10 @@ function createCapacityChecks(source) {
|
|
|
6561
5945
|
// src/partitioning/manager/index.ts
|
|
6562
5946
|
function createPartitionManager(indexName, config, language, router, initialPartitionCount, vectorIndexes) {
|
|
6563
5947
|
requirePatternSearchFor(config.schema);
|
|
5948
|
+
requirePartialWordSearchFor(config.schema);
|
|
6564
5949
|
const count = initialPartitionCount ?? 1;
|
|
6565
5950
|
const analysis = resolveIndexAnalysis(config);
|
|
5951
|
+
const partialWordAnalysis = resolvePartialWordAnalysis(config, language, analysis);
|
|
6566
5952
|
const trackPositions = config.trackPositions ?? true;
|
|
6567
5953
|
const vecIndexes = vectorIndexes ?? /* @__PURE__ */ new Map();
|
|
6568
5954
|
let partitions = [];
|
|
@@ -6582,6 +5968,9 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
6582
5968
|
function resolveInsertOptions(options) {
|
|
6583
5969
|
return resolvePartitionInsertOptions(config, analysis, options);
|
|
6584
5970
|
}
|
|
5971
|
+
function preparePartialWords(partitionId) {
|
|
5972
|
+
if (partialWordAnalysis !== null) partitions[partitionId].preparePartialWords(partialWordAnalysis);
|
|
5973
|
+
}
|
|
6585
5974
|
function locateDocument(docId) {
|
|
6586
5975
|
return docPartitionMap.get(docId);
|
|
6587
5976
|
}
|
|
@@ -6637,6 +6026,9 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
6637
6026
|
get analysis() {
|
|
6638
6027
|
return analysis;
|
|
6639
6028
|
},
|
|
6029
|
+
get partialWordAnalysis() {
|
|
6030
|
+
return partialWordAnalysis;
|
|
6031
|
+
},
|
|
6640
6032
|
getPartition(partitionId) {
|
|
6641
6033
|
validatePartitionId(partitionId);
|
|
6642
6034
|
return partitions[partitionId];
|
|
@@ -6713,6 +6105,7 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
6713
6105
|
rebuildTextIndex(partitionId) {
|
|
6714
6106
|
validatePartitionId(partitionId);
|
|
6715
6107
|
partitions[partitionId].rebuildTextIndex(config.schema, language, resolveInsertOptions());
|
|
6108
|
+
preparePartialWords(partitionId);
|
|
6716
6109
|
},
|
|
6717
6110
|
beginBatchRemove() {
|
|
6718
6111
|
for (let i = 0; i < partitions.length; i++) {
|
|
@@ -6774,10 +6167,6 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
6774
6167
|
validatePartitionId(partitionId);
|
|
6775
6168
|
return partitions[partitionId].serialize(indexName, partitions.length, language.name, config.schema);
|
|
6776
6169
|
},
|
|
6777
|
-
serializePartitionToBytes(partitionId) {
|
|
6778
|
-
validatePartitionId(partitionId);
|
|
6779
|
-
return partitions[partitionId].serializeToBytes(indexName, partitions.length, language.name, config.schema);
|
|
6780
|
-
},
|
|
6781
6170
|
mergeSegment(partitionId, payload, documents) {
|
|
6782
6171
|
validatePartitionId(partitionId);
|
|
6783
6172
|
const partition = partitions[partitionId];
|
|
@@ -6818,6 +6207,7 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
6818
6207
|
deserializePartition(partitionId, data) {
|
|
6819
6208
|
validatePartitionId(partitionId);
|
|
6820
6209
|
partitions[partitionId].deserialize(data, config.schema);
|
|
6210
|
+
preparePartialWords(partitionId);
|
|
6821
6211
|
rebuildDocPartitionMapForPartition(partitionId);
|
|
6822
6212
|
},
|
|
6823
6213
|
getAggregateStats() {
|
|
@@ -6903,6 +6293,9 @@ var WORKER_COPY_MIN_VECTORS = 1024;
|
|
|
6903
6293
|
var BUILD_CHUNK_SIZE = 100;
|
|
6904
6294
|
var REBUILD_REMOVED_RATIO = 0.2;
|
|
6905
6295
|
var VECTOR_FILE_REPLACED_ABOVE_DEAD_SHARE = 0.2;
|
|
6296
|
+
var VECTOR_FILE_FIXED_OVERHEAD_BYTES = 65536;
|
|
6297
|
+
var VECTOR_FILE_STRING_HEADER_BYTES = 5;
|
|
6298
|
+
var VECTOR_FILE_CENTROID_BYTES_PER_COMPONENT = 9;
|
|
6906
6299
|
var OSQ4_MIN_DIMENSION = 384;
|
|
6907
6300
|
var DISK_ADOPTION_YIELD_INTERVAL = 4096;
|
|
6908
6301
|
|
|
@@ -6962,7 +6355,7 @@ function yieldToEventLoop() {
|
|
|
6962
6355
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
6963
6356
|
}
|
|
6964
6357
|
function* allLiveDocIds(state) {
|
|
6965
|
-
for (const
|
|
6358
|
+
for (const docId of state.store.docIds()) {
|
|
6966
6359
|
if (state.tombstones.has(docId)) continue;
|
|
6967
6360
|
yield docId;
|
|
6968
6361
|
}
|
|
@@ -7083,14 +6476,6 @@ async function nodeThreadId() {
|
|
|
7083
6476
|
return 0;
|
|
7084
6477
|
}
|
|
7085
6478
|
}
|
|
7086
|
-
async function isNodeMainThread() {
|
|
7087
|
-
try {
|
|
7088
|
-
const workerThreads = await import('worker_threads');
|
|
7089
|
-
return workerThreads.isMainThread;
|
|
7090
|
-
} catch {
|
|
7091
|
-
return true;
|
|
7092
|
-
}
|
|
7093
|
-
}
|
|
7094
6479
|
|
|
7095
6480
|
// src/workers/entry-point.ts
|
|
7096
6481
|
var DIST_SEGMENT = "/dist/";
|
|
@@ -7855,6 +7240,12 @@ function scheduleBuild(state) {
|
|
|
7855
7240
|
}, 0);
|
|
7856
7241
|
}
|
|
7857
7242
|
|
|
7243
|
+
// src/serialization/constants.ts
|
|
7244
|
+
var CHECKSUM_YIELD_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
7245
|
+
var NATIVE_CRC32_MIN_BYTES = 16;
|
|
7246
|
+
var MAX_FILE_BYTES = 2147483647;
|
|
7247
|
+
var VALID_HNSW_METRICS = /* @__PURE__ */ new Set(["cosine", "dotProduct", "euclidean"]);
|
|
7248
|
+
|
|
7858
7249
|
// src/vector/vector-index/payload.ts
|
|
7859
7250
|
var VECTOR_INDEX_PAYLOAD_VERSION = 3;
|
|
7860
7251
|
var VECTOR_INDEX_PART_VECTORS = 65536;
|
|
@@ -7881,7 +7272,7 @@ function invalid(message, details) {
|
|
|
7881
7272
|
function isRecord(value) {
|
|
7882
7273
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7883
7274
|
}
|
|
7884
|
-
function
|
|
7275
|
+
function isNonNegativeInteger(value) {
|
|
7885
7276
|
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
7886
7277
|
}
|
|
7887
7278
|
function isSerializedGraph(value) {
|
|
@@ -7911,9 +7302,9 @@ function decodeVectorIndexPart(raw) {
|
|
|
7911
7302
|
);
|
|
7912
7303
|
}
|
|
7913
7304
|
if (typeof raw.fieldName !== "string") invalid("fieldName must be a string");
|
|
7914
|
-
if (!
|
|
7915
|
-
if (!
|
|
7916
|
-
if (!
|
|
7305
|
+
if (!isNonNegativeInteger(raw.dimension) || raw.dimension === 0) invalid("dimension must be a positive integer");
|
|
7306
|
+
if (!isNonNegativeInteger(raw.part)) invalid("part must be a non-negative integer");
|
|
7307
|
+
if (!isNonNegativeInteger(raw.parts) || raw.parts === 0 || raw.part >= raw.parts) {
|
|
7917
7308
|
invalid("parts must exceed part", { part: raw.part, parts: raw.parts });
|
|
7918
7309
|
}
|
|
7919
7310
|
if (!Array.isArray(raw.docIds) || !raw.docIds.every((docId) => typeof docId === "string")) {
|
|
@@ -7952,6 +7343,8 @@ function decodeVectorIndexParts(raw) {
|
|
|
7952
7343
|
// src/vector/vector-index/checkpoint-payload.ts
|
|
7953
7344
|
var VECTOR_FILE_PAYLOAD_VERSION = 1;
|
|
7954
7345
|
var VECTOR_GRAPH_PAYLOAD_VERSION = 1;
|
|
7346
|
+
var VECTOR_GRAPH_PART_PAYLOAD_VERSION = 2;
|
|
7347
|
+
var VECTOR_GRAPH_PART_VECTORS = 16384;
|
|
7955
7348
|
var VECTOR_FILE_MAX_VECTORS = VECTOR_INDEX_PART_VECTORS;
|
|
7956
7349
|
var METRICS = ["cosine", "dotProduct", "euclidean"];
|
|
7957
7350
|
function invalid2(payload, message, details) {
|
|
@@ -8002,14 +7395,16 @@ function decodeVectorFilePayload(raw) {
|
|
|
8002
7395
|
function isMetric(value) {
|
|
8003
7396
|
return METRICS.some((metric) => metric === value);
|
|
8004
7397
|
}
|
|
8005
|
-
function decodeNumberedGraph(raw) {
|
|
7398
|
+
function decodeNumberedGraph(raw, minimumM) {
|
|
8006
7399
|
const name = "vector graph";
|
|
8007
7400
|
if (!isRecord2(raw)) invalid2(name, "each graph must be a map");
|
|
8008
7401
|
const entryPoint = raw.entryPoint ?? null;
|
|
8009
7402
|
if (entryPoint !== null && !isIntegerUpTo(entryPoint, 4294967295))
|
|
8010
7403
|
invalid2(name, "entryPoint must be a uint32 or nil");
|
|
8011
7404
|
if (!isIntegerUpTo(raw.maxLayer, 255)) invalid2(name, "maxLayer must be a uint8");
|
|
8012
|
-
if (!isIntegerUpTo(raw.m,
|
|
7405
|
+
if (!isIntegerUpTo(raw.m, MAX_M) || raw.m < minimumM) {
|
|
7406
|
+
invalid2(name, `m must be a whole number from ${minimumM} to ${MAX_M}`);
|
|
7407
|
+
}
|
|
8013
7408
|
if (!isIntegerUpTo(raw.efConstruction, 65535)) invalid2(name, "efConstruction must be a uint16");
|
|
8014
7409
|
if (!isMetric(raw.metric)) invalid2(name, "metric must name a supported metric", { metric: raw.metric });
|
|
8015
7410
|
if (!(raw.levels instanceof Uint8Array)) invalid2(name, "levels must be bytes");
|
|
@@ -8030,7 +7425,56 @@ function decodeVectorGraphPayload(raw) {
|
|
|
8030
7425
|
requireVersion(name, raw.v, VECTOR_GRAPH_PAYLOAD_VERSION);
|
|
8031
7426
|
if (typeof raw.fieldName !== "string") invalid2(name, "fieldName must be a string");
|
|
8032
7427
|
if (!Array.isArray(raw.graphs)) invalid2(name, "graphs must be a list");
|
|
8033
|
-
return {
|
|
7428
|
+
return {
|
|
7429
|
+
v: VECTOR_GRAPH_PAYLOAD_VERSION,
|
|
7430
|
+
fieldName: raw.fieldName,
|
|
7431
|
+
graphs: raw.graphs.map((graph) => decodeNumberedGraph(graph, EARLIER_RELEASE_MIN_M))
|
|
7432
|
+
};
|
|
7433
|
+
}
|
|
7434
|
+
function decodeVectorGraphPartPayload(raw) {
|
|
7435
|
+
const name = "vector graph part";
|
|
7436
|
+
if (!isRecord2(raw)) invalid2(name, "payload must be a map");
|
|
7437
|
+
requireVersion(name, raw.v, VECTOR_GRAPH_PART_PAYLOAD_VERSION);
|
|
7438
|
+
if (typeof raw.fieldName !== "string") invalid2(name, "fieldName must be a string");
|
|
7439
|
+
if (!Array.isArray(raw.graphs)) invalid2(name, "graphs must be a list");
|
|
7440
|
+
return {
|
|
7441
|
+
v: VECTOR_GRAPH_PART_PAYLOAD_VERSION,
|
|
7442
|
+
fieldName: raw.fieldName,
|
|
7443
|
+
graphs: raw.graphs.map((graph) => decodeNumberedGraph(graph, MIN_M))
|
|
7444
|
+
};
|
|
7445
|
+
}
|
|
7446
|
+
function sameGraphHeader(a, b) {
|
|
7447
|
+
return a.entryPoint === b.entryPoint && a.maxLayer === b.maxLayer && a.m === b.m && a.efConstruction === b.efConstruction && a.metric === b.metric;
|
|
7448
|
+
}
|
|
7449
|
+
function assembleGraphParts(parts) {
|
|
7450
|
+
const name = "vector graph part";
|
|
7451
|
+
const first = parts[0];
|
|
7452
|
+
if (first === void 0) invalid2(name, "a field that holds a graph must have at least one part");
|
|
7453
|
+
const partLists = first.graphs.map(() => []);
|
|
7454
|
+
for (let p = 0; p < parts.length; p++) {
|
|
7455
|
+
const part = parts[p];
|
|
7456
|
+
const isLast = p === parts.length - 1;
|
|
7457
|
+
if (part.fieldName !== first.fieldName || part.graphs.length !== first.graphs.length) {
|
|
7458
|
+
invalid2(name, `part ${p} lists other graphs than part 0`, { part: p });
|
|
7459
|
+
}
|
|
7460
|
+
for (let g = 0; g < part.graphs.length; g++) {
|
|
7461
|
+
const graph = part.graphs[g];
|
|
7462
|
+
if (!sameGraphHeader(graph, first.graphs[g]))
|
|
7463
|
+
invalid2(name, `part ${p} gives graph ${g} other headers`, { part: p });
|
|
7464
|
+
const levels = graph.levels.length;
|
|
7465
|
+
const fits = isLast ? levels >= 1 && levels <= VECTOR_GRAPH_PART_VECTORS : levels === VECTOR_GRAPH_PART_VECTORS;
|
|
7466
|
+
if (!fits) invalid2(name, `part ${p} gives graph ${g} ${levels} bytes of levels`, { part: p, levels });
|
|
7467
|
+
partLists[g].push(graph);
|
|
7468
|
+
}
|
|
7469
|
+
}
|
|
7470
|
+
const graphs = partLists.map((list) => ({ partSize: VECTOR_GRAPH_PART_VECTORS, parts: list }));
|
|
7471
|
+
return { fieldName: first.fieldName, graphs };
|
|
7472
|
+
}
|
|
7473
|
+
function graphPartsOfEarlierPayload(payload) {
|
|
7474
|
+
return {
|
|
7475
|
+
fieldName: payload.fieldName,
|
|
7476
|
+
graphs: payload.graphs.map((graph) => ({ partSize: Math.max(graph.levels.length, 1), parts: [graph] }))
|
|
7477
|
+
};
|
|
8034
7478
|
}
|
|
8035
7479
|
|
|
8036
7480
|
// src/vector/vector-index/dead-bits.ts
|
|
@@ -8060,36 +7504,6 @@ function deadBitsWhere(count, isDeadAt) {
|
|
|
8060
7504
|
}
|
|
8061
7505
|
|
|
8062
7506
|
// src/vector/vector-index/persistence.ts
|
|
8063
|
-
function liveDocIds(state) {
|
|
8064
|
-
const docIds = [];
|
|
8065
|
-
for (let ordinal = 0; ordinal < state.store.slots; ordinal++) {
|
|
8066
|
-
const docId = state.store.docIdForOrdinal(ordinal);
|
|
8067
|
-
if (docId === void 0 || state.tombstones.has(docId)) continue;
|
|
8068
|
-
docIds.push(docId);
|
|
8069
|
-
}
|
|
8070
|
-
return docIds;
|
|
8071
|
-
}
|
|
8072
|
-
function partVectors(state, docIds) {
|
|
8073
|
-
const dimension = state.dimension;
|
|
8074
|
-
const vectors = new Float32Array(docIds.length * dimension);
|
|
8075
|
-
for (let i = 0; i < docIds.length; i++) {
|
|
8076
|
-
const entry = state.store.get(docIds[i]);
|
|
8077
|
-
if (entry !== void 0) vectors.set(entry.vector, i * dimension);
|
|
8078
|
-
}
|
|
8079
|
-
return vectors;
|
|
8080
|
-
}
|
|
8081
|
-
function graphsPerPart(state, partOf, parts) {
|
|
8082
|
-
const sliced = Array.from({ length: parts }, () => []);
|
|
8083
|
-
if (state.hnsw === null || partOf.size === 0) return sliced;
|
|
8084
|
-
const graph = state.hnsw.serialize();
|
|
8085
|
-
const nodesPerPart = Array.from({ length: parts }, () => []);
|
|
8086
|
-
for (const node of graph.nodes) {
|
|
8087
|
-
const part = partOf.get(node[0]);
|
|
8088
|
-
if (part !== void 0) nodesPerPart[part].push(node);
|
|
8089
|
-
}
|
|
8090
|
-
for (let part = 0; part < parts; part++) sliced[part].push({ ...graph, nodes: nodesPerPart[part] });
|
|
8091
|
-
return sliced;
|
|
8092
|
-
}
|
|
8093
7507
|
function recordFor(state, quantizer, docId) {
|
|
8094
7508
|
const record = quantizer.recordOf(docId);
|
|
8095
7509
|
if (record !== void 0) return record;
|
|
@@ -8128,36 +7542,6 @@ function partCodes(state, docIds, centroid) {
|
|
|
8128
7542
|
}
|
|
8129
7543
|
return { bits: quantizer.bits, centroid, records };
|
|
8130
7544
|
}
|
|
8131
|
-
function planParts(state) {
|
|
8132
|
-
const docIds = liveDocIds(state);
|
|
8133
|
-
const parts = Math.max(1, Math.ceil(docIds.length / VECTOR_INDEX_PART_VECTORS));
|
|
8134
|
-
const partOf = /* @__PURE__ */ new Map();
|
|
8135
|
-
for (let i = 0; i < docIds.length; i++) partOf.set(docIds[i], Math.floor(i / VECTOR_INDEX_PART_VECTORS));
|
|
8136
|
-
const graphs = graphsPerPart(state, partOf, parts);
|
|
8137
|
-
const centroid = codedCentroid(state);
|
|
8138
|
-
return {
|
|
8139
|
-
parts,
|
|
8140
|
-
readPart(part) {
|
|
8141
|
-
const start = part * VECTOR_INDEX_PART_VECTORS;
|
|
8142
|
-
const slice = docIds.slice(start, start + VECTOR_INDEX_PART_VECTORS);
|
|
8143
|
-
return {
|
|
8144
|
-
v: VECTOR_INDEX_PAYLOAD_VERSION,
|
|
8145
|
-
fieldName: state.fieldName,
|
|
8146
|
-
dimension: state.dimension,
|
|
8147
|
-
part,
|
|
8148
|
-
parts,
|
|
8149
|
-
docIds: slice,
|
|
8150
|
-
graphs: graphs[part],
|
|
8151
|
-
codes: partCodes(state, slice, centroid),
|
|
8152
|
-
vectors: vectorsToBytes(partVectors(state, slice))
|
|
8153
|
-
};
|
|
8154
|
-
}
|
|
8155
|
-
};
|
|
8156
|
-
}
|
|
8157
|
-
function serialize(state) {
|
|
8158
|
-
const plan = planParts(state);
|
|
8159
|
-
return Array.from({ length: plan.parts }, (_, part) => plan.readPart(part));
|
|
8160
|
-
}
|
|
8161
7545
|
function splitSequences(parts) {
|
|
8162
7546
|
const sequences = [];
|
|
8163
7547
|
let current = null;
|
|
@@ -8210,7 +7594,7 @@ function restoreCodes(state, sequences) {
|
|
|
8210
7594
|
}
|
|
8211
7595
|
function restoreGraphs(state, graphs) {
|
|
8212
7596
|
if (graphs.length === 0) {
|
|
8213
|
-
for (const
|
|
7597
|
+
for (const docId of state.store.docIds()) {
|
|
8214
7598
|
if (!state.tombstones.has(docId)) state.buffer.add(docId);
|
|
8215
7599
|
}
|
|
8216
7600
|
return;
|
|
@@ -8233,14 +7617,14 @@ function restoreGraphs(state, graphs) {
|
|
|
8233
7617
|
if (!restoredHnsw.has(nodeDocId) && state.store.has(nodeDocId)) restoredHnsw.insertNode(nodeDocId);
|
|
8234
7618
|
}
|
|
8235
7619
|
}
|
|
8236
|
-
for (const
|
|
7620
|
+
for (const docId of state.store.docIds()) {
|
|
8237
7621
|
if (state.tombstones.has(docId)) continue;
|
|
8238
7622
|
if (!restoredHnsw.has(docId)) state.buffer.add(docId);
|
|
8239
7623
|
}
|
|
8240
7624
|
if (state.buffer.size > restoredHnsw.size) {
|
|
8241
7625
|
adoptGraph(state, null);
|
|
8242
7626
|
state.buffer.clear();
|
|
8243
|
-
for (const
|
|
7627
|
+
for (const docId of state.store.docIds()) {
|
|
8244
7628
|
if (!state.tombstones.has(docId)) state.buffer.add(docId);
|
|
8245
7629
|
}
|
|
8246
7630
|
}
|
|
@@ -8279,6 +7663,17 @@ function deserialize(state, parts) {
|
|
|
8279
7663
|
|
|
8280
7664
|
// src/vector/vector-index/checkpoint-plan.ts
|
|
8281
7665
|
var ORDINAL_HOLDS_NO_NUMBER = -1;
|
|
7666
|
+
function vectorsPerFile(dimension, codeBits) {
|
|
7667
|
+
const recordBytes = codeBits === 1 || codeBits === 2 || codeBits === 4 || codeBits === 8 ? osqRecordBytes(dimension, codeBits) : 0;
|
|
7668
|
+
const docIdBytes = VECTOR_FILE_STRING_HEADER_BYTES + MAX_DOC_ID_LENGTH * 3;
|
|
7669
|
+
const perVector = dimension * 4 + recordBytes + docIdBytes;
|
|
7670
|
+
const overhead = VECTOR_FILE_FIXED_OVERHEAD_BYTES + dimension * VECTOR_FILE_CENTROID_BYTES_PER_COMPONENT;
|
|
7671
|
+
const fitting = Math.floor((MAX_FILE_BYTES - overhead) / perVector);
|
|
7672
|
+
return Math.max(1, Math.min(VECTOR_FILE_MAX_VECTORS, fitting));
|
|
7673
|
+
}
|
|
7674
|
+
function fileCapacityOf(state) {
|
|
7675
|
+
return vectorsPerFile(state.dimension, osqBitsOf(state.quantizationMode));
|
|
7676
|
+
}
|
|
8282
7677
|
function calibrationOf(state) {
|
|
8283
7678
|
if (codedCentroid(state) === null) return null;
|
|
8284
7679
|
return Atomics.load(state.store.handles.header, STORE_CALIBRATION_GENERATION);
|
|
@@ -8318,10 +7713,10 @@ function filesWorthKeeping(state, listed, calibration, liveCounts) {
|
|
|
8318
7713
|
}
|
|
8319
7714
|
return kept;
|
|
8320
7715
|
}
|
|
8321
|
-
function absorbSmallerPartialFiles(kept, liveCounts, vectorsToWrite) {
|
|
7716
|
+
function absorbSmallerPartialFiles(kept, liveCounts, vectorsToWrite, capacity) {
|
|
8322
7717
|
let pending = vectorsToWrite;
|
|
8323
7718
|
for (let index = kept.length - 1; index >= 0 && pending > 0; index--) {
|
|
8324
|
-
if (kept[index].ordinals.length >=
|
|
7719
|
+
if (kept[index].ordinals.length >= capacity) continue;
|
|
8325
7720
|
if (liveCounts[index] > pending) return;
|
|
8326
7721
|
pending += liveCounts[index];
|
|
8327
7722
|
kept.splice(index, 1);
|
|
@@ -8369,13 +7764,14 @@ function numberEveryVector(state, kept, written) {
|
|
|
8369
7764
|
}
|
|
8370
7765
|
return { numberOfOrdinal, ordinalOfNumber };
|
|
8371
7766
|
}
|
|
8372
|
-
function
|
|
8373
|
-
if (state.hnsw === null) return null;
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
7767
|
+
function graphPartsOf(state, numbers) {
|
|
7768
|
+
if (state.hnsw === null || numbers.ordinalOfNumber.length === 0) return null;
|
|
7769
|
+
const parts = state.hnsw.serializeNumbered(
|
|
7770
|
+
numbers.numberOfOrdinal,
|
|
7771
|
+
numbers.ordinalOfNumber,
|
|
7772
|
+
VECTOR_GRAPH_PART_VECTORS
|
|
7773
|
+
);
|
|
7774
|
+
return parts.map((graph) => ({ v: VECTOR_GRAPH_PART_PAYLOAD_VERSION, fieldName: state.fieldName, graphs: [graph] }));
|
|
8379
7775
|
}
|
|
8380
7776
|
function readFile(state, planned, docIds, centroid) {
|
|
8381
7777
|
const dimension = state.dimension;
|
|
@@ -8400,18 +7796,19 @@ function readFile(state, planned, docIds, centroid) {
|
|
|
8400
7796
|
ordinals
|
|
8401
7797
|
};
|
|
8402
7798
|
}
|
|
8403
|
-
function planCheckpoint(state, listedKeys) {
|
|
7799
|
+
function planCheckpoint(state, listedKeys, rewritesGraph = false) {
|
|
8404
7800
|
const signature = signatureOf(state);
|
|
8405
7801
|
const calibration = signature.calibration;
|
|
8406
7802
|
const trusted = registryMatches(state, listedKeys);
|
|
7803
|
+
const capacity = fileCapacityOf(state);
|
|
8407
7804
|
const liveCounts = [];
|
|
8408
7805
|
const keptFiles = filesWorthKeeping(state, trusted ? state.savedFiles : [], calibration, liveCounts);
|
|
8409
|
-
absorbSmallerPartialFiles(keptFiles, liveCounts, countOutside(state, liveCounts));
|
|
7806
|
+
absorbSmallerPartialFiles(keptFiles, liveCounts, countOutside(state, liveCounts), capacity);
|
|
8410
7807
|
const written = ordinalsOutsideOf(state, keptFiles);
|
|
8411
7808
|
const writtenDocIds = written.map((ordinal) => state.store.docIdForOrdinal(ordinal) ?? "");
|
|
8412
7809
|
const centroid = codedCentroid(state);
|
|
8413
7810
|
const listedBefore = trusted && listedKeys !== null;
|
|
8414
|
-
const unchanged = listedBefore && sameSignature(state.savedSignature, signature) && written.length === 0;
|
|
7811
|
+
const unchanged = !rewritesGraph && listedBefore && sameSignature(state.savedSignature, signature) && written.length === 0;
|
|
8415
7812
|
return {
|
|
8416
7813
|
unchanged,
|
|
8417
7814
|
keptFiles,
|
|
@@ -8421,12 +7818,12 @@ function planCheckpoint(state, listedKeys) {
|
|
|
8421
7818
|
count: file.ordinals.length,
|
|
8422
7819
|
dead: deadBitsOf(state, file)
|
|
8423
7820
|
})),
|
|
8424
|
-
newFiles: Math.ceil(written.length /
|
|
8425
|
-
|
|
7821
|
+
newFiles: Math.ceil(written.length / capacity),
|
|
7822
|
+
graphParts: unchanged ? null : graphPartsOf(state, numberEveryVector(state, keptFiles, written)),
|
|
8426
7823
|
signature,
|
|
8427
7824
|
readNewFile(index) {
|
|
8428
|
-
const start = index *
|
|
8429
|
-
const end = start +
|
|
7825
|
+
const start = index * capacity;
|
|
7826
|
+
const end = start + capacity;
|
|
8430
7827
|
return readFile(state, written.slice(start, end), writtenDocIds.slice(start, end), centroid);
|
|
8431
7828
|
}
|
|
8432
7829
|
};
|
|
@@ -8446,13 +7843,22 @@ function sameCentroid2(a, b) {
|
|
|
8446
7843
|
return true;
|
|
8447
7844
|
}
|
|
8448
7845
|
function bufferEveryVectorOutsideTheGraph(state) {
|
|
8449
|
-
for (const
|
|
7846
|
+
for (const docId of state.store.docIds()) {
|
|
8450
7847
|
if (state.tombstones.has(docId)) continue;
|
|
8451
7848
|
if (state.hnsw === null || !state.hnsw.has(docId)) state.buffer.add(docId);
|
|
8452
7849
|
}
|
|
8453
7850
|
}
|
|
7851
|
+
function insertNodesOfLaterGraph(state, graph, later, ordinals) {
|
|
7852
|
+
for (const part of later.parts) requireWholeNeighbourLists(part);
|
|
7853
|
+
for (let number = 0; number < ordinals.length; number++) {
|
|
7854
|
+
const ordinal = ordinals[number];
|
|
7855
|
+
if (ordinal === NO_LIVE_VECTOR_AT_POSITION || topLayerInParts(later, number) < 0) continue;
|
|
7856
|
+
const docId = state.store.docIdForOrdinal(ordinal);
|
|
7857
|
+
if (docId !== void 0 && !graph.has(docId)) graph.insertOrdinal(ordinal);
|
|
7858
|
+
}
|
|
7859
|
+
}
|
|
8454
7860
|
function restoreGraph(state, payload, ordinalOfNumber) {
|
|
8455
|
-
const first = payload?.graphs[0];
|
|
7861
|
+
const first = payload?.graphs[0]?.parts[0];
|
|
8456
7862
|
if (payload === null || first === void 0) {
|
|
8457
7863
|
bufferEveryVectorOutsideTheGraph(state);
|
|
8458
7864
|
return;
|
|
@@ -8463,17 +7869,9 @@ function restoreGraph(state, payload, ordinalOfNumber) {
|
|
|
8463
7869
|
{ m: first.m, efConstruction: first.efConstruction, metric: first.metric },
|
|
8464
7870
|
state.osq ?? void 0
|
|
8465
7871
|
);
|
|
8466
|
-
graph.deserializeNumbered(
|
|
7872
|
+
graph.deserializeNumbered(payload.graphs[0], ordinalOfNumber);
|
|
8467
7873
|
adoptGraph(state, graph);
|
|
8468
|
-
for (const later of payload.graphs.slice(1))
|
|
8469
|
-
requireWholeNeighbourLists(later);
|
|
8470
|
-
for (let number = 0; number < later.levels.length && number < ordinalOfNumber.length; number++) {
|
|
8471
|
-
const ordinal = ordinalOfNumber[number];
|
|
8472
|
-
if (later.levels[number] === 0 || ordinal === NO_LIVE_VECTOR_AT_POSITION) continue;
|
|
8473
|
-
const docId = state.store.docIdForOrdinal(ordinal);
|
|
8474
|
-
if (docId !== void 0 && !graph.has(docId)) graph.insertOrdinal(ordinal);
|
|
8475
|
-
}
|
|
8476
|
-
}
|
|
7874
|
+
for (const later of payload.graphs.slice(1)) insertNodesOfLaterGraph(state, graph, later, ordinalOfNumber);
|
|
8477
7875
|
bufferEveryVectorOutsideTheGraph(state);
|
|
8478
7876
|
if (state.buffer.size <= graph.size) return;
|
|
8479
7877
|
adoptGraph(state, null);
|
|
@@ -9154,12 +8552,11 @@ function createVectorIndex(fieldName, dimension, config, workerCopies = VECTOR_W
|
|
|
9154
8552
|
},
|
|
9155
8553
|
maintenanceStatus: () => maintenanceStatus(state),
|
|
9156
8554
|
estimateMemoryBytes: () => estimateMemoryBytes(state),
|
|
9157
|
-
serialize: () => serialize(state),
|
|
9158
8555
|
deserialize: (parts) => {
|
|
9159
8556
|
invalidateWorkerCopies(state);
|
|
9160
8557
|
deserialize(state, parts);
|
|
9161
8558
|
},
|
|
9162
|
-
planCheckpoint: (listedKeys) => planCheckpoint(state, listedKeys),
|
|
8559
|
+
planCheckpoint: (listedKeys, rewritesGraph) => planCheckpoint(state, listedKeys, rewritesGraph),
|
|
9163
8560
|
recordCheckpoint: (plan, written) => recordCheckpoint(state, plan, written),
|
|
9164
8561
|
restoreCheckpoint: (shape) => {
|
|
9165
8562
|
invalidateWorkerCopies(state);
|
|
@@ -9277,11 +8674,55 @@ function createFrozenDocTable(idTable, lengthColumns, documents, tombstones) {
|
|
|
9277
8674
|
}
|
|
9278
8675
|
};
|
|
9279
8676
|
}
|
|
8677
|
+
function removeFieldAtPath(document, fieldPath) {
|
|
8678
|
+
const segments = fieldPath.split(".");
|
|
8679
|
+
let current = document;
|
|
8680
|
+
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
8681
|
+
const next = current[segments[i]];
|
|
8682
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) return;
|
|
8683
|
+
current = next;
|
|
8684
|
+
}
|
|
8685
|
+
delete current[segments[segments.length - 1]];
|
|
8686
|
+
}
|
|
8687
|
+
function decodeStoredDocument(bytes, discardedFields) {
|
|
8688
|
+
let decoded;
|
|
8689
|
+
try {
|
|
8690
|
+
decoded = decode(bytes);
|
|
8691
|
+
} catch (error) {
|
|
8692
|
+
throw new NarsilError(
|
|
8693
|
+
ErrorCodes.PERSISTENCE_LOAD_FAILED,
|
|
8694
|
+
`A stored document is not MessagePack: ${error instanceof Error ? error.message : String(error)}`
|
|
8695
|
+
);
|
|
8696
|
+
}
|
|
8697
|
+
if (decoded === null || typeof decoded !== "object" || Array.isArray(decoded) || decoded instanceof Uint8Array) {
|
|
8698
|
+
throw new NarsilError(ErrorCodes.PERSISTENCE_LOAD_FAILED, "A stored document decodes to something other than a map");
|
|
8699
|
+
}
|
|
8700
|
+
const document = decoded;
|
|
8701
|
+
if (discardedFields !== void 0) {
|
|
8702
|
+
for (const fieldPath of discardedFields) removeFieldAtPath(document, fieldPath);
|
|
8703
|
+
}
|
|
8704
|
+
return document;
|
|
8705
|
+
}
|
|
8706
|
+
function* storedDocumentsOf(data) {
|
|
8707
|
+
const count = data.offsets.length - 1;
|
|
8708
|
+
for (let ordinal = 0; ordinal < count; ordinal++) {
|
|
8709
|
+
yield decodeStoredDocument(
|
|
8710
|
+
data.blob.subarray(data.offsets[ordinal], data.offsets[ordinal + 1]),
|
|
8711
|
+
data.discardedFields
|
|
8712
|
+
);
|
|
8713
|
+
}
|
|
8714
|
+
}
|
|
8715
|
+
function decodeEveryStoredDocument(data) {
|
|
8716
|
+
const count = data.offsets.length - 1;
|
|
8717
|
+
for (let ordinal = 0; ordinal < count; ordinal++) {
|
|
8718
|
+
decodeStoredDocument(data.blob.subarray(data.offsets[ordinal], data.offsets[ordinal + 1]), data.discardedFields);
|
|
8719
|
+
}
|
|
8720
|
+
}
|
|
9280
8721
|
function encodeDocumentTableData(documents) {
|
|
9281
8722
|
const encoded = new Array(documents.length);
|
|
9282
8723
|
let blobLength = 0;
|
|
9283
8724
|
for (let ordinal = 0; ordinal < documents.length; ordinal++) {
|
|
9284
|
-
const bytes =
|
|
8725
|
+
const bytes = encodeDocument(documents[ordinal]);
|
|
9285
8726
|
encoded[ordinal] = bytes;
|
|
9286
8727
|
blobLength += bytes.length;
|
|
9287
8728
|
}
|
|
@@ -9309,11 +8750,14 @@ function wrapEncodedDocumentTable(data) {
|
|
|
9309
8750
|
docAt(ordinal) {
|
|
9310
8751
|
let document = decoded[ordinal];
|
|
9311
8752
|
if (document === void 0) {
|
|
9312
|
-
document =
|
|
8753
|
+
document = decodeStoredDocument(blob.slice(offsets[ordinal], offsets[ordinal + 1]), data.discardedFields);
|
|
9313
8754
|
decoded[ordinal] = document;
|
|
9314
8755
|
decodedBytes += documentValueBytes(document);
|
|
9315
8756
|
}
|
|
9316
8757
|
return document;
|
|
8758
|
+
},
|
|
8759
|
+
readAt(ordinal) {
|
|
8760
|
+
return decoded[ordinal] ?? decodeStoredDocument(blob.subarray(offsets[ordinal], offsets[ordinal + 1]), data.discardedFields);
|
|
9317
8761
|
}
|
|
9318
8762
|
};
|
|
9319
8763
|
}
|
|
@@ -9327,75 +8771,15 @@ function wrapDocumentArray(documents) {
|
|
|
9327
8771
|
byteLength: residentBytes,
|
|
9328
8772
|
docAt(ordinal) {
|
|
9329
8773
|
return documents[ordinal];
|
|
8774
|
+
},
|
|
8775
|
+
readAt(ordinal) {
|
|
8776
|
+
return documents[ordinal];
|
|
9330
8777
|
}
|
|
9331
8778
|
};
|
|
9332
8779
|
}
|
|
9333
8780
|
|
|
9334
|
-
// src/core/partition/frozen/string-blob.ts
|
|
9335
|
-
var SURROGATE = /[\ud800-\udfff]/;
|
|
9336
|
-
var encoder = new TextEncoder();
|
|
9337
|
-
function encodeOneByOne(strings) {
|
|
9338
|
-
const encoded = new Array(strings.length);
|
|
9339
|
-
let blobLength = 0;
|
|
9340
|
-
for (let i = 0; i < strings.length; i++) {
|
|
9341
|
-
encoded[i] = encoder.encode(strings[i]);
|
|
9342
|
-
blobLength += encoded[i].length;
|
|
9343
|
-
}
|
|
9344
|
-
const blob = new Uint8Array(blobLength);
|
|
9345
|
-
const offsets = new Uint32Array(strings.length + 1);
|
|
9346
|
-
let cursor = 0;
|
|
9347
|
-
for (let i = 0; i < strings.length; i++) {
|
|
9348
|
-
blob.set(encoded[i], cursor);
|
|
9349
|
-
cursor += encoded[i].length;
|
|
9350
|
-
offsets[i + 1] = cursor;
|
|
9351
|
-
}
|
|
9352
|
-
return { blob, offsets };
|
|
9353
|
-
}
|
|
9354
|
-
function basicPlaneUtf8Bytes(text) {
|
|
9355
|
-
let bytes = text.length;
|
|
9356
|
-
for (let i = 0; i < text.length; i++) {
|
|
9357
|
-
const unit = text.charCodeAt(i);
|
|
9358
|
-
if (unit >= 128) bytes += unit < 2048 ? 1 : 2;
|
|
9359
|
-
}
|
|
9360
|
-
return bytes;
|
|
9361
|
-
}
|
|
9362
|
-
function encodeStringBlob(strings) {
|
|
9363
|
-
const joined = strings.join("");
|
|
9364
|
-
if (SURROGATE.test(joined)) return encodeOneByOne(strings);
|
|
9365
|
-
const blob = encoder.encode(joined);
|
|
9366
|
-
const offsets = new Uint32Array(strings.length + 1);
|
|
9367
|
-
let cursor = 0;
|
|
9368
|
-
for (let i = 0; i < strings.length; i++) {
|
|
9369
|
-
cursor += basicPlaneUtf8Bytes(strings[i]);
|
|
9370
|
-
offsets[i + 1] = cursor;
|
|
9371
|
-
}
|
|
9372
|
-
return cursor === blob.length ? { blob, offsets } : encodeOneByOne(strings);
|
|
9373
|
-
}
|
|
9374
|
-
function orderByComparator(strings) {
|
|
9375
|
-
const order = new Array(strings.length);
|
|
9376
|
-
for (let i = 0; i < strings.length; i++) order[i] = i;
|
|
9377
|
-
return order.sort((a, b) => compareCodePoints(strings[a], strings[b]));
|
|
9378
|
-
}
|
|
9379
|
-
function alreadyInCodePointOrder(strings) {
|
|
9380
|
-
for (let i = 1; i < strings.length; i++) {
|
|
9381
|
-
if (compareCodePoints(strings[i - 1], strings[i]) > 0) return false;
|
|
9382
|
-
}
|
|
9383
|
-
return true;
|
|
9384
|
-
}
|
|
9385
|
-
function codePointOrder(strings) {
|
|
9386
|
-
if (alreadyInCodePointOrder(strings)) return strings.map((_, i) => i);
|
|
9387
|
-
if (SURROGATE.test(strings.join(""))) return orderByComparator(strings);
|
|
9388
|
-
const positions = /* @__PURE__ */ new Map();
|
|
9389
|
-
for (let i = 0; i < strings.length; i++) positions.set(strings[i], i);
|
|
9390
|
-
if (positions.size !== strings.length) return orderByComparator(strings);
|
|
9391
|
-
const order = new Array(strings.length);
|
|
9392
|
-
const sorted = [...strings].sort();
|
|
9393
|
-
for (let i = 0; i < sorted.length; i++) order[i] = positions.get(sorted[i]) ?? 0;
|
|
9394
|
-
return order;
|
|
9395
|
-
}
|
|
9396
|
-
|
|
9397
8781
|
// src/core/partition/frozen/external-ids.ts
|
|
9398
|
-
var
|
|
8782
|
+
var encoder = new TextEncoder();
|
|
9399
8783
|
var decoder = new TextDecoder();
|
|
9400
8784
|
function encodeExternalIdTableData(docIds) {
|
|
9401
8785
|
const { blob, offsets } = encodeStringBlob(docIds);
|
|
@@ -9427,7 +8811,7 @@ function wrapExternalIdTable(data) {
|
|
|
9427
8811
|
bytes: blob.byteLength + offsets.byteLength + sortedOrdinals.byteLength,
|
|
9428
8812
|
idAt,
|
|
9429
8813
|
ordinalOf(docId) {
|
|
9430
|
-
const query =
|
|
8814
|
+
const query = encoder.encode(docId);
|
|
9431
8815
|
let lo = 0;
|
|
9432
8816
|
let hi = count;
|
|
9433
8817
|
while (lo < hi) {
|
|
@@ -9713,6 +9097,10 @@ function createFrozenInvertedReader(table, views) {
|
|
|
9713
9097
|
if (at < 0) return void 0;
|
|
9714
9098
|
return views.viewReadOnce(table.payloadSlot(at), table.documentFrequencyAt(at));
|
|
9715
9099
|
},
|
|
9100
|
+
documentFrequency(token) {
|
|
9101
|
+
const at = table.find(token);
|
|
9102
|
+
return at < 0 ? 0 : table.documentFrequencyAt(at);
|
|
9103
|
+
},
|
|
9716
9104
|
fuzzyLookup(token, tolerance, prefixLength) {
|
|
9717
9105
|
if (tolerance === 0) {
|
|
9718
9106
|
const at = table.find(token);
|
|
@@ -9867,7 +9255,7 @@ function createLazySurfaceReader(load) {
|
|
|
9867
9255
|
}
|
|
9868
9256
|
|
|
9869
9257
|
// src/core/partition/frozen/token-table.ts
|
|
9870
|
-
var
|
|
9258
|
+
var encoder2 = new TextEncoder();
|
|
9871
9259
|
var decoder3 = new TextDecoder();
|
|
9872
9260
|
function compareBytes2(blob, start, end, query) {
|
|
9873
9261
|
const length = end - start;
|
|
@@ -9931,7 +9319,7 @@ function wrapFrozenTokenTable(data) {
|
|
|
9931
9319
|
size,
|
|
9932
9320
|
bytes: blob.byteLength + offsets.byteLength + payloadSlots.byteLength + documentFrequencies.byteLength,
|
|
9933
9321
|
find(token) {
|
|
9934
|
-
const query =
|
|
9322
|
+
const query = encoder2.encode(token);
|
|
9935
9323
|
const at = lowerBound3(query);
|
|
9936
9324
|
if (at >= size) return -1;
|
|
9937
9325
|
return compareBytes2(blob, offsets[at], offsets[at + 1], query) === 0 ? at : -1;
|
|
@@ -9944,6 +9332,9 @@ function wrapFrozenTokenTable(data) {
|
|
|
9944
9332
|
}
|
|
9945
9333
|
return token;
|
|
9946
9334
|
},
|
|
9335
|
+
byteLengthAt(sortedIndex) {
|
|
9336
|
+
return offsets[sortedIndex + 1] - offsets[sortedIndex];
|
|
9337
|
+
},
|
|
9947
9338
|
payloadSlot(sortedIndex) {
|
|
9948
9339
|
return payloadSlots[sortedIndex];
|
|
9949
9340
|
},
|
|
@@ -9951,7 +9342,7 @@ function wrapFrozenTokenTable(data) {
|
|
|
9951
9342
|
return documentFrequencies[sortedIndex];
|
|
9952
9343
|
},
|
|
9953
9344
|
prefixRange(prefix) {
|
|
9954
|
-
const bytes =
|
|
9345
|
+
const bytes = encoder2.encode(prefix);
|
|
9955
9346
|
const start = lowerBound3(bytes);
|
|
9956
9347
|
return { start, end: prefixEnd(start, bytes) };
|
|
9957
9348
|
},
|
|
@@ -9969,8 +9360,8 @@ function wrapFrozenTokenTable(data) {
|
|
|
9969
9360
|
fromCodePoint = unit;
|
|
9970
9361
|
toCodePoint = nextCodePoint(unit);
|
|
9971
9362
|
}
|
|
9972
|
-
const from =
|
|
9973
|
-
const to =
|
|
9363
|
+
const from = encoder2.encode(String.fromCodePoint(fromCodePoint));
|
|
9364
|
+
const to = encoder2.encode(String.fromCodePoint(toCodePoint));
|
|
9974
9365
|
return { start: lowerBound3(from), end: lowerBound3(to) };
|
|
9975
9366
|
}
|
|
9976
9367
|
};
|
|
@@ -10032,11 +9423,68 @@ function sharedSurfaceTable(payload) {
|
|
|
10032
9423
|
if (table.counts.length === 0) return null;
|
|
10033
9424
|
return { blob: sharedUint8(table.blob), offsets: sharedUint32(table.offsets), counts: sharedUint32(table.counts) };
|
|
10034
9425
|
}
|
|
10035
|
-
function
|
|
9426
|
+
function sharePartialWordTable(table) {
|
|
9427
|
+
if (typeof SharedArrayBuffer !== "function") return table;
|
|
9428
|
+
return {
|
|
9429
|
+
fields: [...table.fields],
|
|
9430
|
+
spellings: sharedUint8(table.spellings),
|
|
9431
|
+
spellingOffsets: sharedUint32(table.spellingOffsets),
|
|
9432
|
+
spellingTokens: sharedUint32(table.spellingTokens),
|
|
9433
|
+
spellingCounts: sharedUint32(table.spellingCounts),
|
|
9434
|
+
runs: sharedUint32(table.runs),
|
|
9435
|
+
runOffsets: sharedUint32(table.runOffsets),
|
|
9436
|
+
runEntries: sharedUint32(table.runEntries)
|
|
9437
|
+
};
|
|
9438
|
+
}
|
|
9439
|
+
function sharedPartialWordsOf(tokenData, spellings, documentData, analysis) {
|
|
9440
|
+
let source = spellings;
|
|
9441
|
+
if (source === null && analysis !== null && analysis.fields.length > 0) {
|
|
9442
|
+
source = encodePartialSpellings(analysis.fields, spellingCountsOf(storedDocumentsOf(documentData), analysis));
|
|
9443
|
+
}
|
|
9444
|
+
if (source === null || source.fields.length === 0) return null;
|
|
9445
|
+
const table = buildPartialWordTableFrom(source, wrapFrozenTokenTable(tokenData));
|
|
9446
|
+
return table === null ? null : sharePartialWordTable(table);
|
|
9447
|
+
}
|
|
9448
|
+
function shareSegmentArrays(arrays, analysis, segmentId) {
|
|
9449
|
+
return {
|
|
9450
|
+
...arrays,
|
|
9451
|
+
segmentId: segmentId ?? generateId(),
|
|
9452
|
+
partialWords: sharedPartialWordsOf(arrays.tokenTable, null, arrays.documentTable, analysis)
|
|
9453
|
+
};
|
|
9454
|
+
}
|
|
9455
|
+
function segmentArraysOf(payload, documentData) {
|
|
9456
|
+
const tokenTable = encodeFrozenTokenTableData(payload.tokens, payload.docFrequencies);
|
|
9457
|
+
const idTable = encodeExternalIdTableData(payload.docIds);
|
|
9458
|
+
const surfaceTable = payload.surfaceForms === null ? null : encodeSurfaceTable(payload.surfaceForms);
|
|
9459
|
+
return {
|
|
9460
|
+
documentCount: payload.documentCount,
|
|
9461
|
+
fieldNames: payload.fieldNames,
|
|
9462
|
+
fieldLengthNames: payload.fieldLengthNames,
|
|
9463
|
+
fieldLengthColumns: payload.fieldLengthColumns,
|
|
9464
|
+
totalFieldLengths: payload.totalFieldLengths,
|
|
9465
|
+
tokenTable,
|
|
9466
|
+
idTable,
|
|
9467
|
+
documentTable: documentData,
|
|
9468
|
+
postingOffsets: payload.postingOffsets,
|
|
9469
|
+
postingDocIds: payload.postingDocIds,
|
|
9470
|
+
postingFrequencies: payload.postingFrequencies,
|
|
9471
|
+
postingFieldIndices: payload.postingFieldIndices,
|
|
9472
|
+
positionOffsets: payload.positionOffsets,
|
|
9473
|
+
positionValues: payload.positionValues,
|
|
9474
|
+
numeric: payload.numeric,
|
|
9475
|
+
sizes: payload.sizes,
|
|
9476
|
+
boolean: payload.boolean,
|
|
9477
|
+
enums: payload.enums,
|
|
9478
|
+
geo: payload.geo,
|
|
9479
|
+
pattern: payload.pattern,
|
|
9480
|
+
surfaceTable: surfaceTable === null || surfaceTable.counts.length === 0 ? null : surfaceTable
|
|
9481
|
+
};
|
|
9482
|
+
}
|
|
9483
|
+
function freezeSegmentShared(payload, documents, segmentId, analysis = null) {
|
|
10036
9484
|
if (typeof SharedArrayBuffer !== "function") return null;
|
|
10037
|
-
return freezeEncodedSegmentShared(payload, encodeDocumentTableData(documents), segmentId);
|
|
9485
|
+
return freezeEncodedSegmentShared(payload, encodeDocumentTableData(documents), segmentId, analysis);
|
|
10038
9486
|
}
|
|
10039
|
-
function freezeEncodedSegmentShared(payload, documentData, segmentId) {
|
|
9487
|
+
function freezeEncodedSegmentShared(payload, documentData, segmentId, analysis = null) {
|
|
10040
9488
|
if (typeof SharedArrayBuffer !== "function") return null;
|
|
10041
9489
|
const tokenData = encodeFrozenTokenTableData(payload.tokens, payload.docFrequencies);
|
|
10042
9490
|
const idData = encodeExternalIdTableData(payload.docIds);
|
|
@@ -10060,12 +9508,13 @@ function freezeEncodedSegmentShared(payload, documentData, segmentId) {
|
|
|
10060
9508
|
},
|
|
10061
9509
|
documentTable: {
|
|
10062
9510
|
blob: sharedUint8(documentData.blob),
|
|
10063
|
-
offsets: sharedUint32(documentData.offsets)
|
|
9511
|
+
offsets: sharedUint32(documentData.offsets),
|
|
9512
|
+
...documentData.discardedFields === void 0 ? {} : { discardedFields: documentData.discardedFields }
|
|
10064
9513
|
},
|
|
10065
9514
|
postingOffsets: sharedUint32(payload.postingOffsets),
|
|
10066
9515
|
postingDocIds: sharedUint32(payload.postingDocIds),
|
|
10067
9516
|
postingFrequencies: sharedUint16(payload.postingFrequencies),
|
|
10068
|
-
postingFieldIndices:
|
|
9517
|
+
postingFieldIndices: sharedUint16(payload.postingFieldIndices),
|
|
10069
9518
|
positionOffsets: payload.positionOffsets === null ? null : sharedUint32(payload.positionOffsets),
|
|
10070
9519
|
positionValues: payload.positionValues === null ? null : sharedUint32(payload.positionValues),
|
|
10071
9520
|
numeric: payload.numeric.map((entry) => ({
|
|
@@ -10102,7 +9551,8 @@ function freezeEncodedSegmentShared(payload, documentData, segmentId) {
|
|
|
10102
9551
|
offsets: sharedUint32(entry.offsets),
|
|
10103
9552
|
postings: sharedUint32(entry.postings)
|
|
10104
9553
|
})),
|
|
10105
|
-
surfaceTable: sharedSurfaceTable(payload)
|
|
9554
|
+
surfaceTable: sharedSurfaceTable(payload),
|
|
9555
|
+
partialWords: sharedPartialWordsOf(tokenData, payload.partialSpellings, documentData, analysis)
|
|
10106
9556
|
};
|
|
10107
9557
|
}
|
|
10108
9558
|
|
|
@@ -10138,7 +9588,12 @@ function buildGeoReaders(entries) {
|
|
|
10138
9588
|
}
|
|
10139
9589
|
return readers;
|
|
10140
9590
|
}
|
|
10141
|
-
function
|
|
9591
|
+
function* survivingDocuments(documentSource, tombstones) {
|
|
9592
|
+
for (let ordinal = 0; ordinal < documentSource.count; ordinal++) {
|
|
9593
|
+
if (!tombstones.has(ordinal)) yield documentSource.readAt(ordinal);
|
|
9594
|
+
}
|
|
9595
|
+
}
|
|
9596
|
+
function assembleFrozenSegment(segmentId, source, documentSource, sharedSnapshot, partialWordTable) {
|
|
10142
9597
|
const tombstones = createFrozenTombstones();
|
|
10143
9598
|
const postingViews = createFrozenPostingViews(source, tombstones);
|
|
10144
9599
|
const lengthColumns = /* @__PURE__ */ new Map();
|
|
@@ -10146,6 +9601,10 @@ function assembleFrozenSegment(segmentId, source, documentSource, sharedSnapshot
|
|
|
10146
9601
|
lengthColumns.set(source.fieldLengthNames[i], source.fieldLengthColumns[i]);
|
|
10147
9602
|
}
|
|
10148
9603
|
const docStore = createFrozenDocTable(source.idTable, lengthColumns, documentSource, tombstones);
|
|
9604
|
+
const partialWords = createFrozenPartialWords(partialWordTable, source.tokenTable, {
|
|
9605
|
+
documentAt: (ordinal) => documentSource.readAt(ordinal),
|
|
9606
|
+
survivors: () => survivingDocuments(documentSource, tombstones)
|
|
9607
|
+
});
|
|
10149
9608
|
const numericIndexes = /* @__PURE__ */ new Map();
|
|
10150
9609
|
for (const entry of source.numeric) numericIndexes.set(entry.fieldPath, createFrozenNumericReader(entry));
|
|
10151
9610
|
const sizeIndexes = /* @__PURE__ */ new Map();
|
|
@@ -10178,6 +9637,7 @@ function assembleFrozenSegment(segmentId, source, documentSource, sharedSnapshot
|
|
|
10178
9637
|
patternIndexes,
|
|
10179
9638
|
sizeIndexes,
|
|
10180
9639
|
fieldNameTable,
|
|
9640
|
+
partialWords,
|
|
10181
9641
|
trackPositions: source.positionOffsets !== null,
|
|
10182
9642
|
flatSchemaCache: null,
|
|
10183
9643
|
lastSchemaRef: null,
|
|
@@ -10197,6 +9657,7 @@ function assembleFrozenSegment(segmentId, source, documentSource, sharedSnapshot
|
|
|
10197
9657
|
if (ordinal === void 0) return false;
|
|
10198
9658
|
const added = tombstones.add(ordinal);
|
|
10199
9659
|
if (added) {
|
|
9660
|
+
partialWords.afterRemoval(ordinal);
|
|
10200
9661
|
docStore.releaseSortedDocIds();
|
|
10201
9662
|
segment.sortColumns = null;
|
|
10202
9663
|
segment.scoreBuffer = null;
|
|
@@ -10212,18 +9673,20 @@ function assembleFrozenSegment(segmentId, source, documentSource, sharedSnapshot
|
|
|
10212
9673
|
return segment;
|
|
10213
9674
|
}
|
|
10214
9675
|
function createFrozenSegment(payload, documents, segmentId) {
|
|
9676
|
+
const tokenTable = buildFrozenTokenTable(payload.tokens, payload.docFrequencies);
|
|
10215
9677
|
return assembleFrozenSegment(
|
|
10216
9678
|
segmentId ?? generateId(),
|
|
10217
9679
|
{
|
|
10218
9680
|
...payload,
|
|
10219
|
-
tokenTable
|
|
9681
|
+
tokenTable,
|
|
10220
9682
|
idTable: buildExternalIdTable(payload.docIds),
|
|
10221
9683
|
documentTable: null,
|
|
10222
9684
|
readSurfaceForms: () => payload.surfaceForms,
|
|
10223
9685
|
docFrequencies: () => payload.docFrequencies
|
|
10224
9686
|
},
|
|
10225
9687
|
wrapDocumentArray(documents),
|
|
10226
|
-
null
|
|
9688
|
+
null,
|
|
9689
|
+
payload.partialSpellings === null ? null : buildPartialWordTableFrom(payload.partialSpellings, tokenTable)
|
|
10227
9690
|
);
|
|
10228
9691
|
}
|
|
10229
9692
|
function createSharedFrozenSegment(snapshot) {
|
|
@@ -10245,9 +9708,137 @@ function createSharedFrozenSegment(snapshot) {
|
|
|
10245
9708
|
}
|
|
10246
9709
|
},
|
|
10247
9710
|
wrapEncodedDocumentTable(snapshot.documentTable),
|
|
10248
|
-
snapshot
|
|
9711
|
+
snapshot,
|
|
9712
|
+
snapshot.partialWords
|
|
10249
9713
|
);
|
|
10250
9714
|
}
|
|
9715
|
+
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
9716
|
+
var keyDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
9717
|
+
function headerAt(view, offset) {
|
|
9718
|
+
if (offset >= view.byteLength) return null;
|
|
9719
|
+
const tag = view.getUint8(offset);
|
|
9720
|
+
if (tag <= 127 || tag >= 224) return { headerBytes: 1, bodyBytes: 0, children: 0 };
|
|
9721
|
+
if (tag <= 143) return { headerBytes: 1, bodyBytes: 0, children: (tag & 15) * 2 };
|
|
9722
|
+
if (tag <= 159) return { headerBytes: 1, bodyBytes: 0, children: tag & 15 };
|
|
9723
|
+
if (tag <= 191) return { headerBytes: 1, bodyBytes: tag & 31, children: 0 };
|
|
9724
|
+
const lengthBytes = LENGTH_BYTES_BY_TAG.get(tag);
|
|
9725
|
+
if (lengthBytes !== void 0) {
|
|
9726
|
+
if (offset + 1 + lengthBytes > view.byteLength) return null;
|
|
9727
|
+
const length = lengthBytes === 1 ? view.getUint8(offset + 1) : lengthBytes === 2 ? view.getUint16(offset + 1, false) : view.getUint32(offset + 1, false);
|
|
9728
|
+
const headerBytes = 1 + lengthBytes;
|
|
9729
|
+
if (ARRAY_TAGS.has(tag)) return { headerBytes, bodyBytes: 0, children: length };
|
|
9730
|
+
if (MAP_TAGS.has(tag)) return { headerBytes, bodyBytes: 0, children: length * 2 };
|
|
9731
|
+
return { headerBytes, bodyBytes: length + (EXT_TAGS.has(tag) ? 1 : 0), children: 0 };
|
|
9732
|
+
}
|
|
9733
|
+
const fixedBytes = FIXED_BODY_BYTES_BY_TAG.get(tag);
|
|
9734
|
+
return fixedBytes === void 0 ? null : { headerBytes: 1, bodyBytes: fixedBytes, children: 0 };
|
|
9735
|
+
}
|
|
9736
|
+
var LENGTH_BYTES_BY_TAG = /* @__PURE__ */ new Map([
|
|
9737
|
+
[196, 1],
|
|
9738
|
+
[197, 2],
|
|
9739
|
+
[198, 4],
|
|
9740
|
+
[199, 1],
|
|
9741
|
+
[200, 2],
|
|
9742
|
+
[201, 4],
|
|
9743
|
+
[217, 1],
|
|
9744
|
+
[218, 2],
|
|
9745
|
+
[219, 4],
|
|
9746
|
+
[220, 2],
|
|
9747
|
+
[221, 4],
|
|
9748
|
+
[222, 2],
|
|
9749
|
+
[223, 4]
|
|
9750
|
+
]);
|
|
9751
|
+
var ARRAY_TAGS = /* @__PURE__ */ new Set([220, 221]);
|
|
9752
|
+
var MAP_TAGS = /* @__PURE__ */ new Set([222, 223]);
|
|
9753
|
+
var EXT_TAGS = /* @__PURE__ */ new Set([199, 200, 201]);
|
|
9754
|
+
var FIXED_BODY_BYTES_BY_TAG = /* @__PURE__ */ new Map([
|
|
9755
|
+
[192, 0],
|
|
9756
|
+
[194, 0],
|
|
9757
|
+
[195, 0],
|
|
9758
|
+
[202, 4],
|
|
9759
|
+
[203, 8],
|
|
9760
|
+
[204, 1],
|
|
9761
|
+
[205, 2],
|
|
9762
|
+
[206, 4],
|
|
9763
|
+
[207, 8],
|
|
9764
|
+
[208, 1],
|
|
9765
|
+
[209, 2],
|
|
9766
|
+
[210, 4],
|
|
9767
|
+
[211, 8],
|
|
9768
|
+
[212, 2],
|
|
9769
|
+
[213, 3],
|
|
9770
|
+
[214, 5],
|
|
9771
|
+
[215, 9],
|
|
9772
|
+
[216, 17]
|
|
9773
|
+
]);
|
|
9774
|
+
function endOfValue(view, start) {
|
|
9775
|
+
let offset = start;
|
|
9776
|
+
let pending = 1;
|
|
9777
|
+
while (pending > 0) {
|
|
9778
|
+
const header = headerAt(view, offset);
|
|
9779
|
+
if (header === null) return null;
|
|
9780
|
+
offset += header.headerBytes + header.bodyBytes;
|
|
9781
|
+
if (offset > view.byteLength) return null;
|
|
9782
|
+
pending += header.children - 1;
|
|
9783
|
+
}
|
|
9784
|
+
return offset;
|
|
9785
|
+
}
|
|
9786
|
+
function stringKeyAt(bytes, view, offset) {
|
|
9787
|
+
const header = headerAt(view, offset);
|
|
9788
|
+
if (header === null || header.children !== 0) return null;
|
|
9789
|
+
const tag = view.getUint8(offset);
|
|
9790
|
+
const isString = tag >= 160 && tag <= 191 || tag === 217 || tag === 218 || tag === 219;
|
|
9791
|
+
const end = offset + header.headerBytes + header.bodyBytes;
|
|
9792
|
+
if (!isString || end > bytes.length) return null;
|
|
9793
|
+
try {
|
|
9794
|
+
return { key: keyDecoder.decode(bytes.subarray(offset + header.headerBytes, end)), end };
|
|
9795
|
+
} catch {
|
|
9796
|
+
return null;
|
|
9797
|
+
}
|
|
9798
|
+
}
|
|
9799
|
+
function topLevelMapKeys(bytes) {
|
|
9800
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
9801
|
+
const top = headerAt(view, 0);
|
|
9802
|
+
if (top === null || top.bodyBytes !== 0) return null;
|
|
9803
|
+
const tag = view.getUint8(0);
|
|
9804
|
+
if (!(tag >= 128 && tag <= 143 || MAP_TAGS.has(tag))) return null;
|
|
9805
|
+
const keys = /* @__PURE__ */ new Set();
|
|
9806
|
+
let offset = top.headerBytes;
|
|
9807
|
+
for (let pair = 0; pair < top.children / 2; pair += 1) {
|
|
9808
|
+
const key = stringKeyAt(bytes, view, offset);
|
|
9809
|
+
if (key === null) return null;
|
|
9810
|
+
const valueEnd = endOfValue(view, key.end);
|
|
9811
|
+
if (valueEnd === null) return null;
|
|
9812
|
+
keys.add(key.key);
|
|
9813
|
+
offset = valueEnd;
|
|
9814
|
+
}
|
|
9815
|
+
return keys;
|
|
9816
|
+
}
|
|
9817
|
+
function decodeMapWithoutFields(bytes, skippedFields) {
|
|
9818
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
9819
|
+
const top = headerAt(view, 0);
|
|
9820
|
+
if (top === null || top.children === 0 || top.bodyBytes !== 0) return null;
|
|
9821
|
+
const tag = view.getUint8(0);
|
|
9822
|
+
const isMap = tag >= 128 && tag <= 143 || MAP_TAGS.has(tag);
|
|
9823
|
+
if (!isMap) return null;
|
|
9824
|
+
const document = {};
|
|
9825
|
+
let offset = top.headerBytes;
|
|
9826
|
+
for (let pair = 0; pair < top.children / 2; pair += 1) {
|
|
9827
|
+
const key = stringKeyAt(bytes, view, offset);
|
|
9828
|
+
if (key === null || FORBIDDEN_KEYS.has(key.key)) return null;
|
|
9829
|
+
const valueEnd = endOfValue(view, key.end);
|
|
9830
|
+
if (valueEnd === null) return null;
|
|
9831
|
+
if (!skippedFields.has(key.key)) {
|
|
9832
|
+
try {
|
|
9833
|
+
document[key.key] = decode(bytes.subarray(key.end, valueEnd));
|
|
9834
|
+
} catch {
|
|
9835
|
+
return null;
|
|
9836
|
+
}
|
|
9837
|
+
}
|
|
9838
|
+
offset = valueEnd;
|
|
9839
|
+
}
|
|
9840
|
+
return offset === bytes.length ? document : null;
|
|
9841
|
+
}
|
|
10251
9842
|
|
|
10252
9843
|
// src/core/partition/frozen/merge-fields.ts
|
|
10253
9844
|
function indexByFieldPath(entries) {
|
|
@@ -10510,7 +10101,7 @@ function mergePostings2(inputs) {
|
|
|
10510
10101
|
const postingOffsets = new Uint32Array(tokenCount + 1);
|
|
10511
10102
|
const postingDocIds = new Uint32Array(totalPostings);
|
|
10512
10103
|
const postingFrequencies = new Uint16Array(totalPostings);
|
|
10513
|
-
const postingFieldIndices = new
|
|
10104
|
+
const postingFieldIndices = new Uint16Array(totalPostings);
|
|
10514
10105
|
const positionOffsets = hasPositions ? new Uint32Array(totalPostings + 1) : null;
|
|
10515
10106
|
const positionValues = hasPositions ? new Uint32Array(totalPositions) : null;
|
|
10516
10107
|
let postingCursor = 0;
|
|
@@ -10584,11 +10175,15 @@ function mergePostings2(inputs) {
|
|
|
10584
10175
|
}
|
|
10585
10176
|
|
|
10586
10177
|
// src/core/partition/frozen/merge.ts
|
|
10587
|
-
function
|
|
10178
|
+
function selectionKeeps(selection, ordinal) {
|
|
10179
|
+
return selection.keep === void 0 ? !selection.segment.isTombstoned(ordinal) : selection.keep(ordinal);
|
|
10180
|
+
}
|
|
10181
|
+
function remapOf(selection, docIds) {
|
|
10182
|
+
const { segment } = selection;
|
|
10588
10183
|
const count = segment.arrays.documentCount;
|
|
10589
10184
|
const remap = new Int32Array(count).fill(-1);
|
|
10590
10185
|
for (let ordinal = 0; ordinal < count; ordinal++) {
|
|
10591
|
-
if (
|
|
10186
|
+
if (!selectionKeeps(selection, ordinal)) continue;
|
|
10592
10187
|
remap[ordinal] = docIds.length;
|
|
10593
10188
|
docIds.push(segment.arrays.idTable.idAt(ordinal));
|
|
10594
10189
|
}
|
|
@@ -10601,7 +10196,7 @@ function fieldNameIndex(fieldNames, name) {
|
|
|
10601
10196
|
return fieldNames.length - 1;
|
|
10602
10197
|
}
|
|
10603
10198
|
function fieldIndexRemapOf(segment, fieldNames) {
|
|
10604
|
-
const remap = new
|
|
10199
|
+
const remap = new Uint16Array(segment.arrays.fieldNames.length);
|
|
10605
10200
|
for (let i = 0; i < segment.arrays.fieldNames.length; i++) {
|
|
10606
10201
|
remap[i] = fieldNameIndex(fieldNames, segment.arrays.fieldNames[i]);
|
|
10607
10202
|
}
|
|
@@ -10647,20 +10242,34 @@ function mergeSurfaceForms2(inputs) {
|
|
|
10647
10242
|
}
|
|
10648
10243
|
return registry.size() === 0 ? null : registry.serialize();
|
|
10649
10244
|
}
|
|
10245
|
+
function holdsADiscardedField(bytes, discardedFields) {
|
|
10246
|
+
const keys = topLevelMapKeys(bytes);
|
|
10247
|
+
if (keys === null) return true;
|
|
10248
|
+
for (const fieldPath of discardedFields) {
|
|
10249
|
+
const dot = fieldPath.indexOf(".");
|
|
10250
|
+
if (keys.has(dot < 0 ? fieldPath : fieldPath.slice(0, dot))) return true;
|
|
10251
|
+
}
|
|
10252
|
+
return false;
|
|
10253
|
+
}
|
|
10650
10254
|
function encodedDocumentsOf(input) {
|
|
10651
10255
|
const table = input.segment.arrays.documentTable;
|
|
10652
|
-
if (table !== null) {
|
|
10653
|
-
return (ordinal) => table.blob.subarray(table.offsets[ordinal], table.offsets[ordinal + 1]);
|
|
10654
|
-
}
|
|
10655
10256
|
const encoded = new Array(input.remap.length);
|
|
10656
|
-
|
|
10257
|
+
const encodeOrdinal = (ordinal) => {
|
|
10657
10258
|
let bytes = encoded[ordinal];
|
|
10658
10259
|
if (bytes === void 0) {
|
|
10659
|
-
bytes =
|
|
10260
|
+
bytes = encodeDocument(input.segment.documentSource.docAt(ordinal));
|
|
10660
10261
|
encoded[ordinal] = bytes;
|
|
10661
10262
|
}
|
|
10662
10263
|
return bytes;
|
|
10663
10264
|
};
|
|
10265
|
+
if (table === null) return encodeOrdinal;
|
|
10266
|
+
const discardedFields = table.discardedFields;
|
|
10267
|
+
return (ordinal) => {
|
|
10268
|
+
if (encoded[ordinal] !== void 0) return encodeOrdinal(ordinal);
|
|
10269
|
+
const stored = table.blob.subarray(table.offsets[ordinal], table.offsets[ordinal + 1]);
|
|
10270
|
+
if (discardedFields === void 0 || !holdsADiscardedField(stored, discardedFields)) return stored;
|
|
10271
|
+
return encodeOrdinal(ordinal);
|
|
10272
|
+
};
|
|
10664
10273
|
}
|
|
10665
10274
|
function mergeDocuments2(inputs, documentCount) {
|
|
10666
10275
|
const readers = inputs.map(encodedDocumentsOf);
|
|
@@ -10682,14 +10291,18 @@ function mergeDocuments2(inputs, documentCount) {
|
|
|
10682
10291
|
}
|
|
10683
10292
|
return { blob, offsets };
|
|
10684
10293
|
}
|
|
10685
|
-
function mergeFrozenSegments(segments) {
|
|
10294
|
+
function mergeFrozenSegments(segments, analysis) {
|
|
10686
10295
|
if (typeof SharedArrayBuffer !== "function") return null;
|
|
10296
|
+
const merged = mergeSegmentContents(segments.map((segment) => ({ segment })));
|
|
10297
|
+
return freezeEncodedSegmentShared(merged.payload, merged.documents, void 0, analysis);
|
|
10298
|
+
}
|
|
10299
|
+
function mergeSegmentContents(selections) {
|
|
10687
10300
|
const docIds = [];
|
|
10688
10301
|
const fieldNames = [];
|
|
10689
|
-
const inputs =
|
|
10690
|
-
segment,
|
|
10691
|
-
remap: remapOf(
|
|
10692
|
-
fieldIndexRemap: fieldIndexRemapOf(segment, fieldNames)
|
|
10302
|
+
const inputs = selections.map((selection) => ({
|
|
10303
|
+
segment: selection.segment,
|
|
10304
|
+
remap: remapOf(selection, docIds),
|
|
10305
|
+
fieldIndexRemap: fieldIndexRemapOf(selection.segment, fieldNames)
|
|
10693
10306
|
}));
|
|
10694
10307
|
const documentCount = docIds.length;
|
|
10695
10308
|
const postings = mergePostings2(inputs);
|
|
@@ -10710,9 +10323,10 @@ function mergeFrozenSegments(segments) {
|
|
|
10710
10323
|
totalFieldLengths: lengths.totalFieldLengths,
|
|
10711
10324
|
docFrequencies: postings.docFrequencies,
|
|
10712
10325
|
surfaceForms: mergeSurfaceForms2(inputs),
|
|
10326
|
+
partialSpellings: null,
|
|
10713
10327
|
...mergeFieldIndexes2(inputs)
|
|
10714
10328
|
};
|
|
10715
|
-
return
|
|
10329
|
+
return { payload, documents: mergeDocuments2(inputs, documentCount) };
|
|
10716
10330
|
}
|
|
10717
10331
|
|
|
10718
10332
|
// src/core/partition/segment-postings.ts
|
|
@@ -10826,7 +10440,7 @@ var TextPostings = class {
|
|
|
10826
10440
|
const writeCursor = postingOffsets.slice(0, tokenCount);
|
|
10827
10441
|
const postingDocIds = new Uint32Array(postings);
|
|
10828
10442
|
const postingFrequencies = new Uint16Array(postings);
|
|
10829
|
-
const postingFieldIndices = new
|
|
10443
|
+
const postingFieldIndices = new Uint16Array(postings);
|
|
10830
10444
|
const logRowOfPosting = new Uint32Array(postings);
|
|
10831
10445
|
for (let row = 0; row < postings; row++) {
|
|
10832
10446
|
const target = writeCursor[this.logToken.values[row]]++;
|
|
@@ -10980,14 +10594,18 @@ function buildSegmentPayload(documents, schema, language, options, trackPosition
|
|
|
10980
10594
|
patternIndexes: /* @__PURE__ */ new Map(),
|
|
10981
10595
|
sizeIndexes: /* @__PURE__ */ new Map()
|
|
10982
10596
|
};
|
|
10597
|
+
const partialFields = partialFieldsOf(schema);
|
|
10598
|
+
const spellings = /* @__PURE__ */ new Map();
|
|
10599
|
+
let fieldSpellings = null;
|
|
10983
10600
|
let positionOffset = 0;
|
|
10984
10601
|
const addToken = (token, position, surface) => {
|
|
10985
10602
|
postings.addToken(token, positionOffset + position);
|
|
10986
10603
|
surfaces.count(surface, token);
|
|
10604
|
+
if (fieldSpellings !== null) countSpelling(fieldSpellings, token, surface ?? token, 1);
|
|
10987
10605
|
};
|
|
10988
10606
|
for (let ordinal = 0; ordinal < documents.length; ordinal++) {
|
|
10989
10607
|
const document = documents[ordinal].document;
|
|
10990
|
-
for (const { path: fieldPath, base: fieldType, pattern } of fields) {
|
|
10608
|
+
for (const { path: fieldPath, base: fieldType, pattern, partial } of fields) {
|
|
10991
10609
|
const value = getNestedValue(document, fieldPath);
|
|
10992
10610
|
if (value === void 0 || value === null) continue;
|
|
10993
10611
|
recordValueSize(filters.sizeIndexes, ordinal, fieldPath, fieldType, value);
|
|
@@ -10996,6 +10614,7 @@ function buildSegmentPayload(documents, schema, language, options, trackPosition
|
|
|
10996
10614
|
indexFilterValue(filters, ordinal, fieldPath, fieldType, value);
|
|
10997
10615
|
continue;
|
|
10998
10616
|
}
|
|
10617
|
+
fieldSpellings = partial ? spellings : null;
|
|
10999
10618
|
postings.beginField();
|
|
11000
10619
|
positionOffset = 0;
|
|
11001
10620
|
for (const text of fieldType === "string" ? [value] : value) {
|
|
@@ -11016,6 +10635,7 @@ function buildSegmentPayload(documents, schema, language, options, trackPosition
|
|
|
11016
10635
|
fieldLengthColumns: lengths.columns,
|
|
11017
10636
|
totalFieldLengths: lengths.totalsByName(),
|
|
11018
10637
|
surfaceForms: surfaces.encode(),
|
|
10638
|
+
partialSpellings: partialFields.length === 0 ? null : encodePartialSpellings(partialFields, spellings),
|
|
11019
10639
|
...encodeFieldIndexes(filters, identity)
|
|
11020
10640
|
};
|
|
11021
10641
|
}
|
|
@@ -11082,7 +10702,7 @@ function runSegmentAction(entry, action) {
|
|
|
11082
10702
|
}
|
|
11083
10703
|
case "compactSegments": {
|
|
11084
10704
|
const partition = requireComposite(entry, action.indexName, action.partitionId, "compact");
|
|
11085
|
-
return mergeFrozenSegments(partition.frozenSegmentsById(action.segmentIds));
|
|
10705
|
+
return mergeFrozenSegments(partition.frozenSegmentsById(action.segmentIds), entry.manager.partialWordAnalysis);
|
|
11086
10706
|
}
|
|
11087
10707
|
case "swapSegments": {
|
|
11088
10708
|
requireComposite(entry, action.indexName, action.partitionId, "swap");
|
|
@@ -11559,4 +11179,4 @@ function createDirectExecutor(options) {
|
|
|
11559
11179
|
};
|
|
11560
11180
|
}
|
|
11561
11181
|
|
|
11562
|
-
export { CONSECUTIVE_TIMEOUTS_BEFORE_DEATH, DEFAULT_BACKPRESSURE_LIMIT, DEFAULT_REQUEST_TIMEOUT_MS, FIELD_FILTER_OPERATORS, FILTER_EXPRESSION_KEYS, NO_LIVE_VECTOR_AT_POSITION, SHUTDOWN_TIMEOUT_MS, VECTOR_FILE_MAX_VECTORS, buildSegmentPayload,
|
|
11182
|
+
export { CHECKSUM_YIELD_CHUNK_BYTES, CONSECUTIVE_TIMEOUTS_BEFORE_DEATH, DEFAULT_BACKPRESSURE_LIMIT, DEFAULT_REQUEST_TIMEOUT_MS, FIELD_FILTER_OPERATORS, FILTER_EXPRESSION_KEYS, MAX_FILE_BYTES, NATIVE_CRC32_MIN_BYTES, NO_LIVE_VECTOR_AT_POSITION, SHUTDOWN_TIMEOUT_MS, VALID_HNSW_METRICS, VECTOR_FILE_MAX_VECTORS, VECTOR_FILE_PAYLOAD_VERSION, assembleGraphParts, buildSegmentPayload, bytesToVectors, countDead, createDirectExecutor, createFrozenSegment, createPartitionIndex, createPartitionManager, createPartitionRouter, createSharedFrozenSegment, deadBitsWhere, deadBytesFor, decodeEveryStoredDocument, decodeMapWithoutFields, decodeStoredDocument, decodeVectorFilePayload, decodeVectorGraphPartPayload, decodeVectorGraphPayload, decodeVectorIndexParts, encodeSegmentState, freezeSegmentShared, generateId, getStopWords, getTokenizer, graphPartsOfEarlierPayload, hasStopWords, hasTokenizer, isCompositePartition, isDead, mergeFrozenSegments, mergeSegmentContents, missingWorkerEntry, nodeThreadId, partitionStateOf, readHeapStatistics, registerPartialWordSearch, registerPatternSearch, registerStopWords, registerTokenizer, requirePartialWordSearchFor, requirePatternSearchFor, resolveIndexAnalysis, resolvePartitionInsertOptions, resolveRequestThreadCount, resolveWorkerCount, resolveWorkerEntry, segmentArraysOf, selectionKeeps, shareSegmentArrays, spawnNodeWorker, splitWorkerBudget, survivorDocumentsOf, vectorsPerFile, vectorsToBytes, workerResourceLimits };
|