@delali/narsil 0.1.14 → 0.2.0
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/NOTICE +54 -0
- package/README.md +38 -972
- package/dist/adapters/filesystem.mjs +1 -1
- package/dist/adapters/indexeddb.mjs +1 -1
- package/dist/{chunk-WISGW24C.mjs → chunk-AUMKFYTG.mjs} +1 -1
- package/dist/{chunk-HRABJLPB.mjs → chunk-BKAI2WXI.mjs} +1 -0
- package/dist/chunk-GHJWC2E5.mjs +9 -0
- package/dist/chunk-KH3YGMVT.mjs +15 -0
- package/dist/{chunk-ALB35PRQ.mjs → chunk-M2EDG55Y.mjs} +8 -0
- package/dist/{chunk-HMO6OMZ3.mjs → chunk-S6IAXOBA.mjs} +1073 -506
- package/dist/chunk-TGP5M5R7.mjs +880 -0
- package/dist/chunk-U2BKYEC7.mjs +254 -0
- package/dist/{chunk-MEW7HD75.mjs → chunk-XAKNSWIK.mjs} +2543 -1154
- package/dist/{config-CojEPOgS.d.ts → config-P27AtSn4.d.ts} +28 -7
- package/dist/direct-executor-2FV3MEDD.mjs +5 -0
- package/dist/distribution/coordinator/etcd.d.ts +2 -2
- package/dist/distribution/coordinator/etcd.mjs +2 -2
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution.d.ts +10 -4
- package/dist/distribution.mjs +1875 -1772
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/index.browser.mjs +4566 -1783
- package/dist/index.d.ts +14 -5
- package/dist/index.mjs +6 -5
- package/dist/{language-ONQ3iVDf.d.ts → language-CmJBHf1j.d.ts} +4 -1
- package/dist/languages/albanian.d.ts +5 -0
- package/dist/languages/albanian.mjs +103 -0
- package/dist/languages/amharic.d.ts +5 -0
- package/dist/languages/amharic.mjs +240 -0
- package/dist/languages/arabic.d.ts +1 -1
- package/dist/languages/arabic.mjs +939 -154
- package/dist/languages/armenian.d.ts +1 -1
- package/dist/languages/armenian.mjs +275 -243
- package/dist/languages/azerbaijani.d.ts +5 -0
- package/dist/languages/azerbaijani.mjs +152 -0
- package/dist/languages/bambara.d.ts +5 -0
- package/dist/languages/bambara.mjs +60 -0
- package/dist/languages/basque.d.ts +5 -0
- package/dist/languages/basque.mjs +726 -0
- package/dist/languages/belarusian.d.ts +5 -0
- package/dist/languages/belarusian.mjs +100 -0
- package/dist/languages/bengali.d.ts +5 -0
- package/dist/languages/bengali.mjs +128 -0
- package/dist/languages/bosnian.d.ts +5 -0
- package/dist/languages/bosnian.mjs +197 -0
- package/dist/languages/breton.d.ts +5 -0
- package/dist/languages/breton.mjs +96 -0
- package/dist/languages/bulgarian.d.ts +1 -1
- package/dist/languages/bulgarian.mjs +11 -2
- package/dist/languages/burmese.d.ts +5 -0
- package/dist/languages/burmese.mjs +57 -0
- package/dist/languages/catalan.d.ts +5 -0
- package/dist/languages/catalan.mjs +987 -0
- package/dist/languages/chinese.d.ts +1 -1
- package/dist/languages/chinese.mjs +4 -3
- package/dist/languages/croatian.d.ts +5 -0
- package/dist/languages/croatian.mjs +191 -0
- package/dist/languages/czech.d.ts +5 -0
- package/dist/languages/czech.mjs +628 -0
- package/dist/languages/dagbani.d.ts +1 -1
- package/dist/languages/dagbani.mjs +11 -2
- package/dist/languages/danish.d.ts +1 -1
- package/dist/languages/danish.mjs +215 -110
- package/dist/languages/dutch.d.ts +1 -1
- package/dist/languages/dutch.mjs +1248 -163
- package/dist/languages/english.d.ts +1 -1
- package/dist/languages/english.mjs +2 -1
- package/dist/languages/esperanto.d.ts +5 -0
- package/dist/languages/esperanto.mjs +689 -0
- package/dist/languages/estonian.d.ts +5 -0
- package/dist/languages/estonian.mjs +2160 -0
- package/dist/languages/ewe.d.ts +1 -1
- package/dist/languages/ewe.mjs +11 -2
- package/dist/languages/faroese.d.ts +5 -0
- package/dist/languages/faroese.mjs +93 -0
- package/dist/languages/fijian.d.ts +5 -0
- package/dist/languages/fijian.mjs +55 -0
- package/dist/languages/finnish.d.ts +1 -1
- package/dist/languages/finnish.mjs +528 -263
- package/dist/languages/french.d.ts +1 -1
- package/dist/languages/french.mjs +950 -437
- package/dist/languages/ga.d.ts +1 -1
- package/dist/languages/ga.mjs +2 -1
- package/dist/languages/galician.d.ts +5 -0
- package/dist/languages/galician.mjs +172 -0
- package/dist/languages/georgian.d.ts +5 -0
- package/dist/languages/georgian.mjs +91 -0
- package/dist/languages/german.d.ts +1 -1
- package/dist/languages/german.mjs +432 -162
- package/dist/languages/greek.d.ts +1 -1
- package/dist/languages/greek.mjs +1970 -281
- package/dist/languages/guarani.d.ts +5 -0
- package/dist/languages/guarani.mjs +132 -0
- package/dist/languages/gujarati.d.ts +5 -0
- package/dist/languages/gujarati.mjs +234 -0
- package/dist/languages/haitian-creole.d.ts +5 -0
- package/dist/languages/haitian-creole.mjs +106 -0
- package/dist/languages/hausa.d.ts +1 -1
- package/dist/languages/hausa.mjs +2 -1
- package/dist/languages/hawaiian.d.ts +5 -0
- package/dist/languages/hawaiian.mjs +69 -0
- package/dist/languages/hebrew.d.ts +5 -0
- package/dist/languages/hebrew.mjs +213 -0
- package/dist/languages/hindi.d.ts +1 -1
- package/dist/languages/hindi.mjs +175 -97
- package/dist/languages/hungarian.d.ts +1 -1
- package/dist/languages/hungarian.mjs +412 -326
- package/dist/languages/icelandic.d.ts +5 -0
- package/dist/languages/icelandic.mjs +161 -0
- package/dist/languages/igbo.d.ts +1 -1
- package/dist/languages/igbo.mjs +2 -1
- package/dist/languages/indonesian.d.ts +1 -1
- package/dist/languages/indonesian.mjs +329 -137
- package/dist/languages/irish.d.ts +1 -1
- package/dist/languages/irish.mjs +223 -139
- package/dist/languages/italian.d.ts +1 -1
- package/dist/languages/italian.mjs +703 -406
- package/dist/languages/japanese.d.ts +1 -1
- package/dist/languages/japanese.mjs +5 -108
- package/dist/languages/kannada.d.ts +5 -0
- package/dist/languages/kannada.mjs +94 -0
- package/dist/languages/kazakh.d.ts +5 -0
- package/dist/languages/kazakh.mjs +90 -0
- package/dist/languages/khmer.d.ts +5 -0
- package/dist/languages/khmer.mjs +181 -0
- package/dist/languages/kinyarwanda.d.ts +5 -0
- package/dist/languages/kinyarwanda.mjs +99 -0
- package/dist/languages/kirundi.d.ts +5 -0
- package/dist/languages/kirundi.mjs +92 -0
- package/dist/languages/korean.d.ts +5 -0
- package/dist/languages/korean.mjs +252 -0
- package/dist/languages/kurmanji.d.ts +5 -0
- package/dist/languages/kurmanji.mjs +50 -0
- package/dist/languages/kyrgyz.d.ts +5 -0
- package/dist/languages/kyrgyz.mjs +108 -0
- package/dist/languages/lao.d.ts +5 -0
- package/dist/languages/lao.mjs +63 -0
- package/dist/languages/latin.d.ts +5 -0
- package/dist/languages/latin.mjs +69 -0
- package/dist/languages/latvian.d.ts +5 -0
- package/dist/languages/latvian.mjs +173 -0
- package/dist/languages/lingala.d.ts +5 -0
- package/dist/languages/lingala.mjs +61 -0
- package/dist/languages/lithuanian.d.ts +5 -0
- package/dist/languages/lithuanian.mjs +571 -0
- package/dist/languages/luxembourgish.d.ts +5 -0
- package/dist/languages/luxembourgish.mjs +214 -0
- package/dist/languages/macedonian.d.ts +5 -0
- package/dist/languages/macedonian.mjs +808 -0
- package/dist/languages/malagasy.d.ts +5 -0
- package/dist/languages/malagasy.mjs +67 -0
- package/dist/languages/malay.d.ts +5 -0
- package/dist/languages/malay.mjs +482 -0
- package/dist/languages/malayalam.d.ts +5 -0
- package/dist/languages/malayalam.mjs +122 -0
- package/dist/languages/maltese.d.ts +5 -0
- package/dist/languages/maltese.mjs +139 -0
- package/dist/languages/maori.d.ts +5 -0
- package/dist/languages/maori.mjs +79 -0
- package/dist/languages/marathi.d.ts +5 -0
- package/dist/languages/marathi.mjs +111 -0
- package/dist/languages/nepali.d.ts +1 -1
- package/dist/languages/nepali.mjs +209 -99
- package/dist/languages/norwegian.d.ts +1 -1
- package/dist/languages/norwegian.mjs +218 -85
- package/dist/languages/oromo.d.ts +5 -0
- package/dist/languages/oromo.mjs +78 -0
- package/dist/languages/persian.d.ts +5 -0
- package/dist/languages/persian.mjs +710 -0
- package/dist/languages/polish.d.ts +5 -0
- package/dist/languages/polish.mjs +614 -0
- package/dist/languages/portuguese.d.ts +1 -1
- package/dist/languages/portuguese.mjs +613 -380
- package/dist/languages/punjabi.d.ts +5 -0
- package/dist/languages/punjabi.mjs +197 -0
- package/dist/languages/romanian.d.ts +1 -1
- package/dist/languages/romanian.mjs +561 -382
- package/dist/languages/russian.d.ts +1 -1
- package/dist/languages/russian.mjs +373 -244
- package/dist/languages/samoan.d.ts +5 -0
- package/dist/languages/samoan.mjs +63 -0
- package/dist/languages/sanskrit.d.ts +1 -1
- package/dist/languages/sanskrit.mjs +2 -2
- package/dist/languages/scottish-gaelic.d.ts +5 -0
- package/dist/languages/scottish-gaelic.mjs +370 -0
- package/dist/languages/serbian.d.ts +1 -1
- package/dist/languages/serbian.mjs +3635 -155
- package/dist/languages/shona.d.ts +5 -0
- package/dist/languages/shona.mjs +91 -0
- package/dist/languages/sinhala.d.ts +5 -0
- package/dist/languages/sinhala.mjs +182 -0
- package/dist/languages/slovak.d.ts +5 -0
- package/dist/languages/slovak.mjs +430 -0
- package/dist/languages/slovenian.d.ts +1 -1
- package/dist/languages/slovenian.mjs +11 -2
- package/dist/languages/sorani.d.ts +5 -0
- package/dist/languages/sorani.mjs +156 -0
- package/dist/languages/spanish.d.ts +1 -1
- package/dist/languages/spanish.mjs +676 -374
- package/dist/languages/swahili.d.ts +1 -1
- package/dist/languages/swahili.mjs +2 -1
- package/dist/languages/swedish.d.ts +1 -1
- package/dist/languages/swedish.mjs +237 -95
- package/dist/languages/tagalog.d.ts +5 -0
- package/dist/languages/tagalog.mjs +159 -0
- package/dist/languages/tamil.d.ts +1 -1
- package/dist/languages/tamil.mjs +836 -64
- package/dist/languages/tatar.d.ts +5 -0
- package/dist/languages/tatar.mjs +1017 -0
- package/dist/languages/telugu.d.ts +5 -0
- package/dist/languages/telugu.mjs +62 -0
- package/dist/languages/thai.d.ts +5 -0
- package/dist/languages/thai.mjs +65 -0
- package/dist/languages/tibetan.d.ts +5 -0
- package/dist/languages/tibetan.mjs +119 -0
- package/dist/languages/tigrinya.d.ts +5 -0
- package/dist/languages/tigrinya.mjs +194 -0
- package/dist/languages/tongan.d.ts +5 -0
- package/dist/languages/tongan.mjs +56 -0
- package/dist/languages/turkish.d.ts +1 -1
- package/dist/languages/turkish.mjs +1246 -393
- package/dist/languages/twi.d.ts +1 -1
- package/dist/languages/twi.mjs +13 -2
- package/dist/languages/ukrainian.d.ts +1 -1
- package/dist/languages/ukrainian.mjs +125 -47
- package/dist/languages/urdu.d.ts +5 -0
- package/dist/languages/urdu.mjs +528 -0
- package/dist/languages/vietnamese.d.ts +5 -0
- package/dist/languages/vietnamese.mjs +277 -0
- package/dist/languages/welsh.d.ts +5 -0
- package/dist/languages/welsh.mjs +446 -0
- package/dist/languages/wolof.d.ts +5 -0
- package/dist/languages/wolof.mjs +79 -0
- package/dist/languages/xhosa.d.ts +5 -0
- package/dist/languages/xhosa.mjs +95 -0
- package/dist/languages/yoruba.d.ts +1 -1
- package/dist/languages/yoruba.mjs +1 -0
- package/dist/languages/zulu.d.ts +1 -1
- package/dist/languages/zulu.mjs +2 -1
- package/dist/narsil-CMZRPDlQ.d.ts +159 -0
- package/dist/persistence/durability/checkpoint-worker.d.ts +13 -0
- package/dist/persistence/durability/checkpoint-worker.mjs +6 -5
- package/dist/{schema-DCgkO1j4.d.ts → schema-BnvLvjRp.d.ts} +5 -3
- package/dist/server.d.ts +12 -3
- package/dist/server.mjs +183 -64
- package/dist/{types-DHX6zGeD.d.ts → types-BRTcBgAp.d.ts} +1 -1
- package/dist/workers/entry.mjs +2 -2
- package/package.json +10 -3
- package/dist/chunk-TW6BXTOL.mjs +0 -338
- package/dist/direct-executor-E52FFGDE.mjs +0 -4
- package/dist/narsil-D-84Nvm4.d.ts +0 -72
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { english } from './chunk-TGP5M5R7.mjs';
|
|
1
2
|
import { createVectorStore, createArenaSimd, createHNSWIndex, magnitude, createBoundedMaxHeap, euclideanDistance, dotProduct, cosineSimilarityWithMagnitudes } from './chunk-S7RJJMHI.mjs';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { decode, encode } from '@msgpack/msgpack';
|
|
3
|
+
import { NarsilError, ErrorCodes, createNarsilError } from './chunk-M2EDG55Y.mjs';
|
|
4
|
+
import { encode, decode } from '@msgpack/msgpack';
|
|
5
5
|
|
|
6
6
|
// src/languages/registry.ts
|
|
7
7
|
var languages = /* @__PURE__ */ new Map();
|
|
@@ -17,157 +17,68 @@ function getLanguage(name) {
|
|
|
17
17
|
return lang;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// src/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// src/core/bitset.ts
|
|
47
|
-
function createBitSet(capacity) {
|
|
48
|
-
return new Uint32Array(capacity + 31 >>> 5 || 1);
|
|
49
|
-
}
|
|
50
|
-
function bitsetSet(bs, index) {
|
|
51
|
-
const word = index >>> 5;
|
|
52
|
-
if (word < bs.length) {
|
|
53
|
-
bs[word] |= 1 << (index & 31);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function bitsetHas(bs, index) {
|
|
57
|
-
const word = index >>> 5;
|
|
58
|
-
if (word >= bs.length) return false;
|
|
59
|
-
return (bs[word] & 1 << (index & 31)) !== 0;
|
|
60
|
-
}
|
|
61
|
-
function bitsetAnd(a, b) {
|
|
62
|
-
const len = Math.min(a.length, b.length);
|
|
63
|
-
const result = new Uint32Array(len);
|
|
64
|
-
for (let i = 0; i < len; i++) {
|
|
65
|
-
result[i] = a[i] & b[i];
|
|
66
|
-
}
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
function bitsetOr(a, b) {
|
|
70
|
-
const longer = a.length >= b.length ? a : b;
|
|
71
|
-
const shorter = a.length >= b.length ? b : a;
|
|
72
|
-
const result = new Uint32Array(longer.length);
|
|
73
|
-
for (let i = 0; i < shorter.length; i++) {
|
|
74
|
-
result[i] = longer[i] | shorter[i];
|
|
75
|
-
}
|
|
76
|
-
for (let i = shorter.length; i < longer.length; i++) {
|
|
77
|
-
result[i] = longer[i];
|
|
78
|
-
}
|
|
79
|
-
return result;
|
|
20
|
+
// src/core/tokenizer/normalize.ts
|
|
21
|
+
var DOTTED_CAPITAL_I = "\u0130";
|
|
22
|
+
var COMBINING_DOT_ABOVE = "\u0307";
|
|
23
|
+
var ARMENIAN_MARKS = /[\u055B-\u055F]/;
|
|
24
|
+
var FOLDED_FORMS = /\u0307|[\u0130\u055B-\u055F\u2018\u2019\u02BC\u02BB]/g;
|
|
25
|
+
var WIDTH_FORMS = /[\uFF01-\uFF5E\uFF61-\uFF9F]/;
|
|
26
|
+
var WIDTH_FORMS_GLOBAL = /[\uFF01-\uFF5E\uFF61-\uFF9F]/g;
|
|
27
|
+
var FULLWIDTH_ASCII_END = 65374;
|
|
28
|
+
var FULLWIDTH_ASCII_OFFSET = 65248;
|
|
29
|
+
var HALFWIDTH_KANA_START = 65377;
|
|
30
|
+
var HALFWIDTH_VOICED_MARK = 65438;
|
|
31
|
+
var HALFWIDTH_SEMI_VOICED_MARK = 65439;
|
|
32
|
+
var COMBINING_VOICED_MARK = "\u3099";
|
|
33
|
+
var COMBINING_SEMI_VOICED_MARK = "\u309A";
|
|
34
|
+
var HALFWIDTH_KANA_TARGETS = "\u3002\u300C\u300D\u3001\u30FB\u30F2\u30A1\u30A3\u30A5\u30A7\u30A9\u30E3\u30E5\u30E7\u30C3\u30FC\u30A2\u30A4\u30A6\u30A8\u30AA\u30AB\u30AD\u30AF\u30B1\u30B3\u30B5\u30B7\u30B9\u30BB\u30BD\u30BF\u30C1\u30C4\u30C6\u30C8\u30CA\u30CB\u30CC\u30CD\u30CE\u30CF\u30D2\u30D5\u30D8\u30DB\u30DE\u30DF\u30E0\u30E1\u30E2\u30E4\u30E6\u30E8\u30E9\u30EA\u30EB\u30EC\u30ED\u30EF\u30F3";
|
|
35
|
+
function foldForm(match) {
|
|
36
|
+
if (match === DOTTED_CAPITAL_I) return "i";
|
|
37
|
+
if (match === COMBINING_DOT_ABOVE || ARMENIAN_MARKS.test(match)) return "";
|
|
38
|
+
return "'";
|
|
39
|
+
}
|
|
40
|
+
function foldWidth(match) {
|
|
41
|
+
const codePoint = match.charCodeAt(0);
|
|
42
|
+
if (codePoint <= FULLWIDTH_ASCII_END) return String.fromCharCode(codePoint - FULLWIDTH_ASCII_OFFSET);
|
|
43
|
+
if (codePoint === HALFWIDTH_VOICED_MARK) return COMBINING_VOICED_MARK;
|
|
44
|
+
if (codePoint === HALFWIDTH_SEMI_VOICED_MARK) return COMBINING_SEMI_VOICED_MARK;
|
|
45
|
+
return HALFWIDTH_KANA_TARGETS[codePoint - HALFWIDTH_KANA_START];
|
|
80
46
|
}
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
for (let i = 0; i < fullWords; i++) {
|
|
85
|
-
result[i] = ~bs[i];
|
|
86
|
-
}
|
|
87
|
-
const remainder = capacity & 31;
|
|
88
|
-
if (remainder > 0 && fullWords < bs.length) {
|
|
89
|
-
result[fullWords] = ~bs[fullWords] & (1 << remainder) - 1;
|
|
90
|
-
}
|
|
91
|
-
return result;
|
|
92
|
-
}
|
|
93
|
-
function bitsetIsEmpty(bs) {
|
|
94
|
-
for (let i = 0; i < bs.length; i++) {
|
|
95
|
-
if (bs[i] !== 0) return false;
|
|
47
|
+
function isAscii(text) {
|
|
48
|
+
for (let i = 0; i < text.length; i++) {
|
|
49
|
+
if (text.charCodeAt(i) > 127) return false;
|
|
96
50
|
}
|
|
97
51
|
return true;
|
|
98
52
|
}
|
|
99
|
-
function
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
bs[id >>> 5] |= 1 << (id & 31);
|
|
103
|
-
}
|
|
104
|
-
return bs;
|
|
53
|
+
function foldWidthForms(text) {
|
|
54
|
+
if (!WIDTH_FORMS.test(text)) return text;
|
|
55
|
+
return text.replace(WIDTH_FORMS_GLOBAL, foldWidth);
|
|
105
56
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const n = b.length;
|
|
113
|
-
if (m === 0) {
|
|
114
|
-
return n <= tolerance ? { distance: n, withinTolerance: true } : { distance: n, withinTolerance: false };
|
|
115
|
-
}
|
|
116
|
-
if (n === 0) {
|
|
117
|
-
return m <= tolerance ? { distance: m, withinTolerance: true } : { distance: m, withinTolerance: false };
|
|
118
|
-
}
|
|
119
|
-
if (a.startsWith(b)) {
|
|
120
|
-
const diff2 = m - n;
|
|
121
|
-
return diff2 <= tolerance ? { distance: diff2, withinTolerance: true } : { distance: diff2, withinTolerance: false };
|
|
122
|
-
}
|
|
123
|
-
if (b.startsWith(a)) {
|
|
124
|
-
return { distance: 0, withinTolerance: true };
|
|
125
|
-
}
|
|
126
|
-
const diff = Math.abs(m - n);
|
|
127
|
-
if (diff > tolerance) return { distance: -1, withinTolerance: false };
|
|
128
|
-
const matrix = [];
|
|
129
|
-
for (let i = 0; i <= m; i++) {
|
|
130
|
-
matrix[i] = [i];
|
|
131
|
-
for (let j = 1; j <= n; j++) {
|
|
132
|
-
matrix[i][j] = i === 0 ? j : 0;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
for (let i = 1; i <= m; i++) {
|
|
136
|
-
let rowMin = Infinity;
|
|
137
|
-
for (let j = 1; j <= n; j++) {
|
|
138
|
-
if (a[i - 1] === b[j - 1]) {
|
|
139
|
-
matrix[i][j] = matrix[i - 1][j - 1];
|
|
140
|
-
} else {
|
|
141
|
-
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + 1);
|
|
142
|
-
}
|
|
143
|
-
rowMin = Math.min(rowMin, matrix[i][j]);
|
|
144
|
-
}
|
|
145
|
-
if (rowMin > tolerance) {
|
|
146
|
-
return { distance: -1, withinTolerance: false };
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
const finalDistance = matrix[m][n];
|
|
150
|
-
return {
|
|
151
|
-
distance: finalDistance,
|
|
152
|
-
withinTolerance: finalDistance <= tolerance
|
|
153
|
-
};
|
|
57
|
+
function normalizeForSplitting(text) {
|
|
58
|
+
if (isAscii(text)) return text.toLowerCase();
|
|
59
|
+
return foldWidthForms(text).normalize("NFC").replace(FOLDED_FORMS, foldForm).toLowerCase();
|
|
60
|
+
}
|
|
61
|
+
function stripDiacritics(text) {
|
|
62
|
+
return text.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
154
63
|
}
|
|
155
64
|
|
|
156
|
-
// src/core/tokenizer.ts
|
|
157
|
-
var DEFAULT_SPLIT_PATTERN = /[^\p{L}\p{N}_'-]+/u;
|
|
158
|
-
var DEFAULT_MIN_TOKEN_LENGTH = 1;
|
|
65
|
+
// src/core/tokenizer/cache.ts
|
|
159
66
|
var CACHE_SIZE_FLOOR = 5e4;
|
|
160
67
|
var CACHE_SIZE_CEILING = 2e6;
|
|
161
68
|
var BYTES_PER_ENTRY = 200;
|
|
69
|
+
var NODE_CACHE_ENTRIES = 1e6;
|
|
70
|
+
var UNKNOWN_MEMORY_CACHE_ENTRIES = 2e5;
|
|
71
|
+
function clampCacheSize(entries) {
|
|
72
|
+
return Math.max(CACHE_SIZE_FLOOR, Math.min(entries, CACHE_SIZE_CEILING));
|
|
73
|
+
}
|
|
162
74
|
function computeDefaultCacheSize() {
|
|
163
75
|
try {
|
|
164
76
|
if (typeof process !== "undefined" && typeof process.versions?.node === "string" && typeof window === "undefined") {
|
|
165
77
|
const constrainedMemory = typeof process.constrainedMemory === "function" ? process.constrainedMemory() : 0;
|
|
166
78
|
if (constrainedMemory > 0) {
|
|
167
|
-
|
|
168
|
-
return Math.max(CACHE_SIZE_FLOOR, Math.min(budget, CACHE_SIZE_CEILING));
|
|
79
|
+
return clampCacheSize(Math.floor(constrainedMemory * 0.05 / BYTES_PER_ENTRY));
|
|
169
80
|
}
|
|
170
|
-
return
|
|
81
|
+
return clampCacheSize(NODE_CACHE_ENTRIES);
|
|
171
82
|
}
|
|
172
83
|
if (typeof navigator !== "undefined") {
|
|
173
84
|
const mem = navigator.deviceMemory;
|
|
@@ -176,17 +87,20 @@ function computeDefaultCacheSize() {
|
|
|
176
87
|
if (mem <= 1) entries = 1e5;
|
|
177
88
|
else if (mem <= 4) entries = 25e4;
|
|
178
89
|
else entries = 5e5;
|
|
179
|
-
return
|
|
90
|
+
return clampCacheSize(entries);
|
|
180
91
|
}
|
|
181
|
-
return Math.max(CACHE_SIZE_FLOOR, Math.min(2e5, CACHE_SIZE_CEILING));
|
|
182
92
|
}
|
|
183
93
|
} catch {
|
|
94
|
+
return clampCacheSize(UNKNOWN_MEMORY_CACHE_ENTRIES);
|
|
184
95
|
}
|
|
185
|
-
return
|
|
96
|
+
return clampCacheSize(UNKNOWN_MEMORY_CACHE_ENTRIES);
|
|
186
97
|
}
|
|
187
98
|
var normalizationCache = /* @__PURE__ */ new Map();
|
|
188
99
|
var normalizationCacheSize = 0;
|
|
189
100
|
var maxCacheSize = computeDefaultCacheSize();
|
|
101
|
+
var cachedLangName = "";
|
|
102
|
+
var cachedFlags = "";
|
|
103
|
+
var cachedBucket = null;
|
|
190
104
|
function configureNormalizationCache(maxSize) {
|
|
191
105
|
if (!Number.isFinite(maxSize)) {
|
|
192
106
|
throw createNarsilError(ErrorCodes.CONFIG_INVALID, "tokenizerCacheSize must be a finite number", {
|
|
@@ -212,26 +126,16 @@ function configureNormalizationCache(maxSize) {
|
|
|
212
126
|
evictOldestEntries(normalizationCacheSize - maxCacheSize);
|
|
213
127
|
}
|
|
214
128
|
}
|
|
215
|
-
var cachedLangName = "";
|
|
216
|
-
var cachedFlags = "";
|
|
217
|
-
var cachedBucket = null;
|
|
218
|
-
function stripDiacritics(text) {
|
|
219
|
-
return text.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
220
|
-
}
|
|
221
|
-
function resolveStopWords(language, override) {
|
|
222
|
-
if (!override) return language.stopWords;
|
|
223
|
-
if (override instanceof Set) return override;
|
|
224
|
-
return override(language.stopWords);
|
|
225
|
-
}
|
|
226
129
|
function getCacheBucket(language, flags) {
|
|
227
|
-
|
|
228
|
-
|
|
130
|
+
const langKey = `${language.name}@${language.revision}`;
|
|
131
|
+
if (cachedBucket && langKey === cachedLangName && flags === cachedFlags) return cachedBucket;
|
|
132
|
+
const key = `${langKey}:${flags}`;
|
|
229
133
|
let bucket = normalizationCache.get(key);
|
|
230
134
|
if (!bucket) {
|
|
231
135
|
bucket = /* @__PURE__ */ new Map();
|
|
232
136
|
normalizationCache.set(key, bucket);
|
|
233
137
|
}
|
|
234
|
-
cachedLangName =
|
|
138
|
+
cachedLangName = langKey;
|
|
235
139
|
cachedFlags = flags;
|
|
236
140
|
cachedBucket = bucket;
|
|
237
141
|
return bucket;
|
|
@@ -263,6 +167,9 @@ function transformToken(raw, language, stem, removeDiacritics) {
|
|
|
263
167
|
const cached = bucket.get(raw);
|
|
264
168
|
if (cached !== void 0) return cached;
|
|
265
169
|
let normalized = raw;
|
|
170
|
+
if (language.normalizer) {
|
|
171
|
+
normalized = language.normalizer(normalized);
|
|
172
|
+
}
|
|
266
173
|
if (removeDiacritics) {
|
|
267
174
|
normalized = stripDiacritics(normalized);
|
|
268
175
|
}
|
|
@@ -277,9 +184,173 @@ function transformToken(raw, language, stem, removeDiacritics) {
|
|
|
277
184
|
normalizationCacheSize++;
|
|
278
185
|
return normalized;
|
|
279
186
|
}
|
|
187
|
+
function clearNormalizationCache() {
|
|
188
|
+
normalizationCache.clear();
|
|
189
|
+
normalizationCacheSize = 0;
|
|
190
|
+
cachedBucket = null;
|
|
191
|
+
}
|
|
192
|
+
function resetNormalizationCache() {
|
|
193
|
+
clearNormalizationCache();
|
|
194
|
+
maxCacheSize = computeDefaultCacheSize();
|
|
195
|
+
}
|
|
196
|
+
function getNormalizationCacheSize() {
|
|
197
|
+
return normalizationCacheSize;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/core/tokenizer/ngrams.ts
|
|
201
|
+
var OTHER_SCRIPT = 0;
|
|
202
|
+
var HAN_SCRIPT = 1;
|
|
203
|
+
var HIRAGANA_SCRIPT = 2;
|
|
204
|
+
var KATAKANA_SCRIPT = 3;
|
|
205
|
+
var HANGUL_SCRIPT = 4;
|
|
206
|
+
var THAI_SCRIPT = 5;
|
|
207
|
+
var LAO_SCRIPT = 6;
|
|
208
|
+
var KHMER_SCRIPT = 7;
|
|
209
|
+
var MYANMAR_SCRIPT = 8;
|
|
210
|
+
var PROLONGED_SOUND_MARK = 12540;
|
|
211
|
+
var IDEOGRAPHIC_ITERATION_MARK = 12293;
|
|
212
|
+
var LOWEST_NGRAM_CODE_POINT = 3584;
|
|
213
|
+
var LOWEST_MARK_CODE_POINT = 768;
|
|
214
|
+
var THAI_BLOCK_END = 3711;
|
|
215
|
+
var LAO_BLOCK_END = 3839;
|
|
216
|
+
var MYANMAR_BLOCK_START = 4096;
|
|
217
|
+
var MYANMAR_BLOCK_END = 4255;
|
|
218
|
+
var KHMER_BLOCK_START = 6016;
|
|
219
|
+
var KHMER_BLOCK_END = 6655;
|
|
220
|
+
var SOUTHEAST_ASIAN_BLOCKS_END = 6656;
|
|
221
|
+
var HIRAGANA_BLOCK_START = 12352;
|
|
222
|
+
var HIRAGANA_BLOCK_END = 12447;
|
|
223
|
+
var COMBINING_VOICED_MARK2 = 12441;
|
|
224
|
+
var COMBINING_SEMI_VOICED_MARK2 = 12442;
|
|
225
|
+
var KATAKANA_BLOCK_START = 12448;
|
|
226
|
+
var KATAKANA_BLOCK_END = 12543;
|
|
227
|
+
var HAN_EXTENSION_A_START = 13312;
|
|
228
|
+
var HAN_EXTENSION_A_END = 19903;
|
|
229
|
+
var HAN_UNIFIED_START = 19968;
|
|
230
|
+
var HAN_UNIFIED_END = 40959;
|
|
231
|
+
var HANGUL_SYLLABLE_START = 44032;
|
|
232
|
+
var HANGUL_SYLLABLE_END = 55203;
|
|
233
|
+
var HAN_COMPATIBILITY_START = 63744;
|
|
234
|
+
var HAN_COMPATIBILITY_END = 64255;
|
|
235
|
+
var SUPPLEMENTARY_PLANE_START = 65536;
|
|
236
|
+
var MARK = /\p{M}/uy;
|
|
237
|
+
var HAN = /\p{Script=Han}/uy;
|
|
238
|
+
var HIRAGANA = /\p{Script=Hiragana}/uy;
|
|
239
|
+
var KATAKANA = /\p{Script=Katakana}/uy;
|
|
240
|
+
var HANGUL = /\p{Script=Hangul}/uy;
|
|
241
|
+
var THAI = /\p{Script=Thai}/uy;
|
|
242
|
+
var LAO = /\p{Script=Lao}/uy;
|
|
243
|
+
var KHMER = /\p{Script=Khmer}/uy;
|
|
244
|
+
var MYANMAR = /\p{Script=Myanmar}/uy;
|
|
245
|
+
function matchesAt(pattern, part, index) {
|
|
246
|
+
pattern.lastIndex = index;
|
|
247
|
+
return pattern.test(part);
|
|
248
|
+
}
|
|
249
|
+
function isMark(part, index, codePoint) {
|
|
250
|
+
if (codePoint < LOWEST_MARK_CODE_POINT) return false;
|
|
251
|
+
if (codePoint >= HAN_UNIFIED_START && codePoint <= HAN_UNIFIED_END) return false;
|
|
252
|
+
if (codePoint >= HIRAGANA_BLOCK_START && codePoint <= KATAKANA_BLOCK_END) {
|
|
253
|
+
return codePoint === COMBINING_VOICED_MARK2 || codePoint === COMBINING_SEMI_VOICED_MARK2;
|
|
254
|
+
}
|
|
255
|
+
if (codePoint >= HANGUL_SYLLABLE_START && codePoint <= HANGUL_SYLLABLE_END) return false;
|
|
256
|
+
if (codePoint >= HAN_EXTENSION_A_START && codePoint <= HAN_EXTENSION_A_END) return false;
|
|
257
|
+
return matchesAt(MARK, part, index);
|
|
258
|
+
}
|
|
259
|
+
function classifyOutsideCommonBlocks(part, index) {
|
|
260
|
+
if (matchesAt(HAN, part, index)) return HAN_SCRIPT;
|
|
261
|
+
if (matchesAt(HIRAGANA, part, index)) return HIRAGANA_SCRIPT;
|
|
262
|
+
if (matchesAt(KATAKANA, part, index)) return KATAKANA_SCRIPT;
|
|
263
|
+
if (matchesAt(HANGUL, part, index)) return HANGUL_SCRIPT;
|
|
264
|
+
if (matchesAt(THAI, part, index)) return THAI_SCRIPT;
|
|
265
|
+
if (matchesAt(LAO, part, index)) return LAO_SCRIPT;
|
|
266
|
+
if (matchesAt(KHMER, part, index)) return KHMER_SCRIPT;
|
|
267
|
+
if (matchesAt(MYANMAR, part, index)) return MYANMAR_SCRIPT;
|
|
268
|
+
return OTHER_SCRIPT;
|
|
269
|
+
}
|
|
270
|
+
function classifySoutheastAsian(part, index, codePoint) {
|
|
271
|
+
if (codePoint <= THAI_BLOCK_END) return matchesAt(THAI, part, index) ? THAI_SCRIPT : OTHER_SCRIPT;
|
|
272
|
+
if (codePoint <= LAO_BLOCK_END) return matchesAt(LAO, part, index) ? LAO_SCRIPT : OTHER_SCRIPT;
|
|
273
|
+
if (codePoint >= MYANMAR_BLOCK_START && codePoint <= MYANMAR_BLOCK_END) {
|
|
274
|
+
return matchesAt(MYANMAR, part, index) ? MYANMAR_SCRIPT : OTHER_SCRIPT;
|
|
275
|
+
}
|
|
276
|
+
if (codePoint >= KHMER_BLOCK_START && codePoint <= KHMER_BLOCK_END) {
|
|
277
|
+
return matchesAt(KHMER, part, index) ? KHMER_SCRIPT : OTHER_SCRIPT;
|
|
278
|
+
}
|
|
279
|
+
return classifyOutsideCommonBlocks(part, index);
|
|
280
|
+
}
|
|
281
|
+
function classify(part, index, codePoint, current) {
|
|
282
|
+
if (codePoint < LOWEST_NGRAM_CODE_POINT) return OTHER_SCRIPT;
|
|
283
|
+
if (codePoint < SOUTHEAST_ASIAN_BLOCKS_END) return classifySoutheastAsian(part, index, codePoint);
|
|
284
|
+
if (codePoint === PROLONGED_SOUND_MARK) {
|
|
285
|
+
return current === HIRAGANA_SCRIPT ? HIRAGANA_SCRIPT : KATAKANA_SCRIPT;
|
|
286
|
+
}
|
|
287
|
+
if (codePoint >= HIRAGANA_BLOCK_START && codePoint <= HIRAGANA_BLOCK_END) return HIRAGANA_SCRIPT;
|
|
288
|
+
if (codePoint >= KATAKANA_BLOCK_START && codePoint <= KATAKANA_BLOCK_END) return KATAKANA_SCRIPT;
|
|
289
|
+
if (codePoint >= HAN_UNIFIED_START && codePoint <= HAN_UNIFIED_END) return HAN_SCRIPT;
|
|
290
|
+
if (codePoint >= HAN_EXTENSION_A_START && codePoint <= HAN_EXTENSION_A_END) return HAN_SCRIPT;
|
|
291
|
+
if (codePoint >= HANGUL_SYLLABLE_START && codePoint <= HANGUL_SYLLABLE_END) return HANGUL_SCRIPT;
|
|
292
|
+
if (codePoint >= HAN_COMPATIBILITY_START && codePoint <= HAN_COMPATIBILITY_END) return HAN_SCRIPT;
|
|
293
|
+
if (codePoint === IDEOGRAPHIC_ITERATION_MARK) return HAN_SCRIPT;
|
|
294
|
+
return classifyOutsideCommonBlocks(part, index);
|
|
295
|
+
}
|
|
296
|
+
function emitRun(part, offsets, kind, size, out) {
|
|
297
|
+
const count = offsets.length - 1;
|
|
298
|
+
if (count < 1) return;
|
|
299
|
+
if (kind === OTHER_SCRIPT || count <= size) {
|
|
300
|
+
out.push(part.slice(offsets[0], offsets[count]));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
for (let start = 0; start + size <= count; start++) {
|
|
304
|
+
out.push(part.slice(offsets[start], offsets[start + size]));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function expandNgrams(part, size, out) {
|
|
308
|
+
const length = part.length;
|
|
309
|
+
if (length === 0) return;
|
|
310
|
+
const offsets = [];
|
|
311
|
+
let kind = OTHER_SCRIPT;
|
|
312
|
+
let index = 0;
|
|
313
|
+
while (index < length) {
|
|
314
|
+
const codePoint = part.codePointAt(index);
|
|
315
|
+
if (codePoint === void 0) break;
|
|
316
|
+
const width = codePoint >= SUPPLEMENTARY_PLANE_START ? 2 : 1;
|
|
317
|
+
if (offsets.length > 0 && isMark(part, index, codePoint)) {
|
|
318
|
+
index += width;
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
const next = classify(part, index, codePoint, kind);
|
|
322
|
+
if (offsets.length > 0 && next !== kind) {
|
|
323
|
+
offsets.push(index);
|
|
324
|
+
emitRun(part, offsets, kind, size, out);
|
|
325
|
+
offsets.length = 0;
|
|
326
|
+
}
|
|
327
|
+
kind = next;
|
|
328
|
+
offsets.push(index);
|
|
329
|
+
index += width;
|
|
330
|
+
}
|
|
331
|
+
offsets.push(length);
|
|
332
|
+
emitRun(part, offsets, kind, size, out);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/core/tokenizer/tokenize.ts
|
|
336
|
+
var DEFAULT_SPLIT_PATTERN = /[^\p{L}\p{M}\p{N}_'-]+/u;
|
|
337
|
+
var DEFAULT_MIN_TOKEN_LENGTH = 1;
|
|
338
|
+
function resolveStopWords(language, override) {
|
|
339
|
+
if (!override) return language.stopWords;
|
|
340
|
+
if (override instanceof Set) return override;
|
|
341
|
+
return override(language.stopWords);
|
|
342
|
+
}
|
|
280
343
|
function splitText(text, language) {
|
|
281
344
|
const pattern = language.tokenizer?.splitPattern ?? DEFAULT_SPLIT_PATTERN;
|
|
282
|
-
|
|
345
|
+
const parts = text.split(pattern);
|
|
346
|
+
const ngramSize = language.tokenizer?.ngramSize;
|
|
347
|
+
if (ngramSize === void 0 || ngramSize < 1) return parts;
|
|
348
|
+
const size = Math.floor(ngramSize);
|
|
349
|
+
const expanded = [];
|
|
350
|
+
for (const part of parts) {
|
|
351
|
+
expandNgrams(part, size, expanded);
|
|
352
|
+
}
|
|
353
|
+
return expanded;
|
|
283
354
|
}
|
|
284
355
|
var CHAR_APOSTROPHE = 39;
|
|
285
356
|
var CHAR_S = 115;
|
|
@@ -293,12 +364,6 @@ function stripPossessive(token) {
|
|
|
293
364
|
}
|
|
294
365
|
return token;
|
|
295
366
|
}
|
|
296
|
-
function isAscii(text) {
|
|
297
|
-
for (let i = 0; i < text.length; i++) {
|
|
298
|
-
if (text.charCodeAt(i) > 127) return false;
|
|
299
|
-
}
|
|
300
|
-
return true;
|
|
301
|
-
}
|
|
302
367
|
function tokenize(text, language, options) {
|
|
303
368
|
const {
|
|
304
369
|
stem = true,
|
|
@@ -316,11 +381,11 @@ function tokenize(text, language, options) {
|
|
|
316
381
|
originalTokens: originals
|
|
317
382
|
};
|
|
318
383
|
}
|
|
319
|
-
const normalized =
|
|
384
|
+
const normalized = normalizeForSplitting(text);
|
|
320
385
|
const rawParts = splitText(normalized, language);
|
|
321
386
|
const minLength = language.tokenizer?.minTokenLength ?? DEFAULT_MIN_TOKEN_LENGTH;
|
|
322
387
|
const effectiveDiacritics = removeDiacritics || (language.tokenizer?.normalizeDiacritics ?? false);
|
|
323
|
-
const stemsTokens = stem && language.stemmer !==
|
|
388
|
+
const stemsTokens = stem && language.stemmer !== null;
|
|
324
389
|
const stopWords = removeStopWords ? resolveStopWords(language, stopWordOverride) : /* @__PURE__ */ new Set();
|
|
325
390
|
const stripPossessives = language.tokenizer?.stripPossessive ?? false;
|
|
326
391
|
const tokens = [];
|
|
@@ -348,66 +413,287 @@ function tokenize(text, language, options) {
|
|
|
348
413
|
}
|
|
349
414
|
position++;
|
|
350
415
|
}
|
|
351
|
-
return { tokens, originalTokens, surfaces };
|
|
352
|
-
}
|
|
353
|
-
function* tokenizeIterator(text, language, options) {
|
|
354
|
-
const {
|
|
355
|
-
stem = true,
|
|
356
|
-
removeStopWords = true,
|
|
357
|
-
removeDiacritics = false,
|
|
358
|
-
collectSurfaces = false,
|
|
359
|
-
customTokenizer,
|
|
360
|
-
stopWordOverride
|
|
361
|
-
} = options ?? {};
|
|
362
|
-
if (customTokenizer) {
|
|
363
|
-
const customResult = customTokenizer.tokenize(text);
|
|
364
|
-
for (const entry of customResult) {
|
|
365
|
-
yield entry;
|
|
416
|
+
return { tokens, originalTokens, surfaces };
|
|
417
|
+
}
|
|
418
|
+
function* tokenizeIterator(text, language, options) {
|
|
419
|
+
const {
|
|
420
|
+
stem = true,
|
|
421
|
+
removeStopWords = true,
|
|
422
|
+
removeDiacritics = false,
|
|
423
|
+
collectSurfaces = false,
|
|
424
|
+
customTokenizer,
|
|
425
|
+
stopWordOverride
|
|
426
|
+
} = options ?? {};
|
|
427
|
+
if (customTokenizer) {
|
|
428
|
+
const customResult = customTokenizer.tokenize(text);
|
|
429
|
+
for (const entry of customResult) {
|
|
430
|
+
yield entry;
|
|
431
|
+
}
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const normalized = normalizeForSplitting(text);
|
|
435
|
+
const rawParts = splitText(normalized, language);
|
|
436
|
+
const minLength = language.tokenizer?.minTokenLength ?? DEFAULT_MIN_TOKEN_LENGTH;
|
|
437
|
+
const effectiveDiacritics = removeDiacritics || (language.tokenizer?.normalizeDiacritics ?? false);
|
|
438
|
+
const stemsTokens = stem && language.stemmer !== null;
|
|
439
|
+
const wantSurfaces = collectSurfaces && stemsTokens;
|
|
440
|
+
const stopWords = removeStopWords ? resolveStopWords(language, stopWordOverride) : /* @__PURE__ */ new Set();
|
|
441
|
+
const stripPossessives = language.tokenizer?.stripPossessive ?? false;
|
|
442
|
+
let position = 0;
|
|
443
|
+
for (const part of rawParts) {
|
|
444
|
+
const candidate = stripPossessives ? stripPossessive(part) : part;
|
|
445
|
+
if (candidate.length < minLength) {
|
|
446
|
+
position++;
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (stopWords.has(candidate)) {
|
|
450
|
+
position++;
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
453
|
+
const processed = transformToken(candidate, language, stem, effectiveDiacritics);
|
|
454
|
+
if (processed.length > 0) {
|
|
455
|
+
if (wantSurfaces) {
|
|
456
|
+
const surface = effectiveDiacritics ? transformToken(candidate, language, false, true) : candidate;
|
|
457
|
+
yield { token: processed, position, surface: surface === processed ? void 0 : surface };
|
|
458
|
+
} else {
|
|
459
|
+
yield { token: processed, position };
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
position++;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// src/partitioning/distributed-scoring.ts
|
|
467
|
+
function analysedQueryTokens(term, language, analysis) {
|
|
468
|
+
const { tokens } = tokenize(term, language, {
|
|
469
|
+
stem: true,
|
|
470
|
+
removeStopWords: true,
|
|
471
|
+
customTokenizer: analysis.customTokenizer,
|
|
472
|
+
stopWordOverride: analysis.stopWords
|
|
473
|
+
});
|
|
474
|
+
const unique = /* @__PURE__ */ new Set();
|
|
475
|
+
for (const { token } of tokens) {
|
|
476
|
+
unique.add(token);
|
|
477
|
+
}
|
|
478
|
+
return unique;
|
|
479
|
+
}
|
|
480
|
+
function copyNumericRecord(source) {
|
|
481
|
+
const copy = /* @__PURE__ */ Object.create(null);
|
|
482
|
+
for (const [key, value] of Object.entries(source)) {
|
|
483
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
484
|
+
copy[key] = value;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return copy;
|
|
488
|
+
}
|
|
489
|
+
function sanitizeGlobalStats(stats) {
|
|
490
|
+
return {
|
|
491
|
+
totalDocuments: typeof stats.totalDocuments === "number" && Number.isFinite(stats.totalDocuments) ? stats.totalDocuments : 0,
|
|
492
|
+
docFrequencies: copyNumericRecord(stats.docFrequencies),
|
|
493
|
+
totalFieldLengths: copyNumericRecord(stats.totalFieldLengths),
|
|
494
|
+
averageFieldLengths: copyNumericRecord(stats.averageFieldLengths)
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
function pruneStatsToQueryTerms(stats, term, language, analysis) {
|
|
498
|
+
const docFrequencies = /* @__PURE__ */ Object.create(null);
|
|
499
|
+
for (const token of analysedQueryTokens(term, language, analysis)) {
|
|
500
|
+
if (Object.hasOwn(stats.docFrequencies, token)) {
|
|
501
|
+
docFrequencies[token] = stats.docFrequencies[token];
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return {
|
|
505
|
+
totalDocuments: stats.totalDocuments,
|
|
506
|
+
docFrequencies,
|
|
507
|
+
totalFieldLengths: stats.totalFieldLengths,
|
|
508
|
+
averageFieldLengths: stats.averageFieldLengths
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function collectQueryTermStats(manager, term, language, analysis) {
|
|
512
|
+
const queryTokens = analysedQueryTokens(term, language, analysis);
|
|
513
|
+
let totalDocuments = 0;
|
|
514
|
+
const docFrequencies = /* @__PURE__ */ Object.create(null);
|
|
515
|
+
const totalFieldLengths = /* @__PURE__ */ Object.create(null);
|
|
516
|
+
for (const partition of manager.getAllPartitions()) {
|
|
517
|
+
const stats = partition.stats;
|
|
518
|
+
totalDocuments += stats.totalDocuments;
|
|
519
|
+
for (const [field, length] of Object.entries(stats.totalFieldLengths)) {
|
|
520
|
+
totalFieldLengths[field] = (totalFieldLengths[field] ?? 0) + length;
|
|
521
|
+
}
|
|
522
|
+
for (const token of queryTokens) {
|
|
523
|
+
if (Object.hasOwn(stats.docFrequencies, token)) {
|
|
524
|
+
docFrequencies[token] = (docFrequencies[token] ?? 0) + stats.docFrequencies[token];
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
const averageFieldLengths = /* @__PURE__ */ Object.create(null);
|
|
529
|
+
if (totalDocuments > 0) {
|
|
530
|
+
for (const [field, totalLength] of Object.entries(totalFieldLengths)) {
|
|
531
|
+
averageFieldLengths[field] = totalLength / totalDocuments;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return { totalDocuments, docFrequencies, totalFieldLengths, averageFieldLengths };
|
|
535
|
+
}
|
|
536
|
+
function mergePartitionStats(statsArray) {
|
|
537
|
+
let totalDocuments = 0;
|
|
538
|
+
const docFrequencies = /* @__PURE__ */ Object.create(null);
|
|
539
|
+
const totalFieldLengths = /* @__PURE__ */ Object.create(null);
|
|
540
|
+
for (const stats of statsArray) {
|
|
541
|
+
totalDocuments += stats.totalDocuments;
|
|
542
|
+
for (const [term, freq] of Object.entries(stats.docFrequencies)) {
|
|
543
|
+
docFrequencies[term] = (docFrequencies[term] ?? 0) + freq;
|
|
544
|
+
}
|
|
545
|
+
for (const [field, length] of Object.entries(stats.totalFieldLengths)) {
|
|
546
|
+
totalFieldLengths[field] = (totalFieldLengths[field] ?? 0) + length;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
const averageFieldLengths = /* @__PURE__ */ Object.create(null);
|
|
550
|
+
if (totalDocuments > 0) {
|
|
551
|
+
for (const [field, totalLength] of Object.entries(totalFieldLengths)) {
|
|
552
|
+
averageFieldLengths[field] = totalLength / totalDocuments;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
return {
|
|
556
|
+
totalDocuments,
|
|
557
|
+
docFrequencies,
|
|
558
|
+
totalFieldLengths,
|
|
559
|
+
averageFieldLengths
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/search/facets.ts
|
|
564
|
+
function mergeFacets(partitionFacets) {
|
|
565
|
+
const merged = /* @__PURE__ */ new Map();
|
|
566
|
+
for (const partition of partitionFacets) {
|
|
567
|
+
for (const [field, facetResult] of Object.entries(partition)) {
|
|
568
|
+
let fieldMap = merged.get(field);
|
|
569
|
+
if (!fieldMap) {
|
|
570
|
+
fieldMap = /* @__PURE__ */ new Map();
|
|
571
|
+
merged.set(field, fieldMap);
|
|
572
|
+
}
|
|
573
|
+
for (const [value, count] of Object.entries(facetResult.values)) {
|
|
574
|
+
fieldMap.set(value, (fieldMap.get(value) ?? 0) + count);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const result = {};
|
|
579
|
+
for (const [field, valueMap] of merged) {
|
|
580
|
+
const values = {};
|
|
581
|
+
for (const [value, count] of valueMap) {
|
|
582
|
+
values[value] = count;
|
|
583
|
+
}
|
|
584
|
+
result[field] = { values, count: valueMap.size };
|
|
585
|
+
}
|
|
586
|
+
return result;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// src/core/bitset.ts
|
|
590
|
+
function createBitSet(capacity) {
|
|
591
|
+
return new Uint32Array(capacity + 31 >>> 5 || 1);
|
|
592
|
+
}
|
|
593
|
+
function bitsetSet(bs, index) {
|
|
594
|
+
const word = index >>> 5;
|
|
595
|
+
if (word < bs.length) {
|
|
596
|
+
bs[word] |= 1 << (index & 31);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
function bitsetHas(bs, index) {
|
|
600
|
+
const word = index >>> 5;
|
|
601
|
+
if (word >= bs.length) return false;
|
|
602
|
+
return (bs[word] & 1 << (index & 31)) !== 0;
|
|
603
|
+
}
|
|
604
|
+
function bitsetAnd(a, b) {
|
|
605
|
+
const len = Math.min(a.length, b.length);
|
|
606
|
+
const result = new Uint32Array(len);
|
|
607
|
+
for (let i = 0; i < len; i++) {
|
|
608
|
+
result[i] = a[i] & b[i];
|
|
609
|
+
}
|
|
610
|
+
return result;
|
|
611
|
+
}
|
|
612
|
+
function bitsetOr(a, b) {
|
|
613
|
+
const longer = a.length >= b.length ? a : b;
|
|
614
|
+
const shorter = a.length >= b.length ? b : a;
|
|
615
|
+
const result = new Uint32Array(longer.length);
|
|
616
|
+
for (let i = 0; i < shorter.length; i++) {
|
|
617
|
+
result[i] = longer[i] | shorter[i];
|
|
618
|
+
}
|
|
619
|
+
for (let i = shorter.length; i < longer.length; i++) {
|
|
620
|
+
result[i] = longer[i];
|
|
621
|
+
}
|
|
622
|
+
return result;
|
|
623
|
+
}
|
|
624
|
+
function bitsetNot(bs, capacity) {
|
|
625
|
+
const result = new Uint32Array(bs.length);
|
|
626
|
+
const fullWords = capacity >>> 5;
|
|
627
|
+
for (let i = 0; i < fullWords; i++) {
|
|
628
|
+
result[i] = ~bs[i];
|
|
629
|
+
}
|
|
630
|
+
const remainder = capacity & 31;
|
|
631
|
+
if (remainder > 0 && fullWords < bs.length) {
|
|
632
|
+
result[fullWords] = ~bs[fullWords] & (1 << remainder) - 1;
|
|
633
|
+
}
|
|
634
|
+
return result;
|
|
635
|
+
}
|
|
636
|
+
function bitsetIsEmpty(bs) {
|
|
637
|
+
for (let i = 0; i < bs.length; i++) {
|
|
638
|
+
if (bs[i] !== 0) return false;
|
|
639
|
+
}
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
function bitsetFromSet(set, capacity) {
|
|
643
|
+
const bs = createBitSet(capacity);
|
|
644
|
+
for (const id of set) {
|
|
645
|
+
bs[id >>> 5] |= 1 << (id & 31);
|
|
646
|
+
}
|
|
647
|
+
return bs;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// src/core/fuzzy.ts
|
|
651
|
+
function boundedLevenshtein(a, b, tolerance) {
|
|
652
|
+
if (tolerance < 0) return { distance: -1, withinTolerance: false };
|
|
653
|
+
if (a === b) return { distance: 0, withinTolerance: true };
|
|
654
|
+
const m = a.length;
|
|
655
|
+
const n = b.length;
|
|
656
|
+
if (m === 0) {
|
|
657
|
+
return n <= tolerance ? { distance: n, withinTolerance: true } : { distance: n, withinTolerance: false };
|
|
658
|
+
}
|
|
659
|
+
if (n === 0) {
|
|
660
|
+
return m <= tolerance ? { distance: m, withinTolerance: true } : { distance: m, withinTolerance: false };
|
|
661
|
+
}
|
|
662
|
+
if (a.startsWith(b)) {
|
|
663
|
+
const diff2 = m - n;
|
|
664
|
+
return diff2 <= tolerance ? { distance: diff2, withinTolerance: true } : { distance: diff2, withinTolerance: false };
|
|
665
|
+
}
|
|
666
|
+
if (b.startsWith(a)) {
|
|
667
|
+
return { distance: 0, withinTolerance: true };
|
|
668
|
+
}
|
|
669
|
+
const diff = Math.abs(m - n);
|
|
670
|
+
if (diff > tolerance) return { distance: -1, withinTolerance: false };
|
|
671
|
+
const matrix = [];
|
|
672
|
+
for (let i = 0; i <= m; i++) {
|
|
673
|
+
matrix[i] = [i];
|
|
674
|
+
for (let j = 1; j <= n; j++) {
|
|
675
|
+
matrix[i][j] = i === 0 ? j : 0;
|
|
366
676
|
}
|
|
367
|
-
return;
|
|
368
677
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
const wantSurfaces = collectSurfaces && stemsTokens;
|
|
375
|
-
const stopWords = removeStopWords ? resolveStopWords(language, stopWordOverride) : /* @__PURE__ */ new Set();
|
|
376
|
-
const stripPossessives = language.tokenizer?.stripPossessive ?? false;
|
|
377
|
-
let position = 0;
|
|
378
|
-
for (const part of rawParts) {
|
|
379
|
-
const candidate = stripPossessives ? stripPossessive(part) : part;
|
|
380
|
-
if (candidate.length < minLength) {
|
|
381
|
-
position++;
|
|
382
|
-
continue;
|
|
383
|
-
}
|
|
384
|
-
if (stopWords.has(candidate)) {
|
|
385
|
-
position++;
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
const processed = transformToken(candidate, language, stem, effectiveDiacritics);
|
|
389
|
-
if (processed.length > 0) {
|
|
390
|
-
if (wantSurfaces) {
|
|
391
|
-
const surface = effectiveDiacritics ? transformToken(candidate, language, false, true) : candidate;
|
|
392
|
-
yield { token: processed, position, surface: surface === processed ? void 0 : surface };
|
|
678
|
+
for (let i = 1; i <= m; i++) {
|
|
679
|
+
let rowMin = Infinity;
|
|
680
|
+
for (let j = 1; j <= n; j++) {
|
|
681
|
+
if (a[i - 1] === b[j - 1]) {
|
|
682
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
393
683
|
} else {
|
|
394
|
-
|
|
684
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + 1);
|
|
395
685
|
}
|
|
686
|
+
rowMin = Math.min(rowMin, matrix[i][j]);
|
|
687
|
+
}
|
|
688
|
+
if (rowMin > tolerance) {
|
|
689
|
+
return { distance: -1, withinTolerance: false };
|
|
396
690
|
}
|
|
397
|
-
position++;
|
|
398
691
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
function resetNormalizationCache() {
|
|
406
|
-
clearNormalizationCache();
|
|
407
|
-
maxCacheSize = computeDefaultCacheSize();
|
|
408
|
-
}
|
|
409
|
-
function getNormalizationCacheSize() {
|
|
410
|
-
return normalizationCacheSize;
|
|
692
|
+
const finalDistance = matrix[m][n];
|
|
693
|
+
return {
|
|
694
|
+
distance: finalDistance,
|
|
695
|
+
withinTolerance: finalDistance <= tolerance
|
|
696
|
+
};
|
|
411
697
|
}
|
|
412
698
|
|
|
413
699
|
// src/schema/validator/shared.ts
|
|
@@ -979,49 +1265,6 @@ function queryTermSatisfied(queryToken, indexTokens, tolerance, exact) {
|
|
|
979
1265
|
return false;
|
|
980
1266
|
}
|
|
981
1267
|
|
|
982
|
-
// src/partitioning/distributed-scoring.ts
|
|
983
|
-
function collectGlobalStats(manager) {
|
|
984
|
-
const aggregate = manager.getAggregateStats();
|
|
985
|
-
const averageFieldLengths = {};
|
|
986
|
-
if (aggregate.totalDocuments > 0) {
|
|
987
|
-
for (const [field, totalLength] of Object.entries(aggregate.totalFieldLengths)) {
|
|
988
|
-
averageFieldLengths[field] = totalLength / aggregate.totalDocuments;
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
return {
|
|
992
|
-
totalDocuments: aggregate.totalDocuments,
|
|
993
|
-
docFrequencies: aggregate.docFrequencies,
|
|
994
|
-
totalFieldLengths: aggregate.totalFieldLengths,
|
|
995
|
-
averageFieldLengths
|
|
996
|
-
};
|
|
997
|
-
}
|
|
998
|
-
function mergePartitionStats(statsArray) {
|
|
999
|
-
let totalDocuments = 0;
|
|
1000
|
-
const docFrequencies = {};
|
|
1001
|
-
const totalFieldLengths = {};
|
|
1002
|
-
for (const stats of statsArray) {
|
|
1003
|
-
totalDocuments += stats.totalDocuments;
|
|
1004
|
-
for (const [term, freq] of Object.entries(stats.docFrequencies)) {
|
|
1005
|
-
docFrequencies[term] = (docFrequencies[term] ?? 0) + freq;
|
|
1006
|
-
}
|
|
1007
|
-
for (const [field, length] of Object.entries(stats.totalFieldLengths)) {
|
|
1008
|
-
totalFieldLengths[field] = (totalFieldLengths[field] ?? 0) + length;
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
const averageFieldLengths = {};
|
|
1012
|
-
if (totalDocuments > 0) {
|
|
1013
|
-
for (const [field, totalLength] of Object.entries(totalFieldLengths)) {
|
|
1014
|
-
averageFieldLengths[field] = totalLength / totalDocuments;
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
return {
|
|
1018
|
-
totalDocuments,
|
|
1019
|
-
docFrequencies,
|
|
1020
|
-
totalFieldLengths,
|
|
1021
|
-
averageFieldLengths
|
|
1022
|
-
};
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
1268
|
// src/partitioning/fan-out.ts
|
|
1026
1269
|
async function fanOutQuery(manager, params, language, schema, config, searchOptions) {
|
|
1027
1270
|
const partitions = config.partitionIds ? config.partitionIds.map((id) => manager.partitionAt(id)).filter((p) => p !== void 0) : manager.getAllPartitions();
|
|
@@ -1031,7 +1274,12 @@ async function fanOutQuery(manager, params, language, schema, config, searchOpti
|
|
|
1031
1274
|
let globalStats;
|
|
1032
1275
|
const effectiveMode = resolveEffectiveMode(config);
|
|
1033
1276
|
if (effectiveMode === "dfs") {
|
|
1034
|
-
|
|
1277
|
+
if (params.term !== void 0 && params.term.trim().length > 0) {
|
|
1278
|
+
globalStats = collectQueryTermStats(manager, params.term, language, {
|
|
1279
|
+
stopWords: searchOptions?.stopWords,
|
|
1280
|
+
customTokenizer: searchOptions?.customTokenizer
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1035
1283
|
} else if (effectiveMode === "broadcast") {
|
|
1036
1284
|
globalStats = config.globalStats;
|
|
1037
1285
|
}
|
|
@@ -1212,6 +1460,232 @@ function heapPop(heap) {
|
|
|
1212
1460
|
}
|
|
1213
1461
|
return top;
|
|
1214
1462
|
}
|
|
1463
|
+
|
|
1464
|
+
// src/analysis/registry.ts
|
|
1465
|
+
var tokenizers = /* @__PURE__ */ new Map();
|
|
1466
|
+
var stopWordSets = /* @__PURE__ */ new Map();
|
|
1467
|
+
function requireName(name, kind) {
|
|
1468
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
1469
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `A registered ${kind} needs a non-empty name`, { name });
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
function registerTokenizer(name, tokenizer) {
|
|
1473
|
+
requireName(name, "tokenizer");
|
|
1474
|
+
if (typeof tokenizer?.tokenize !== "function") {
|
|
1475
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `Tokenizer "${name}" needs a tokenize method`, { tokenizer: name });
|
|
1476
|
+
}
|
|
1477
|
+
tokenizers.set(name, tokenizer);
|
|
1478
|
+
}
|
|
1479
|
+
function registerStopWords(name, stopWords) {
|
|
1480
|
+
requireName(name, "stop word set");
|
|
1481
|
+
if (!(stopWords instanceof Set) && typeof stopWords !== "function") {
|
|
1482
|
+
throw new NarsilError(
|
|
1483
|
+
ErrorCodes.CONFIG_INVALID,
|
|
1484
|
+
`Stop word set "${name}" needs a Set of words or a function returning one`,
|
|
1485
|
+
{ stopWords: name }
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1488
|
+
stopWordSets.set(name, stopWords);
|
|
1489
|
+
}
|
|
1490
|
+
function hasTokenizer(name) {
|
|
1491
|
+
return tokenizers.has(name);
|
|
1492
|
+
}
|
|
1493
|
+
function hasStopWords(name) {
|
|
1494
|
+
return stopWordSets.has(name);
|
|
1495
|
+
}
|
|
1496
|
+
function getTokenizer(name) {
|
|
1497
|
+
const tokenizer = tokenizers.get(name);
|
|
1498
|
+
if (!tokenizer) {
|
|
1499
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `Tokenizer "${name}" is not registered on this engine`, {
|
|
1500
|
+
tokenizer: name,
|
|
1501
|
+
available: [...tokenizers.keys()]
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
return tokenizer;
|
|
1505
|
+
}
|
|
1506
|
+
function getStopWords(name) {
|
|
1507
|
+
const stopWords = stopWordSets.get(name);
|
|
1508
|
+
if (!stopWords) {
|
|
1509
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `Stop word set "${name}" is not registered on this engine`, {
|
|
1510
|
+
stopWords: name,
|
|
1511
|
+
available: [...stopWordSets.keys()]
|
|
1512
|
+
});
|
|
1513
|
+
}
|
|
1514
|
+
return stopWords;
|
|
1515
|
+
}
|
|
1516
|
+
function resolveIndexAnalysis(config) {
|
|
1517
|
+
return {
|
|
1518
|
+
stopWords: typeof config.stopWords === "string" ? getStopWords(config.stopWords) : config.stopWords,
|
|
1519
|
+
customTokenizer: typeof config.tokenizer === "string" ? getTokenizer(config.tokenizer) : config.tokenizer
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
function metadataToWire(meta) {
|
|
1523
|
+
const wire = {
|
|
1524
|
+
index_name: meta.indexName,
|
|
1525
|
+
schema: meta.schema,
|
|
1526
|
+
language: meta.language,
|
|
1527
|
+
partition_count: meta.partitionCount,
|
|
1528
|
+
bm25_params: meta.bm25Params,
|
|
1529
|
+
created_at: meta.createdAt,
|
|
1530
|
+
engine_version: meta.engineVersion
|
|
1531
|
+
};
|
|
1532
|
+
if (meta.vectorFields) {
|
|
1533
|
+
wire.vector_fields = meta.vectorFields;
|
|
1534
|
+
}
|
|
1535
|
+
if (meta.embedding) {
|
|
1536
|
+
wire.embedding = meta.embedding.adapter !== void 0 ? { adapter: meta.embedding.adapter, fields: meta.embedding.fields } : { fields: meta.embedding.fields };
|
|
1537
|
+
}
|
|
1538
|
+
if (meta.surfaceForms === true) {
|
|
1539
|
+
wire.surface_forms_enabled = true;
|
|
1540
|
+
}
|
|
1541
|
+
if (meta.analysisRevision !== void 0) {
|
|
1542
|
+
wire.analysis_revision = meta.analysisRevision;
|
|
1543
|
+
}
|
|
1544
|
+
if (meta.tokenizer !== void 0) {
|
|
1545
|
+
wire.tokenizer = meta.tokenizer;
|
|
1546
|
+
}
|
|
1547
|
+
if (meta.stopWords !== void 0) {
|
|
1548
|
+
wire.stop_words = meta.stopWords;
|
|
1549
|
+
}
|
|
1550
|
+
if (meta.stopWordList !== void 0) {
|
|
1551
|
+
wire.stop_word_list = meta.stopWordList;
|
|
1552
|
+
}
|
|
1553
|
+
if (meta.partitionLimits !== void 0) {
|
|
1554
|
+
wire.partition_limits = {
|
|
1555
|
+
...meta.partitionLimits.maxDocsPerPartition !== void 0 ? { max_docs_per_partition: meta.partitionLimits.maxDocsPerPartition } : {},
|
|
1556
|
+
...meta.partitionLimits.maxPartitions !== void 0 ? { max_partitions: meta.partitionLimits.maxPartitions } : {},
|
|
1557
|
+
...meta.partitionLimits.watermark !== void 0 ? { watermark: meta.partitionLimits.watermark } : {}
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
if (meta.defaultScoring !== void 0) {
|
|
1561
|
+
wire.default_scoring = meta.defaultScoring;
|
|
1562
|
+
}
|
|
1563
|
+
if (meta.trackPositions !== void 0) {
|
|
1564
|
+
wire.track_positions = meta.trackPositions;
|
|
1565
|
+
}
|
|
1566
|
+
if (meta.strict !== void 0) {
|
|
1567
|
+
wire.strict = meta.strict;
|
|
1568
|
+
}
|
|
1569
|
+
if (meta.required !== void 0) {
|
|
1570
|
+
wire.required = meta.required;
|
|
1571
|
+
}
|
|
1572
|
+
if (meta.vectorPromotion !== void 0) {
|
|
1573
|
+
const promotion = meta.vectorPromotion;
|
|
1574
|
+
wire.vector_promotion = {
|
|
1575
|
+
...promotion.threshold !== void 0 ? { threshold: promotion.threshold } : {},
|
|
1576
|
+
...promotion.filterThreshold !== void 0 ? { filter_threshold: promotion.filterThreshold } : {},
|
|
1577
|
+
...promotion.hnswConfig !== void 0 ? {
|
|
1578
|
+
hnsw_config: {
|
|
1579
|
+
...promotion.hnswConfig.m !== void 0 ? { m: promotion.hnswConfig.m } : {},
|
|
1580
|
+
...promotion.hnswConfig.efConstruction !== void 0 ? { ef_construction: promotion.hnswConfig.efConstruction } : {},
|
|
1581
|
+
...promotion.hnswConfig.metric !== void 0 ? { metric: promotion.hnswConfig.metric } : {}
|
|
1582
|
+
}
|
|
1583
|
+
} : {},
|
|
1584
|
+
...promotion.quantization !== void 0 ? { quantization: promotion.quantization } : {}
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
return wire;
|
|
1588
|
+
}
|
|
1589
|
+
function wireToMetadata(raw) {
|
|
1590
|
+
const meta = {
|
|
1591
|
+
indexName: raw.index_name,
|
|
1592
|
+
schema: raw.schema ?? {},
|
|
1593
|
+
language: raw.language ?? "english",
|
|
1594
|
+
partitionCount: raw.partition_count ?? 1,
|
|
1595
|
+
bm25Params: raw.bm25_params ?? { k1: 1.2, b: 0.75 },
|
|
1596
|
+
createdAt: raw.created_at ?? 0,
|
|
1597
|
+
engineVersion: raw.engine_version ?? "0.0.0"
|
|
1598
|
+
};
|
|
1599
|
+
if (raw.vector_fields) {
|
|
1600
|
+
meta.vectorFields = raw.vector_fields;
|
|
1601
|
+
}
|
|
1602
|
+
if (raw.embedding && typeof raw.embedding === "object" && typeof raw.embedding.fields === "object") {
|
|
1603
|
+
meta.embedding = typeof raw.embedding.adapter === "string" ? { adapter: raw.embedding.adapter, fields: raw.embedding.fields } : { fields: raw.embedding.fields };
|
|
1604
|
+
}
|
|
1605
|
+
if (raw.surface_forms_enabled === true) {
|
|
1606
|
+
meta.surfaceForms = true;
|
|
1607
|
+
}
|
|
1608
|
+
if (typeof raw.analysis_revision === "string") {
|
|
1609
|
+
meta.analysisRevision = raw.analysis_revision;
|
|
1610
|
+
}
|
|
1611
|
+
if (typeof raw.tokenizer === "string") {
|
|
1612
|
+
meta.tokenizer = raw.tokenizer;
|
|
1613
|
+
}
|
|
1614
|
+
if (typeof raw.stop_words === "string") {
|
|
1615
|
+
meta.stopWords = raw.stop_words;
|
|
1616
|
+
}
|
|
1617
|
+
if (Array.isArray(raw.stop_word_list) && raw.stop_word_list.every((word) => typeof word === "string")) {
|
|
1618
|
+
meta.stopWordList = raw.stop_word_list;
|
|
1619
|
+
}
|
|
1620
|
+
if (raw.partition_limits && typeof raw.partition_limits === "object") {
|
|
1621
|
+
const limits = {
|
|
1622
|
+
...isPositiveInteger2(raw.partition_limits.max_docs_per_partition) ? { maxDocsPerPartition: raw.partition_limits.max_docs_per_partition } : {},
|
|
1623
|
+
...isPositiveInteger2(raw.partition_limits.max_partitions) ? { maxPartitions: raw.partition_limits.max_partitions } : {},
|
|
1624
|
+
...isWatermarkFraction(raw.partition_limits.watermark) ? { watermark: raw.partition_limits.watermark } : {}
|
|
1625
|
+
};
|
|
1626
|
+
if (Object.keys(limits).length > 0) {
|
|
1627
|
+
meta.partitionLimits = limits;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
if (raw.default_scoring === "local" || raw.default_scoring === "dfs" || raw.default_scoring === "broadcast") {
|
|
1631
|
+
meta.defaultScoring = raw.default_scoring;
|
|
1632
|
+
}
|
|
1633
|
+
if (typeof raw.track_positions === "boolean") {
|
|
1634
|
+
meta.trackPositions = raw.track_positions;
|
|
1635
|
+
}
|
|
1636
|
+
if (typeof raw.strict === "boolean") {
|
|
1637
|
+
meta.strict = raw.strict;
|
|
1638
|
+
}
|
|
1639
|
+
if (Array.isArray(raw.required) && raw.required.every((field) => typeof field === "string")) {
|
|
1640
|
+
meta.required = raw.required;
|
|
1641
|
+
}
|
|
1642
|
+
if (raw.vector_promotion && typeof raw.vector_promotion === "object") {
|
|
1643
|
+
const promotion = raw.vector_promotion;
|
|
1644
|
+
const hnsw = promotion.hnsw_config && typeof promotion.hnsw_config === "object" ? promotion.hnsw_config : void 0;
|
|
1645
|
+
const metric = hnsw?.metric;
|
|
1646
|
+
const restored = {};
|
|
1647
|
+
const hnswConfig = {};
|
|
1648
|
+
if (isPositiveInteger2(hnsw?.m)) {
|
|
1649
|
+
hnswConfig.m = hnsw?.m;
|
|
1650
|
+
}
|
|
1651
|
+
if (isPositiveInteger2(hnsw?.ef_construction)) {
|
|
1652
|
+
hnswConfig.efConstruction = hnsw?.ef_construction;
|
|
1653
|
+
}
|
|
1654
|
+
if (metric === "cosine" || metric === "dotProduct" || metric === "euclidean") {
|
|
1655
|
+
hnswConfig.metric = metric;
|
|
1656
|
+
}
|
|
1657
|
+
if (isPositiveInteger2(promotion.threshold)) {
|
|
1658
|
+
restored.threshold = promotion.threshold;
|
|
1659
|
+
}
|
|
1660
|
+
if (isPositiveInteger2(promotion.filter_threshold)) {
|
|
1661
|
+
restored.filterThreshold = promotion.filter_threshold;
|
|
1662
|
+
}
|
|
1663
|
+
if (Object.keys(hnswConfig).length > 0) {
|
|
1664
|
+
restored.hnswConfig = hnswConfig;
|
|
1665
|
+
}
|
|
1666
|
+
if (promotion.quantization === "sq8" || promotion.quantization === "none") {
|
|
1667
|
+
restored.quantization = promotion.quantization;
|
|
1668
|
+
}
|
|
1669
|
+
if (Object.keys(restored).length > 0) {
|
|
1670
|
+
meta.vectorPromotion = restored;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
return meta;
|
|
1674
|
+
}
|
|
1675
|
+
function isPositiveInteger2(value) {
|
|
1676
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
1677
|
+
}
|
|
1678
|
+
function isWatermarkFraction(value) {
|
|
1679
|
+
return typeof value === "number" && value > 0 && value <= 1;
|
|
1680
|
+
}
|
|
1681
|
+
function serializeMetadata(meta) {
|
|
1682
|
+
const wire = metadataToWire(meta);
|
|
1683
|
+
return encode(wire);
|
|
1684
|
+
}
|
|
1685
|
+
function deserializeMetadata(data) {
|
|
1686
|
+
const raw = decode(data);
|
|
1687
|
+
return wireToMetadata(raw);
|
|
1688
|
+
}
|
|
1215
1689
|
function sanitizeSurfaceForms(raw) {
|
|
1216
1690
|
if (raw === void 0 || raw === null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
1217
1691
|
const result = /* @__PURE__ */ Object.create(null);
|
|
@@ -1306,68 +1780,18 @@ function wireToPartition(raw) {
|
|
|
1306
1780
|
geopoint
|
|
1307
1781
|
},
|
|
1308
1782
|
surfaceForms: sanitizeSurfaceForms(raw.surface_forms),
|
|
1309
|
-
vectorData,
|
|
1310
|
-
statistics: {
|
|
1311
|
-
totalDocuments: raw.statistics?.total_documents ?? 0,
|
|
1312
|
-
totalFieldLengths: raw.statistics?.total_field_lengths ?? {},
|
|
1313
|
-
averageFieldLengths: raw.statistics?.average_field_lengths ?? {},
|
|
1314
|
-
docFrequencies: raw.statistics?.doc_frequencies ?? {}
|
|
1315
|
-
}
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
function deserializePayloadV1(data) {
|
|
1319
|
-
const raw = decode(data);
|
|
1320
|
-
return wireToPartition(raw);
|
|
1321
|
-
}
|
|
1322
|
-
function metadataToWire(meta) {
|
|
1323
|
-
const wire = {
|
|
1324
|
-
index_name: meta.indexName,
|
|
1325
|
-
schema: meta.schema,
|
|
1326
|
-
language: meta.language,
|
|
1327
|
-
partition_count: meta.partitionCount,
|
|
1328
|
-
bm25_params: meta.bm25Params,
|
|
1329
|
-
created_at: meta.createdAt,
|
|
1330
|
-
engine_version: meta.engineVersion
|
|
1331
|
-
};
|
|
1332
|
-
if (meta.vectorFields) {
|
|
1333
|
-
wire.vector_fields = meta.vectorFields;
|
|
1334
|
-
}
|
|
1335
|
-
if (meta.embedding) {
|
|
1336
|
-
wire.embedding = meta.embedding.adapter !== void 0 ? { adapter: meta.embedding.adapter, fields: meta.embedding.fields } : { fields: meta.embedding.fields };
|
|
1337
|
-
}
|
|
1338
|
-
if (meta.surfaceForms === true) {
|
|
1339
|
-
wire.surface_forms_enabled = true;
|
|
1340
|
-
}
|
|
1341
|
-
return wire;
|
|
1342
|
-
}
|
|
1343
|
-
function wireToMetadata(raw) {
|
|
1344
|
-
const meta = {
|
|
1345
|
-
indexName: raw.index_name,
|
|
1346
|
-
schema: raw.schema ?? {},
|
|
1347
|
-
language: raw.language ?? "english",
|
|
1348
|
-
partitionCount: raw.partition_count ?? 1,
|
|
1349
|
-
bm25Params: raw.bm25_params ?? { k1: 1.2, b: 0.75 },
|
|
1350
|
-
createdAt: raw.created_at ?? 0,
|
|
1351
|
-
engineVersion: raw.engine_version ?? "0.0.0"
|
|
1783
|
+
vectorData,
|
|
1784
|
+
statistics: {
|
|
1785
|
+
totalDocuments: raw.statistics?.total_documents ?? 0,
|
|
1786
|
+
totalFieldLengths: raw.statistics?.total_field_lengths ?? {},
|
|
1787
|
+
averageFieldLengths: raw.statistics?.average_field_lengths ?? {},
|
|
1788
|
+
docFrequencies: raw.statistics?.doc_frequencies ?? {}
|
|
1789
|
+
}
|
|
1352
1790
|
};
|
|
1353
|
-
if (raw.vector_fields) {
|
|
1354
|
-
meta.vectorFields = raw.vector_fields;
|
|
1355
|
-
}
|
|
1356
|
-
if (raw.embedding && typeof raw.embedding === "object" && typeof raw.embedding.fields === "object") {
|
|
1357
|
-
meta.embedding = typeof raw.embedding.adapter === "string" ? { adapter: raw.embedding.adapter, fields: raw.embedding.fields } : { fields: raw.embedding.fields };
|
|
1358
|
-
}
|
|
1359
|
-
if (raw.surface_forms_enabled === true) {
|
|
1360
|
-
meta.surfaceForms = true;
|
|
1361
|
-
}
|
|
1362
|
-
return meta;
|
|
1363
|
-
}
|
|
1364
|
-
function serializeMetadata(meta) {
|
|
1365
|
-
const wire = metadataToWire(meta);
|
|
1366
|
-
return encode(wire);
|
|
1367
1791
|
}
|
|
1368
|
-
function
|
|
1792
|
+
function deserializePayloadV1(data) {
|
|
1369
1793
|
const raw = decode(data);
|
|
1370
|
-
return
|
|
1794
|
+
return wireToPartition(raw);
|
|
1371
1795
|
}
|
|
1372
1796
|
|
|
1373
1797
|
// src/serialization/payload-v2.ts
|
|
@@ -1571,10 +1995,77 @@ function createDocumentStore() {
|
|
|
1571
1995
|
};
|
|
1572
1996
|
}
|
|
1573
1997
|
|
|
1574
|
-
// src/core/
|
|
1998
|
+
// src/core/posting-list.ts
|
|
1575
1999
|
var INITIAL_CAPACITY = 8;
|
|
1576
2000
|
var MAX_TERM_FREQUENCY = 65535;
|
|
1577
2001
|
var COMPACTION_THRESHOLD = 0.3;
|
|
2002
|
+
function createPostingList() {
|
|
2003
|
+
return {
|
|
2004
|
+
length: 0,
|
|
2005
|
+
docIds: [],
|
|
2006
|
+
termFrequencies: new Uint16Array(INITIAL_CAPACITY),
|
|
2007
|
+
fieldNameIndices: new Uint8Array(INITIAL_CAPACITY),
|
|
2008
|
+
positions: null,
|
|
2009
|
+
docIdSet: /* @__PURE__ */ new Set(),
|
|
2010
|
+
deletedDocs: /* @__PURE__ */ new Set(),
|
|
2011
|
+
totalTermFrequency: 0
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
function growTypedArrays(list) {
|
|
2015
|
+
const newCap = list.termFrequencies.length * 2;
|
|
2016
|
+
const newTF = new Uint16Array(newCap);
|
|
2017
|
+
newTF.set(list.termFrequencies);
|
|
2018
|
+
list.termFrequencies = newTF;
|
|
2019
|
+
const newFNI = new Uint8Array(newCap);
|
|
2020
|
+
newFNI.set(list.fieldNameIndices);
|
|
2021
|
+
list.fieldNameIndices = newFNI;
|
|
2022
|
+
}
|
|
2023
|
+
function compactList(list) {
|
|
2024
|
+
if (list.deletedDocs.size === 0) return;
|
|
2025
|
+
let writeIdx = 0;
|
|
2026
|
+
for (let i = 0; i < list.length; i++) {
|
|
2027
|
+
if (!list.deletedDocs.has(list.docIds[i])) {
|
|
2028
|
+
if (writeIdx !== i) {
|
|
2029
|
+
list.docIds[writeIdx] = list.docIds[i];
|
|
2030
|
+
list.termFrequencies[writeIdx] = list.termFrequencies[i];
|
|
2031
|
+
list.fieldNameIndices[writeIdx] = list.fieldNameIndices[i];
|
|
2032
|
+
if (list.positions) {
|
|
2033
|
+
list.positions[writeIdx] = list.positions[i];
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
writeIdx++;
|
|
2037
|
+
} else {
|
|
2038
|
+
list.totalTermFrequency -= list.termFrequencies[i];
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
list.docIds.length = writeIdx;
|
|
2042
|
+
if (list.positions) list.positions.length = writeIdx;
|
|
2043
|
+
list.length = writeIdx;
|
|
2044
|
+
list.deletedDocs.clear();
|
|
2045
|
+
}
|
|
2046
|
+
function compactDocEntries(list, internalId) {
|
|
2047
|
+
let writeIdx = 0;
|
|
2048
|
+
for (let i = 0; i < list.length; i++) {
|
|
2049
|
+
if (list.docIds[i] !== internalId) {
|
|
2050
|
+
if (writeIdx !== i) {
|
|
2051
|
+
list.docIds[writeIdx] = list.docIds[i];
|
|
2052
|
+
list.termFrequencies[writeIdx] = list.termFrequencies[i];
|
|
2053
|
+
list.fieldNameIndices[writeIdx] = list.fieldNameIndices[i];
|
|
2054
|
+
if (list.positions) {
|
|
2055
|
+
list.positions[writeIdx] = list.positions[i];
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
writeIdx++;
|
|
2059
|
+
} else {
|
|
2060
|
+
list.totalTermFrequency -= list.termFrequencies[i];
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
list.docIds.length = writeIdx;
|
|
2064
|
+
if (list.positions) list.positions.length = writeIdx;
|
|
2065
|
+
list.length = writeIdx;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
// src/core/inverted-index.ts
|
|
1578
2069
|
function createInvertedIndex(fieldNameTable) {
|
|
1579
2070
|
const index = /* @__PURE__ */ new Map();
|
|
1580
2071
|
const charBuckets = /* @__PURE__ */ new Map();
|
|
@@ -1619,74 +2110,12 @@ function createInvertedIndex(fieldNameTable) {
|
|
|
1619
2110
|
function getOrCreateList(token) {
|
|
1620
2111
|
let list = index.get(token);
|
|
1621
2112
|
if (!list) {
|
|
1622
|
-
list =
|
|
1623
|
-
length: 0,
|
|
1624
|
-
docIds: [],
|
|
1625
|
-
termFrequencies: new Uint16Array(INITIAL_CAPACITY),
|
|
1626
|
-
fieldNameIndices: new Uint8Array(INITIAL_CAPACITY),
|
|
1627
|
-
positions: null,
|
|
1628
|
-
docIdSet: /* @__PURE__ */ new Set(),
|
|
1629
|
-
deletedDocs: /* @__PURE__ */ new Set(),
|
|
1630
|
-
totalTermFrequency: 0
|
|
1631
|
-
};
|
|
2113
|
+
list = createPostingList();
|
|
1632
2114
|
index.set(token, list);
|
|
1633
2115
|
trackToken(token);
|
|
1634
2116
|
}
|
|
1635
2117
|
return list;
|
|
1636
2118
|
}
|
|
1637
|
-
function growTypedArrays(list) {
|
|
1638
|
-
const newCap = list.termFrequencies.length * 2;
|
|
1639
|
-
const newTF = new Uint16Array(newCap);
|
|
1640
|
-
newTF.set(list.termFrequencies);
|
|
1641
|
-
list.termFrequencies = newTF;
|
|
1642
|
-
const newFNI = new Uint8Array(newCap);
|
|
1643
|
-
newFNI.set(list.fieldNameIndices);
|
|
1644
|
-
list.fieldNameIndices = newFNI;
|
|
1645
|
-
}
|
|
1646
|
-
function compactList(list) {
|
|
1647
|
-
if (list.deletedDocs.size === 0) return;
|
|
1648
|
-
let writeIdx = 0;
|
|
1649
|
-
for (let i = 0; i < list.length; i++) {
|
|
1650
|
-
if (!list.deletedDocs.has(list.docIds[i])) {
|
|
1651
|
-
if (writeIdx !== i) {
|
|
1652
|
-
list.docIds[writeIdx] = list.docIds[i];
|
|
1653
|
-
list.termFrequencies[writeIdx] = list.termFrequencies[i];
|
|
1654
|
-
list.fieldNameIndices[writeIdx] = list.fieldNameIndices[i];
|
|
1655
|
-
if (list.positions) {
|
|
1656
|
-
list.positions[writeIdx] = list.positions[i];
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
writeIdx++;
|
|
1660
|
-
} else {
|
|
1661
|
-
list.totalTermFrequency -= list.termFrequencies[i];
|
|
1662
|
-
}
|
|
1663
|
-
}
|
|
1664
|
-
list.docIds.length = writeIdx;
|
|
1665
|
-
if (list.positions) list.positions.length = writeIdx;
|
|
1666
|
-
list.length = writeIdx;
|
|
1667
|
-
list.deletedDocs.clear();
|
|
1668
|
-
}
|
|
1669
|
-
function compactDocEntries(list, internalId) {
|
|
1670
|
-
let writeIdx = 0;
|
|
1671
|
-
for (let i = 0; i < list.length; i++) {
|
|
1672
|
-
if (list.docIds[i] !== internalId) {
|
|
1673
|
-
if (writeIdx !== i) {
|
|
1674
|
-
list.docIds[writeIdx] = list.docIds[i];
|
|
1675
|
-
list.termFrequencies[writeIdx] = list.termFrequencies[i];
|
|
1676
|
-
list.fieldNameIndices[writeIdx] = list.fieldNameIndices[i];
|
|
1677
|
-
if (list.positions) {
|
|
1678
|
-
list.positions[writeIdx] = list.positions[i];
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
writeIdx++;
|
|
1682
|
-
} else {
|
|
1683
|
-
list.totalTermFrequency -= list.termFrequencies[i];
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
list.docIds.length = writeIdx;
|
|
1687
|
-
if (list.positions) list.positions.length = writeIdx;
|
|
1688
|
-
list.length = writeIdx;
|
|
1689
|
-
}
|
|
1690
2119
|
return {
|
|
1691
2120
|
insert(token, internalId, termFrequency, fieldNameIndex, positions) {
|
|
1692
2121
|
const list = getOrCreateList(token);
|
|
@@ -3489,6 +3918,64 @@ function applyPartitionFiltersBitset(state, filters, schema) {
|
|
|
3489
3918
|
return evaluateFilters(filters, context);
|
|
3490
3919
|
}
|
|
3491
3920
|
|
|
3921
|
+
// src/core/partition/rebuild.ts
|
|
3922
|
+
var EMPTY_STATS = {
|
|
3923
|
+
totalDocuments: 0,
|
|
3924
|
+
totalFieldLengths: {},
|
|
3925
|
+
averageFieldLengths: {},
|
|
3926
|
+
docFrequencies: {}
|
|
3927
|
+
};
|
|
3928
|
+
function textFieldsOf(flatSchema) {
|
|
3929
|
+
return Object.entries(flatSchema).filter(([, fieldType]) => fieldType === "string" || fieldType === "string[]");
|
|
3930
|
+
}
|
|
3931
|
+
function rebuildTextIndex(state, schema, language, options) {
|
|
3932
|
+
const textFields = textFieldsOf(getFlatSchema(state, schema));
|
|
3933
|
+
state.invertedIdx.clear();
|
|
3934
|
+
state.surfaceRegistry.clear();
|
|
3935
|
+
state.stats.deserialize(EMPTY_STATS);
|
|
3936
|
+
state.invertedIdx.beginBatch();
|
|
3937
|
+
try {
|
|
3938
|
+
for (const [docId, stored] of state.docStore.all()) {
|
|
3939
|
+
const internalId = state.docStore.getInternalId(docId);
|
|
3940
|
+
if (internalId === void 0) continue;
|
|
3941
|
+
const fields = stored.fields;
|
|
3942
|
+
const fieldLengths = {};
|
|
3943
|
+
const tokensByField = {};
|
|
3944
|
+
for (const [fieldPath, fieldType] of textFields) {
|
|
3945
|
+
const value = getNestedValue(fields, fieldPath);
|
|
3946
|
+
if (value === void 0 || value === null) continue;
|
|
3947
|
+
if (fieldType === "string") {
|
|
3948
|
+
indexStringField(
|
|
3949
|
+
state,
|
|
3950
|
+
internalId,
|
|
3951
|
+
fieldPath,
|
|
3952
|
+
value,
|
|
3953
|
+
language,
|
|
3954
|
+
options,
|
|
3955
|
+
fieldLengths,
|
|
3956
|
+
tokensByField
|
|
3957
|
+
);
|
|
3958
|
+
} else {
|
|
3959
|
+
indexStringArrayField(
|
|
3960
|
+
state,
|
|
3961
|
+
internalId,
|
|
3962
|
+
fieldPath,
|
|
3963
|
+
value,
|
|
3964
|
+
language,
|
|
3965
|
+
options,
|
|
3966
|
+
fieldLengths,
|
|
3967
|
+
tokensByField
|
|
3968
|
+
);
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
state.docStore.storeRef(docId, stored.fields, fieldLengths);
|
|
3972
|
+
state.stats.addDocument(fieldLengths, tokensByField);
|
|
3973
|
+
}
|
|
3974
|
+
} finally {
|
|
3975
|
+
state.invertedIdx.endBatch();
|
|
3976
|
+
}
|
|
3977
|
+
}
|
|
3978
|
+
|
|
3492
3979
|
// src/core/scorer.ts
|
|
3493
3980
|
var DEFAULT_K1 = 1.2;
|
|
3494
3981
|
var DEFAULT_B = 0.75;
|
|
@@ -3511,8 +3998,7 @@ function computeBM25WithGlobalStats(termFrequency, globalDocFrequency, globalTot
|
|
|
3511
3998
|
return computeBM25(termFrequency, globalDocFrequency, globalTotalDocs, fieldLength, globalAvgFieldLength, params);
|
|
3512
3999
|
}
|
|
3513
4000
|
|
|
3514
|
-
// src/core/partition/
|
|
3515
|
-
var DEFAULT_MAX_RESULTS = 1e3;
|
|
4001
|
+
// src/core/partition/scoring.ts
|
|
3516
4002
|
var EMPTY_COMPONENTS = Object.freeze({});
|
|
3517
4003
|
function accumulateTermScore(docScores, internalId, termScore, collect, fieldName, token, termFrequency, fieldLength, idf) {
|
|
3518
4004
|
const existing = docScores.get(internalId);
|
|
@@ -3541,6 +4027,61 @@ function accumulateTermScore(docScores, internalId, termScore, collect, fieldNam
|
|
|
3541
4027
|
});
|
|
3542
4028
|
}
|
|
3543
4029
|
}
|
|
4030
|
+
function topKFromMap(docScores, k, resolver) {
|
|
4031
|
+
if (k <= 0) return [];
|
|
4032
|
+
const heap = [];
|
|
4033
|
+
for (const [internalId, data] of docScores) {
|
|
4034
|
+
if (heap.length < k) {
|
|
4035
|
+
heap.push({ internalId, score: data.score });
|
|
4036
|
+
if (heap.length === k) buildMinHeap(heap);
|
|
4037
|
+
} else if (data.score > heap[0].score) {
|
|
4038
|
+
heap[0] = { internalId, score: data.score };
|
|
4039
|
+
siftDown(heap, 0);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
heap.sort((a, b) => b.score - a.score);
|
|
4043
|
+
const result = [];
|
|
4044
|
+
for (let i = 0; i < heap.length; i++) {
|
|
4045
|
+
const data = docScores.get(heap[i].internalId);
|
|
4046
|
+
if (!data) continue;
|
|
4047
|
+
const externalId = resolver.toExternal(heap[i].internalId);
|
|
4048
|
+
if (externalId === void 0) continue;
|
|
4049
|
+
result.push({
|
|
4050
|
+
docId: externalId,
|
|
4051
|
+
score: data.score,
|
|
4052
|
+
termFrequencies: data.termFrequencies,
|
|
4053
|
+
fieldLengths: data.fieldLengths,
|
|
4054
|
+
idf: data.idf
|
|
4055
|
+
});
|
|
4056
|
+
}
|
|
4057
|
+
return result;
|
|
4058
|
+
}
|
|
4059
|
+
function buildMinHeap(heap) {
|
|
4060
|
+
for (let i = (heap.length >> 1) - 1; i >= 0; i--) {
|
|
4061
|
+
siftDown(heap, i);
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
function siftDown(heap, idx) {
|
|
4065
|
+
const len = heap.length;
|
|
4066
|
+
while (true) {
|
|
4067
|
+
let smallest = idx;
|
|
4068
|
+
const left = 2 * idx + 1;
|
|
4069
|
+
const right = 2 * idx + 2;
|
|
4070
|
+
if (left < len && heap[left].score < heap[smallest].score) smallest = left;
|
|
4071
|
+
if (right < len && heap[right].score < heap[smallest].score) smallest = right;
|
|
4072
|
+
if (smallest === idx) break;
|
|
4073
|
+
const tmp = heap[idx];
|
|
4074
|
+
heap[idx] = heap[smallest];
|
|
4075
|
+
heap[smallest] = tmp;
|
|
4076
|
+
idx = smallest;
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
|
|
4080
|
+
// src/core/partition/search.ts
|
|
4081
|
+
var DEFAULT_MAX_RESULTS = 1e3;
|
|
4082
|
+
function globalDocFreqFor(docFreqs, term, fallback) {
|
|
4083
|
+
return Object.hasOwn(docFreqs, term) ? docFreqs[term] : fallback;
|
|
4084
|
+
}
|
|
3544
4085
|
function searchFulltext(state, params) {
|
|
3545
4086
|
const {
|
|
3546
4087
|
queryTokens,
|
|
@@ -3587,7 +4128,7 @@ function searchFulltext(state, params) {
|
|
|
3587
4128
|
seen.add(term);
|
|
3588
4129
|
const postingList = state.invertedIdx.lookup(term);
|
|
3589
4130
|
if (!postingList) continue;
|
|
3590
|
-
const docFreq = globalStats ? globalDocFreqs
|
|
4131
|
+
const docFreq = globalStats ? globalDocFreqFor(globalDocFreqs, term, postingList.docIdSet.size) : postingList.docIdSet.size;
|
|
3591
4132
|
found.push({ token: term, postingList, docFreq });
|
|
3592
4133
|
}
|
|
3593
4134
|
if (found.length === 0) return [];
|
|
@@ -3702,7 +4243,7 @@ function searchFulltext(state, params) {
|
|
|
3702
4243
|
let totalPostings = 0;
|
|
3703
4244
|
const matches = [];
|
|
3704
4245
|
for (const m of rawMatches) {
|
|
3705
|
-
const docFreq = globalStats ? globalDocFreqs
|
|
4246
|
+
const docFreq = globalStats ? globalDocFreqFor(globalDocFreqs, m.token, m.postingList.docIdSet.size) : m.postingList.docIdSet.size;
|
|
3706
4247
|
const idf = computeIDF(docFreq, totalDocs);
|
|
3707
4248
|
totalPostings += m.postingList.length;
|
|
3708
4249
|
matches.push({ token: m.token, docFreq, idf, postingList: m.postingList });
|
|
@@ -3773,7 +4314,7 @@ function searchFulltext(state, params) {
|
|
|
3773
4314
|
return postingList ? [{ token: qt.token, postingList }] : [];
|
|
3774
4315
|
})() : state.invertedIdx.fuzzyLookup(qt.token, tolerance, prefixLength);
|
|
3775
4316
|
for (const match of matchingPostings) {
|
|
3776
|
-
const docFreq = globalStats ? globalDocFreqs
|
|
4317
|
+
const docFreq = globalStats ? globalDocFreqFor(globalDocFreqs, match.token, match.postingList.docIdSet.size) : match.postingList.docIdSet.size;
|
|
3777
4318
|
const idf = computeIDF(docFreq, totalDocs);
|
|
3778
4319
|
const list = match.postingList;
|
|
3779
4320
|
const hasDeleted = list.deletedDocs.size > 0;
|
|
@@ -3816,55 +4357,6 @@ function searchFulltext(state, params) {
|
|
|
3816
4357
|
const scored = topKFromMap(docScores, Math.min(k, totalMatched), resolver);
|
|
3817
4358
|
return { scored, totalMatched };
|
|
3818
4359
|
}
|
|
3819
|
-
function topKFromMap(docScores, k, resolver) {
|
|
3820
|
-
if (k <= 0) return [];
|
|
3821
|
-
const heap = [];
|
|
3822
|
-
for (const [internalId, data] of docScores) {
|
|
3823
|
-
if (heap.length < k) {
|
|
3824
|
-
heap.push({ internalId, score: data.score });
|
|
3825
|
-
if (heap.length === k) buildMinHeap(heap);
|
|
3826
|
-
} else if (data.score > heap[0].score) {
|
|
3827
|
-
heap[0] = { internalId, score: data.score };
|
|
3828
|
-
siftDown(heap, 0);
|
|
3829
|
-
}
|
|
3830
|
-
}
|
|
3831
|
-
heap.sort((a, b) => b.score - a.score);
|
|
3832
|
-
const result = [];
|
|
3833
|
-
for (let i = 0; i < heap.length; i++) {
|
|
3834
|
-
const data = docScores.get(heap[i].internalId);
|
|
3835
|
-
if (!data) continue;
|
|
3836
|
-
const externalId = resolver.toExternal(heap[i].internalId);
|
|
3837
|
-
if (externalId === void 0) continue;
|
|
3838
|
-
result.push({
|
|
3839
|
-
docId: externalId,
|
|
3840
|
-
score: data.score,
|
|
3841
|
-
termFrequencies: data.termFrequencies,
|
|
3842
|
-
fieldLengths: data.fieldLengths,
|
|
3843
|
-
idf: data.idf
|
|
3844
|
-
});
|
|
3845
|
-
}
|
|
3846
|
-
return result;
|
|
3847
|
-
}
|
|
3848
|
-
function buildMinHeap(heap) {
|
|
3849
|
-
for (let i = (heap.length >> 1) - 1; i >= 0; i--) {
|
|
3850
|
-
siftDown(heap, i);
|
|
3851
|
-
}
|
|
3852
|
-
}
|
|
3853
|
-
function siftDown(heap, idx) {
|
|
3854
|
-
const len = heap.length;
|
|
3855
|
-
while (true) {
|
|
3856
|
-
let smallest = idx;
|
|
3857
|
-
const left = 2 * idx + 1;
|
|
3858
|
-
const right = 2 * idx + 2;
|
|
3859
|
-
if (left < len && heap[left].score < heap[smallest].score) smallest = left;
|
|
3860
|
-
if (right < len && heap[right].score < heap[smallest].score) smallest = right;
|
|
3861
|
-
if (smallest === idx) break;
|
|
3862
|
-
const tmp = heap[idx];
|
|
3863
|
-
heap[idx] = heap[smallest];
|
|
3864
|
-
heap[smallest] = tmp;
|
|
3865
|
-
idx = smallest;
|
|
3866
|
-
}
|
|
3867
|
-
}
|
|
3868
4360
|
|
|
3869
4361
|
// src/core/partition/serialization.ts
|
|
3870
4362
|
function serializePartition(state, partitionId, indexName, totalPartitions, language, schema) {
|
|
@@ -4337,6 +4829,9 @@ function createPartitionIndex(partitionId, trackPositions = true) {
|
|
|
4337
4829
|
state.docStore.store(docId, document, stored.fieldLengths);
|
|
4338
4830
|
}
|
|
4339
4831
|
},
|
|
4832
|
+
rebuildTextIndex(schema, language, options) {
|
|
4833
|
+
rebuildTextIndex(state, schema, language, options);
|
|
4834
|
+
},
|
|
4340
4835
|
get(docId) {
|
|
4341
4836
|
const stored = state.docStore.get(docId);
|
|
4342
4837
|
if (!stored) return void 0;
|
|
@@ -4436,6 +4931,7 @@ function setNestedValue(obj, path, value) {
|
|
|
4436
4931
|
}
|
|
4437
4932
|
function createPartitionManager(indexName, config, language, router, initialPartitionCount, vectorIndexes) {
|
|
4438
4933
|
const count = initialPartitionCount ?? 1;
|
|
4934
|
+
const analysis = resolveIndexAnalysis(config);
|
|
4439
4935
|
const trackPositions = config.trackPositions ?? true;
|
|
4440
4936
|
const vecIndexes = vectorIndexes ?? /* @__PURE__ */ new Map();
|
|
4441
4937
|
let partitions = [];
|
|
@@ -4454,14 +4950,14 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
4454
4950
|
}
|
|
4455
4951
|
function resolveInsertOptions(options) {
|
|
4456
4952
|
const applyStrict = config.strict === true;
|
|
4457
|
-
const applyAnalyzer =
|
|
4953
|
+
const applyAnalyzer = analysis.stopWords !== void 0 || analysis.customTokenizer !== void 0;
|
|
4458
4954
|
const applySurfaces = config.surfaceForms === true;
|
|
4459
4955
|
if (!applyStrict && !applyAnalyzer && !applySurfaces) return options;
|
|
4460
4956
|
const resolved = { ...options };
|
|
4461
4957
|
if (applyStrict) resolved.strict = true;
|
|
4462
4958
|
if (applyAnalyzer) {
|
|
4463
|
-
resolved.stopWordOverride = options?.stopWordOverride ??
|
|
4464
|
-
resolved.customTokenizer = options?.customTokenizer ??
|
|
4959
|
+
resolved.stopWordOverride = options?.stopWordOverride ?? analysis.stopWords;
|
|
4960
|
+
resolved.customTokenizer = options?.customTokenizer ?? analysis.customTokenizer;
|
|
4465
4961
|
}
|
|
4466
4962
|
if (applySurfaces) resolved.collectSurfaces = true;
|
|
4467
4963
|
return resolved;
|
|
@@ -4500,6 +4996,9 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
4500
4996
|
get config() {
|
|
4501
4997
|
return config;
|
|
4502
4998
|
},
|
|
4999
|
+
get analysis() {
|
|
5000
|
+
return analysis;
|
|
5001
|
+
},
|
|
4503
5002
|
getPartition(partitionId) {
|
|
4504
5003
|
validatePartitionId(partitionId);
|
|
4505
5004
|
return partitions[partitionId];
|
|
@@ -4532,24 +5031,44 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
4532
5031
|
partitions.splice(partitionId, 1);
|
|
4533
5032
|
rebuildDocPartitionMap();
|
|
4534
5033
|
},
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
partitionCount: partitions.length
|
|
4549
|
-
}
|
|
4550
|
-
);
|
|
5034
|
+
trimPartitions(newCount) {
|
|
5035
|
+
if (newCount < 1) {
|
|
5036
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, `Cannot trim index "${indexName}" below one partition`, {
|
|
5037
|
+
indexName,
|
|
5038
|
+
requestedCount: newCount
|
|
5039
|
+
});
|
|
5040
|
+
}
|
|
5041
|
+
if (newCount >= partitions.length) {
|
|
5042
|
+
return;
|
|
5043
|
+
}
|
|
5044
|
+
for (const [docId, pid] of docPartitionMap) {
|
|
5045
|
+
if (pid >= newCount) {
|
|
5046
|
+
docPartitionMap.delete(docId);
|
|
4551
5047
|
}
|
|
4552
5048
|
}
|
|
5049
|
+
partitions.length = newCount;
|
|
5050
|
+
},
|
|
5051
|
+
assertCapacity(pendingWrites = 0, partitionCountCap) {
|
|
5052
|
+
const currentMaxDocs = config.partitions?.maxDocsPerPartition;
|
|
5053
|
+
if (currentMaxDocs === void 0) return;
|
|
5054
|
+
const effectivePartitionCount = partitionCountCap === void 0 ? partitions.length : Math.min(partitions.length, partitionCountCap);
|
|
5055
|
+
const totalCapacity = currentMaxDocs * effectivePartitionCount;
|
|
5056
|
+
if (docPartitionMap.size + pendingWrites >= totalCapacity) {
|
|
5057
|
+
throw new NarsilError(
|
|
5058
|
+
ErrorCodes.PARTITION_CAPACITY_EXCEEDED,
|
|
5059
|
+
`Index "${indexName}" has reached its capacity of ${totalCapacity} documents (${currentMaxDocs} per partition \xD7 ${effectivePartitionCount} partitions)`,
|
|
5060
|
+
{
|
|
5061
|
+
indexName,
|
|
5062
|
+
currentCount: docPartitionMap.size + pendingWrites,
|
|
5063
|
+
totalCapacity,
|
|
5064
|
+
maxDocsPerPartition: currentMaxDocs,
|
|
5065
|
+
partitionCount: effectivePartitionCount
|
|
5066
|
+
}
|
|
5067
|
+
);
|
|
5068
|
+
}
|
|
5069
|
+
},
|
|
5070
|
+
insert(docId, document, options) {
|
|
5071
|
+
manager.assertCapacity();
|
|
4553
5072
|
const pid = router.route(docId, partitions.length);
|
|
4554
5073
|
const insertOpts = resolveInsertOptions(options);
|
|
4555
5074
|
partitions[pid].insert(docId, document, config.schema, language, insertOpts);
|
|
@@ -4563,6 +5082,10 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
4563
5082
|
partitions[pid].remove(docId, config.schema, language, resolveInsertOptions());
|
|
4564
5083
|
docPartitionMap.delete(docId);
|
|
4565
5084
|
},
|
|
5085
|
+
rebuildTextIndex(partitionId) {
|
|
5086
|
+
validatePartitionId(partitionId);
|
|
5087
|
+
partitions[partitionId].rebuildTextIndex(config.schema, language, resolveInsertOptions());
|
|
5088
|
+
},
|
|
4566
5089
|
beginBatchRemove() {
|
|
4567
5090
|
for (let i = 0; i < partitions.length; i++) {
|
|
4568
5091
|
partitions[i].beginBatch();
|
|
@@ -4620,8 +5143,8 @@ function createPartitionManager(indexName, config, language, router, initialPart
|
|
|
4620
5143
|
},
|
|
4621
5144
|
getAggregateStats() {
|
|
4622
5145
|
let totalDocuments = 0;
|
|
4623
|
-
const docFrequencies =
|
|
4624
|
-
const totalFieldLengths =
|
|
5146
|
+
const docFrequencies = /* @__PURE__ */ Object.create(null);
|
|
5147
|
+
const totalFieldLengths = /* @__PURE__ */ Object.create(null);
|
|
4625
5148
|
for (let i = 0; i < partitions.length; i++) {
|
|
4626
5149
|
const stats = partitions[i].stats;
|
|
4627
5150
|
totalDocuments += stats.totalDocuments;
|
|
@@ -4706,8 +5229,33 @@ function createPartitionRouter() {
|
|
|
4706
5229
|
return { route, routeBatch };
|
|
4707
5230
|
}
|
|
4708
5231
|
|
|
4709
|
-
// src/vector/scalar-quantization.ts
|
|
5232
|
+
// src/vector/scalar-quantization-calibration.ts
|
|
4710
5233
|
var PADDING_FACTOR = 0.01;
|
|
5234
|
+
function computeCalibrationBounds(vectors, dimensions) {
|
|
5235
|
+
let globalMin = Number.POSITIVE_INFINITY;
|
|
5236
|
+
let globalMax = Number.NEGATIVE_INFINITY;
|
|
5237
|
+
let count = 0;
|
|
5238
|
+
for (const vec of vectors) {
|
|
5239
|
+
for (let d = 0; d < dimensions; d++) {
|
|
5240
|
+
const val = vec[d];
|
|
5241
|
+
if (val < globalMin) globalMin = val;
|
|
5242
|
+
if (val > globalMax) globalMax = val;
|
|
5243
|
+
}
|
|
5244
|
+
count++;
|
|
5245
|
+
}
|
|
5246
|
+
if (count === 0) return null;
|
|
5247
|
+
const range = globalMax - globalMin;
|
|
5248
|
+
const pad = range * PADDING_FACTOR;
|
|
5249
|
+
globalMin -= pad;
|
|
5250
|
+
globalMax += pad;
|
|
5251
|
+
if (globalMin === globalMax) {
|
|
5252
|
+
globalMin -= 1e-3;
|
|
5253
|
+
globalMax += 1e-3;
|
|
5254
|
+
}
|
|
5255
|
+
return { alpha: (globalMax - globalMin) / 255, offset: globalMin };
|
|
5256
|
+
}
|
|
5257
|
+
|
|
5258
|
+
// src/vector/scalar-quantization.ts
|
|
4711
5259
|
var INITIAL_CAPACITY2 = 16;
|
|
4712
5260
|
var PAGE_BYTES = 65536;
|
|
4713
5261
|
function createScalarQuantizer(dimensions, ordinalSource) {
|
|
@@ -4811,28 +5359,10 @@ function createScalarQuantizer(dimensions, ordinalSource) {
|
|
|
4811
5359
|
docToOrd.set(docId, ord);
|
|
4812
5360
|
}
|
|
4813
5361
|
function calibrateFromVectors(vectors) {
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
for (let d = 0; d < dimensions; d++) {
|
|
4819
|
-
const val = vec[d];
|
|
4820
|
-
if (val < globalMin) globalMin = val;
|
|
4821
|
-
if (val > globalMax) globalMax = val;
|
|
4822
|
-
}
|
|
4823
|
-
count++;
|
|
4824
|
-
}
|
|
4825
|
-
if (count === 0) return;
|
|
4826
|
-
const range = globalMax - globalMin;
|
|
4827
|
-
const pad = range * PADDING_FACTOR;
|
|
4828
|
-
globalMin -= pad;
|
|
4829
|
-
globalMax += pad;
|
|
4830
|
-
if (globalMin === globalMax) {
|
|
4831
|
-
globalMin -= 1e-3;
|
|
4832
|
-
globalMax += 1e-3;
|
|
4833
|
-
}
|
|
4834
|
-
alpha = (globalMax - globalMin) / 255;
|
|
4835
|
-
offset = globalMin;
|
|
5362
|
+
const bounds = computeCalibrationBounds(vectors, dimensions);
|
|
5363
|
+
if (bounds === null) return;
|
|
5364
|
+
alpha = bounds.alpha;
|
|
5365
|
+
offset = bounds.offset;
|
|
4836
5366
|
updateDerivedConstants();
|
|
4837
5367
|
calibrated = true;
|
|
4838
5368
|
}
|
|
@@ -5044,20 +5574,6 @@ function createScalarQuantizer(dimensions, ordinalSource) {
|
|
|
5044
5574
|
}
|
|
5045
5575
|
};
|
|
5046
5576
|
}
|
|
5047
|
-
function deserializeScalarQuantizer(data, dimensions, ordinalSource) {
|
|
5048
|
-
const quantizer = createScalarQuantizer(dimensions, ordinalSource);
|
|
5049
|
-
if (data.alpha === 0 && data.offset === 0 && Object.keys(data.quantizedVectors).length === 0) {
|
|
5050
|
-
return quantizer;
|
|
5051
|
-
}
|
|
5052
|
-
quantizer.restoreCalibration(data.alpha, data.offset);
|
|
5053
|
-
for (const [docId, values] of Object.entries(data.quantizedVectors)) {
|
|
5054
|
-
const quantized = new Uint8Array(values);
|
|
5055
|
-
const sum = data.vectorSums[docId] ?? 0;
|
|
5056
|
-
const sumSq = data.vectorSumSqs[docId] ?? 0;
|
|
5057
|
-
quantizer.restoreEntry(docId, quantized, sum, sumSq);
|
|
5058
|
-
}
|
|
5059
|
-
return quantizer;
|
|
5060
|
-
}
|
|
5061
5577
|
|
|
5062
5578
|
// src/workers/node-worker.ts
|
|
5063
5579
|
async function spawnNodeWorker(entryPoint) {
|
|
@@ -5499,6 +6015,22 @@ function estimateMemoryBytes(state) {
|
|
|
5499
6015
|
return Math.round(bytes);
|
|
5500
6016
|
}
|
|
5501
6017
|
|
|
6018
|
+
// src/vector/scalar-quantization-restore.ts
|
|
6019
|
+
function deserializeScalarQuantizer(data, dimensions, ordinalSource) {
|
|
6020
|
+
const quantizer = createScalarQuantizer(dimensions, ordinalSource);
|
|
6021
|
+
if (data.alpha === 0 && data.offset === 0 && Object.keys(data.quantizedVectors).length === 0) {
|
|
6022
|
+
return quantizer;
|
|
6023
|
+
}
|
|
6024
|
+
quantizer.restoreCalibration(data.alpha, data.offset);
|
|
6025
|
+
for (const [docId, values] of Object.entries(data.quantizedVectors)) {
|
|
6026
|
+
const quantized = new Uint8Array(values);
|
|
6027
|
+
const sum = data.vectorSums[docId] ?? 0;
|
|
6028
|
+
const sumSq = data.vectorSumSqs[docId] ?? 0;
|
|
6029
|
+
quantizer.restoreEntry(docId, quantized, sum, sumSq);
|
|
6030
|
+
}
|
|
6031
|
+
return quantizer;
|
|
6032
|
+
}
|
|
6033
|
+
|
|
5502
6034
|
// src/vector/vector-index/persistence.ts
|
|
5503
6035
|
function serialize(state) {
|
|
5504
6036
|
const vectors = [];
|
|
@@ -5846,7 +6378,17 @@ function createDirectExecutor() {
|
|
|
5846
6378
|
vectorIndexes.set(fieldPath, createVectorIndex(fieldPath, dim, config.vectorPromotion));
|
|
5847
6379
|
}
|
|
5848
6380
|
const manager = createPartitionManager(indexName, config, language, router, partitionCount, vectorIndexes);
|
|
5849
|
-
indexes.set(indexName, {
|
|
6381
|
+
indexes.set(indexName, {
|
|
6382
|
+
manager,
|
|
6383
|
+
config,
|
|
6384
|
+
language,
|
|
6385
|
+
searchOptions: {
|
|
6386
|
+
bm25Params: config.bm25,
|
|
6387
|
+
stopWords: manager.analysis.stopWords,
|
|
6388
|
+
customTokenizer: manager.analysis.customTokenizer
|
|
6389
|
+
},
|
|
6390
|
+
vectorIndexes
|
|
6391
|
+
});
|
|
5850
6392
|
}
|
|
5851
6393
|
function dropIndex(indexName) {
|
|
5852
6394
|
const entry = requireIndex(indexName);
|
|
@@ -5863,6 +6405,15 @@ function createDirectExecutor() {
|
|
|
5863
6405
|
}
|
|
5864
6406
|
async function execute(action) {
|
|
5865
6407
|
switch (action.type) {
|
|
6408
|
+
case "bootstrap": {
|
|
6409
|
+
if (typeof action.moduleUrl !== "string" || action.moduleUrl.trim().length === 0) {
|
|
6410
|
+
throw new NarsilError(ErrorCodes.CONFIG_INVALID, "A bootstrap module needs a non-empty module URL", {
|
|
6411
|
+
moduleUrl: action.moduleUrl
|
|
6412
|
+
});
|
|
6413
|
+
}
|
|
6414
|
+
await import(action.moduleUrl);
|
|
6415
|
+
return void 0;
|
|
6416
|
+
}
|
|
5866
6417
|
case "createIndex": {
|
|
5867
6418
|
const language = getLanguage(action.config.language ?? "english");
|
|
5868
6419
|
createIndex(action.indexName, action.config, language);
|
|
@@ -5889,17 +6440,30 @@ function createDirectExecutor() {
|
|
|
5889
6440
|
}
|
|
5890
6441
|
case "query": {
|
|
5891
6442
|
const entry = requireIndex(action.indexName);
|
|
5892
|
-
const result = await fanOutQuery(
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
6443
|
+
const result = await fanOutQuery(
|
|
6444
|
+
entry.manager,
|
|
6445
|
+
action.params,
|
|
6446
|
+
entry.language,
|
|
6447
|
+
entry.config.schema,
|
|
6448
|
+
{
|
|
6449
|
+
scoringMode: action.params.scoring ?? entry.config.defaultScoring ?? "local",
|
|
6450
|
+
partitionIds: action.partitionIds,
|
|
6451
|
+
...action.globalStats !== void 0 ? { globalStats: sanitizeGlobalStats(action.globalStats) } : {}
|
|
6452
|
+
},
|
|
6453
|
+
entry.searchOptions
|
|
6454
|
+
);
|
|
5896
6455
|
return result;
|
|
5897
6456
|
}
|
|
5898
6457
|
case "preflight": {
|
|
5899
6458
|
const entry = requireIndex(action.indexName);
|
|
5900
|
-
const result = await fanOutQuery(
|
|
5901
|
-
|
|
5902
|
-
|
|
6459
|
+
const result = await fanOutQuery(
|
|
6460
|
+
entry.manager,
|
|
6461
|
+
action.params,
|
|
6462
|
+
entry.language,
|
|
6463
|
+
entry.config.schema,
|
|
6464
|
+
{ scoringMode: entry.config.defaultScoring ?? "local" },
|
|
6465
|
+
entry.searchOptions
|
|
6466
|
+
);
|
|
5903
6467
|
return { count: result.totalMatched };
|
|
5904
6468
|
}
|
|
5905
6469
|
case "get": {
|
|
@@ -5945,6 +6509,9 @@ function createDirectExecutor() {
|
|
|
5945
6509
|
}
|
|
5946
6510
|
case "deserialize": {
|
|
5947
6511
|
const entry = requireIndex(action.indexName);
|
|
6512
|
+
while (entry.manager.partitionCount <= action.partitionId) {
|
|
6513
|
+
entry.manager.addPartition();
|
|
6514
|
+
}
|
|
5948
6515
|
entry.manager.deserializePartition(action.partitionId, action.data);
|
|
5949
6516
|
return void 0;
|
|
5950
6517
|
}
|
|
@@ -5976,4 +6543,4 @@ function createDirectExecutor() {
|
|
|
5976
6543
|
};
|
|
5977
6544
|
}
|
|
5978
6545
|
|
|
5979
|
-
export { MAX_NESTING_DEPTH, clearNormalizationCache, configureNormalizationCache, createDirectExecutor, createPartitionIndex, createPartitionManager, createPartitionRouter, createVectorIndex, deserializeMetadata, deserializePayloadV1, deserializePayloadV2, detectRuntime, extractVectorFieldsFromSchema, fanOutQuery, flattenSchema, fnv1a, getLanguage, getNestedValue, getNormalizationCacheSize, isNodeMainThread, kWayMerge, mergePartitionStats, registerLanguage, resetNormalizationCache, serializeMetadata, spawnNodeWorker, tokenize, validateRequiredFields, validateSchema, validateVectorPromotion };
|
|
6546
|
+
export { MAX_NESTING_DEPTH, clearNormalizationCache, configureNormalizationCache, createDirectExecutor, createPartitionIndex, createPartitionManager, createPartitionRouter, createVectorIndex, deserializeMetadata, deserializePayloadV1, deserializePayloadV2, detectRuntime, extractVectorFieldsFromSchema, fanOutQuery, flattenSchema, fnv1a, getLanguage, getNestedValue, getNormalizationCacheSize, getStopWords, getTokenizer, hasStopWords, hasTokenizer, isNodeMainThread, kWayMerge, mergePartitionStats, pruneStatsToQueryTerms, registerLanguage, registerStopWords, registerTokenizer, resetNormalizationCache, resolveIndexAnalysis, serializeMetadata, spawnNodeWorker, tokenize, validateRequiredFields, validateSchema, validateVectorPromotion };
|