@cachly-dev/mcp-server 0.10.129 → 0.10.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.js +1 -7
- package/dist/packages/telegram-notify/client.js +2 -75
- package/dist/src/ambient-cli.js +7 -253
- package/dist/src/ambient-deps.js +1 -55
- package/dist/src/ambient-hooks.js +5 -278
- package/dist/src/ambient-ledger.js +6 -95
- package/dist/src/ambient-memory.js +1 -67
- package/dist/src/ambient-recall.js +1 -221
- package/dist/src/aussetzer.js +1 -225
- package/dist/src/auth.js +9 -140
- package/dist/src/autor-abzeichen.js +1 -56
- package/dist/src/autor.js +1 -136
- package/dist/src/bauabdruck.js +1 -93
- package/dist/src/bedeutung.js +2 -323
- package/dist/src/bench/cachly-bench.js +4 -249
- package/dist/src/bench/external-corpus.js +4 -135
- package/dist/src/bench/fixtures.js +1 -225
- package/dist/src/brain-export.js +16 -119
- package/dist/src/brain-watch-hook.js +8 -86
- package/dist/src/cachly-url.js +1 -21
- package/dist/src/ckg.js +1 -108
- package/dist/src/cls-hook.js +8 -94
- package/dist/src/confidence.js +1 -50
- package/dist/src/credentials.js +1 -85
- package/dist/src/deutsch.js +1 -223
- package/dist/src/doctor.js +2 -248
- package/dist/src/editor.js +1 -63
- package/dist/src/eingaenge-nachruesten.js +1 -290
- package/dist/src/eingaenge.js +2 -260
- package/dist/src/embeddings.js +13 -223
- package/dist/src/feldreparatur.js +3 -113
- package/dist/src/first-contact.js +4 -108
- package/dist/src/first-recall-proof.js +4 -41
- package/dist/src/funnel-milestones.js +2 -48
- package/dist/src/geliefert.js +1 -114
- package/dist/src/handlers/advanced.js +38 -537
- package/dist/src/handlers/brain.js +69 -4397
- package/dist/src/handlers/cache.js +59 -638
- package/dist/src/handlers/context.js +17 -182
- package/dist/src/handlers/fedbrain.js +40 -1436
- package/dist/src/handlers/instances.js +16 -201
- package/dist/src/handlers/roadmap.js +13 -175
- package/dist/src/handlers/share.js +19 -530
- package/dist/src/handlers/syndicate.js +38 -904
- package/dist/src/handlers/team.js +89 -1865
- package/dist/src/handlers/viz.js +3 -148
- package/dist/src/index.js +321 -4281
- package/dist/src/interferenz.js +1 -141
- package/dist/src/kostprobe.js +7 -125
- package/dist/src/lesson-preview.js +2 -133
- package/dist/src/namespace.js +1 -128
- package/dist/src/notifier.js +1 -6
- package/dist/src/rangfolge-stellschrauben.js +1 -0
- package/dist/src/rangfolge.js +1 -249
- package/dist/src/raumkorrektur.js +1 -197
- package/dist/src/recall-tiefe.js +1 -42
- package/dist/src/rerank.js +1 -154
- package/dist/src/resonanz.js +1 -140
- package/dist/src/search.js +1 -2104
- package/dist/src/seltenheitsbestand.js +1 -92
- package/dist/src/speicherlage.js +1 -84
- package/dist/src/spuren.js +1 -150
- package/dist/src/starter-corpus.js +1 -165
- package/dist/src/telemetry-types.js +0 -13
- package/dist/src/tools.js +10 -2465
- package/dist/src/toolspecs.js +1 -121
- package/dist/src/upgrade-nudge.js +1 -29
- package/dist/src/utils.js +1 -89
- package/dist/src/versuch.js +1 -264
- package/dist/src/vorspann.js +1 -146
- package/dist/src/wartung/vektoren-verdichten.js +1 -200
- package/dist/src/werkzeug-nutzung.js +1 -72
- package/dist/src/wertbeitrag.js +1 -203
- package/dist/src/wirkungsspur.js +1 -0
- package/glama.json +1 -1
- package/package.json +8 -7
- package/server.json +3 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
- package/dist/packages/telegram-notify/client.d.ts +0 -19
- package/dist/packages/telegram-notify/client.js.map +0 -1
- package/dist/src/ambient-cli.d.ts +0 -101
- package/dist/src/ambient-cli.js.map +0 -1
- package/dist/src/ambient-deps.d.ts +0 -26
- package/dist/src/ambient-deps.js.map +0 -1
- package/dist/src/ambient-hooks.d.ts +0 -137
- package/dist/src/ambient-hooks.js.map +0 -1
- package/dist/src/ambient-ledger.d.ts +0 -19
- package/dist/src/ambient-ledger.js.map +0 -1
- package/dist/src/ambient-memory.d.ts +0 -12
- package/dist/src/ambient-memory.js.map +0 -1
- package/dist/src/ambient-recall.d.ts +0 -127
- package/dist/src/ambient-recall.js.map +0 -1
- package/dist/src/aussetzer.d.ts +0 -156
- package/dist/src/aussetzer.js.map +0 -1
- package/dist/src/auth.d.ts +0 -43
- package/dist/src/auth.js.map +0 -1
- package/dist/src/autor-abzeichen.d.ts +0 -41
- package/dist/src/autor-abzeichen.js.map +0 -1
- package/dist/src/autor.d.ts +0 -101
- package/dist/src/autor.js.map +0 -1
- package/dist/src/bauabdruck-daten.generiert.json +0 -5
- package/dist/src/bauabdruck.d.ts +0 -38
- package/dist/src/bauabdruck.js.map +0 -1
- package/dist/src/bedeutung.d.ts +0 -168
- package/dist/src/bedeutung.js.map +0 -1
- package/dist/src/bench/cachly-bench.d.ts +0 -61
- package/dist/src/bench/cachly-bench.js.map +0 -1
- package/dist/src/bench/external-corpus.d.ts +0 -44
- package/dist/src/bench/external-corpus.js.map +0 -1
- package/dist/src/bench/fixtures.d.ts +0 -37
- package/dist/src/bench/fixtures.js.map +0 -1
- package/dist/src/brain-export.d.ts +0 -64
- package/dist/src/brain-export.js.map +0 -1
- package/dist/src/brain-watch-hook.d.ts +0 -21
- package/dist/src/brain-watch-hook.js.map +0 -1
- package/dist/src/cachly-url.d.ts +0 -68
- package/dist/src/cachly-url.js.map +0 -1
- package/dist/src/ckg.d.ts +0 -54
- package/dist/src/ckg.js.map +0 -1
- package/dist/src/cls-hook.d.ts +0 -15
- package/dist/src/cls-hook.js.map +0 -1
- package/dist/src/confidence.d.ts +0 -19
- package/dist/src/confidence.js.map +0 -1
- package/dist/src/credentials.d.ts +0 -37
- package/dist/src/credentials.js.map +0 -1
- package/dist/src/deutsch.d.ts +0 -98
- package/dist/src/deutsch.js.map +0 -1
- package/dist/src/doctor.d.ts +0 -47
- package/dist/src/doctor.js.map +0 -1
- package/dist/src/editor.d.ts +0 -9
- package/dist/src/editor.js.map +0 -1
- package/dist/src/eingaenge-nachruesten.d.ts +0 -41
- package/dist/src/eingaenge-nachruesten.js.map +0 -1
- package/dist/src/eingaenge.d.ts +0 -159
- package/dist/src/eingaenge.js.map +0 -1
- package/dist/src/embeddings.d.ts +0 -48
- package/dist/src/embeddings.js.map +0 -1
- package/dist/src/feldreparatur.d.ts +0 -58
- package/dist/src/feldreparatur.js.map +0 -1
- package/dist/src/first-contact.d.ts +0 -56
- package/dist/src/first-contact.js.map +0 -1
- package/dist/src/first-recall-proof.d.ts +0 -19
- package/dist/src/first-recall-proof.js.map +0 -1
- package/dist/src/funnel-milestones.d.ts +0 -5
- package/dist/src/funnel-milestones.js.map +0 -1
- package/dist/src/geliefert.d.ts +0 -63
- package/dist/src/geliefert.js.map +0 -1
- package/dist/src/handlers/advanced.d.ts +0 -6
- package/dist/src/handlers/advanced.js.map +0 -1
- package/dist/src/handlers/brain.d.ts +0 -41
- package/dist/src/handlers/brain.js.map +0 -1
- package/dist/src/handlers/cache.d.ts +0 -6
- package/dist/src/handlers/cache.js.map +0 -1
- package/dist/src/handlers/context.d.ts +0 -6
- package/dist/src/handlers/context.js.map +0 -1
- package/dist/src/handlers/fedbrain.d.ts +0 -18
- package/dist/src/handlers/fedbrain.js.map +0 -1
- package/dist/src/handlers/instances.d.ts +0 -33
- package/dist/src/handlers/instances.js.map +0 -1
- package/dist/src/handlers/roadmap.d.ts +0 -6
- package/dist/src/handlers/roadmap.js.map +0 -1
- package/dist/src/handlers/share.d.ts +0 -8
- package/dist/src/handlers/share.js.map +0 -1
- package/dist/src/handlers/syndicate.d.ts +0 -6
- package/dist/src/handlers/syndicate.js.map +0 -1
- package/dist/src/handlers/team.d.ts +0 -45
- package/dist/src/handlers/team.js.map +0 -1
- package/dist/src/handlers/viz.d.ts +0 -6
- package/dist/src/handlers/viz.js.map +0 -1
- package/dist/src/index.d.ts +0 -93
- package/dist/src/index.js.map +0 -1
- package/dist/src/interferenz.d.ts +0 -111
- package/dist/src/interferenz.js.map +0 -1
- package/dist/src/kostprobe.d.ts +0 -25
- package/dist/src/kostprobe.js.map +0 -1
- package/dist/src/lesson-preview.d.ts +0 -81
- package/dist/src/lesson-preview.js.map +0 -1
- package/dist/src/namespace.d.ts +0 -20
- package/dist/src/namespace.js.map +0 -1
- package/dist/src/notifier.d.ts +0 -5
- package/dist/src/notifier.js.map +0 -1
- package/dist/src/rangfolge.d.ts +0 -205
- package/dist/src/rangfolge.js.map +0 -1
- package/dist/src/raumkorrektur.d.ts +0 -100
- package/dist/src/raumkorrektur.js.map +0 -1
- package/dist/src/recall-tiefe.d.ts +0 -48
- package/dist/src/recall-tiefe.js.map +0 -1
- package/dist/src/rerank.d.ts +0 -48
- package/dist/src/rerank.js.map +0 -1
- package/dist/src/resonanz.d.ts +0 -85
- package/dist/src/resonanz.js.map +0 -1
- package/dist/src/search.d.ts +0 -153
- package/dist/src/search.js.map +0 -1
- package/dist/src/seltenheitsbestand.d.ts +0 -53
- package/dist/src/seltenheitsbestand.js.map +0 -1
- package/dist/src/speicherlage.d.ts +0 -51
- package/dist/src/speicherlage.js.map +0 -1
- package/dist/src/spuren.d.ts +0 -97
- package/dist/src/spuren.js.map +0 -1
- package/dist/src/starter-corpus.d.ts +0 -28
- package/dist/src/starter-corpus.js.map +0 -1
- package/dist/src/telemetry-types.d.ts +0 -87
- package/dist/src/telemetry-types.js.map +0 -1
- package/dist/src/tools.d.ts +0 -2933
- package/dist/src/tools.js.map +0 -1
- package/dist/src/toolspecs.d.ts +0 -43
- package/dist/src/toolspecs.js.map +0 -1
- package/dist/src/upgrade-nudge.d.ts +0 -15
- package/dist/src/upgrade-nudge.js.map +0 -1
- package/dist/src/utils.d.ts +0 -34
- package/dist/src/utils.js.map +0 -1
- package/dist/src/versuch.d.ts +0 -187
- package/dist/src/versuch.js.map +0 -1
- package/dist/src/vorspann.d.ts +0 -73
- package/dist/src/vorspann.js.map +0 -1
- package/dist/src/wartung/vektoren-verdichten.d.ts +0 -50
- package/dist/src/wartung/vektoren-verdichten.js.map +0 -1
- package/dist/src/werkzeug-nutzung.d.ts +0 -62
- package/dist/src/werkzeug-nutzung.js.map +0 -1
- package/dist/src/wertbeitrag.d.ts +0 -148
- package/dist/src/wertbeitrag.js.map +0 -1
package/dist/src/search.js
CHANGED
|
@@ -1,2104 +1 @@
|
|
|
1
|
-
// ── Search Engine (BM25+ with enhancements, works without embedding) ──────────
|
|
2
|
-
//
|
|
3
|
-
// Features beyond standard BM25:
|
|
4
|
-
// • BM25+ (delta=1) — fixes BM25's "long document penalty" bug
|
|
5
|
-
// • Bigram proximity boost — adjacent query terms in doc score 2× more
|
|
6
|
-
// • Recency boost — newer entries rank higher (exponential decay, 7-day half-life)
|
|
7
|
-
// • Multi-query splitting — numbered lists, semicolons, conjunctions
|
|
8
|
-
// • Fuzzy matching with Levenshtein distance ≤ 2
|
|
9
|
-
// • Multilingual stopwords (EN, DE, FR, ES, IT, PT, ZH, JA, KO, AR, HE)
|
|
10
|
-
// • CJK character bigram extraction — handles Chinese, Japanese, Korean
|
|
11
|
-
// • RTL language support (Arabic, Hebrew) — word tokenization + light stemming
|
|
12
|
-
// • Romanization matching — katakana → romaji tokens for romaji queries
|
|
13
|
-
// • Cross-language retrieval — tech term synonyms EN↔JA↔ZH↔KO↔AR↔HE
|
|
14
|
-
// • Pipeline Redis reads for performance
|
|
15
|
-
//
|
|
16
|
-
/**
|
|
17
|
-
* Stopwords — filtered out during tokenization.
|
|
18
|
-
* Covers: English, German, French, Spanish, Italian, Portuguese,
|
|
19
|
-
* Chinese (Simplified + Traditional), Japanese, Korean.
|
|
20
|
-
* Keeps the index small and scores meaningful.
|
|
21
|
-
*/
|
|
22
|
-
const STOPWORDS = new Set([
|
|
23
|
-
// ── English ──
|
|
24
|
-
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
|
|
25
|
-
'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing',
|
|
26
|
-
'will', 'would', 'could', 'should', 'may', 'might', 'shall', 'can',
|
|
27
|
-
'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'as',
|
|
28
|
-
'into', 'through', 'during', 'before', 'after', 'above', 'below',
|
|
29
|
-
'between', 'about', 'against', 'among', 'around', 'without', 'within',
|
|
30
|
-
'along', 'across', 'behind', 'beyond', 'upon', 'toward', 'towards',
|
|
31
|
-
'and', 'but', 'or', 'not', 'no', 'nor', 'so', 'if', 'then', 'than',
|
|
32
|
-
'too', 'very', 'quite', 'rather', 'just', 'also', 'only', 'even',
|
|
33
|
-
'it', 'its', 'this', 'that', 'these', 'those', 'here', 'there',
|
|
34
|
-
'my', 'your', 'his', 'her', 'our', 'their', 'mine', 'yours', 'ours',
|
|
35
|
-
'what', 'which', 'who', 'whom', 'whose', 'how', 'when', 'where', 'why',
|
|
36
|
-
'all', 'each', 'every', 'both', 'few', 'more', 'most', 'much', 'many',
|
|
37
|
-
'other', 'some', 'such', 'own', 'same', 'any', 'either', 'neither',
|
|
38
|
-
'been', 'being', 'because', 'until', 'while', 'once', 'again', 'further',
|
|
39
|
-
'already', 'always', 'never', 'sometimes', 'often', 'still', 'yet',
|
|
40
|
-
// ── German ──
|
|
41
|
-
'der', 'die', 'das', 'den', 'dem', 'des', 'ein', 'eine', 'einen',
|
|
42
|
-
'einem', 'einer', 'eines', 'und', 'oder', 'aber', 'denn', 'weil',
|
|
43
|
-
'ist', 'sind', 'war', 'waren', 'sein', 'wird', 'werden', 'wurde',
|
|
44
|
-
'hat', 'haben', 'hatte', 'hatten', 'kann', 'können', 'konnte',
|
|
45
|
-
'soll', 'sollen', 'sollte', 'muss', 'müssen', 'musste', 'darf',
|
|
46
|
-
'mag', 'möchte', 'wollen', 'wollte', 'würde', 'könnte', 'sollte',
|
|
47
|
-
'mit', 'für', 'auf', 'von', 'aus', 'bei', 'nach', 'über', 'unter',
|
|
48
|
-
'vor', 'hinter', 'neben', 'zwischen', 'durch', 'gegen', 'ohne',
|
|
49
|
-
'um', 'bis', 'seit', 'während', 'wegen', 'trotz', 'statt',
|
|
50
|
-
'wie', 'was', 'wer', 'wen', 'wem', 'wessen', 'wo', 'wann', 'warum',
|
|
51
|
-
'nicht', 'noch', 'auch', 'schon', 'nur', 'sehr', 'mehr', 'viel',
|
|
52
|
-
'alle', 'jeder', 'jede', 'jedes', 'dieser', 'diese', 'dieses',
|
|
53
|
-
'jener', 'jene', 'jenes', 'mein', 'dein', 'sein', 'ihr', 'unser',
|
|
54
|
-
'euer', 'kein', 'keine', 'sich', 'mir', 'dir', 'ihm', 'uns', 'euch',
|
|
55
|
-
'ich', 'du', 'er', 'sie', 'es', 'wir', 'ihr', 'man',
|
|
56
|
-
'hier', 'dort', 'da', 'dann', 'also', 'doch', 'mal', 'eben', 'ganz',
|
|
57
|
-
// ── French ──
|
|
58
|
-
'le', 'la', 'les', 'un', 'une', 'des', 'du', 'de', 'au', 'aux',
|
|
59
|
-
'et', 'ou', 'mais', 'donc', 'car', 'ni', 'que', 'qui', 'quoi',
|
|
60
|
-
'est', 'sont', 'était', 'ont', 'avoir', 'être', 'fait', 'faire',
|
|
61
|
-
'pour', 'par', 'avec', 'dans', 'sur', 'sous', 'entre', 'vers',
|
|
62
|
-
'chez', 'sans', 'avant', 'après', 'pendant', 'depuis', 'contre',
|
|
63
|
-
'ce', 'cette', 'ces', 'mon', 'ton', 'son', 'notre', 'votre', 'leur',
|
|
64
|
-
'je', 'tu', 'il', 'elle', 'nous', 'vous', 'ils', 'elles', 'on',
|
|
65
|
-
'ne', 'pas', 'plus', 'très', 'bien', 'aussi', 'tout', 'tous', 'toute',
|
|
66
|
-
'même', 'autre', 'quel', 'quelle', 'comment', 'quand', 'où', 'pourquoi',
|
|
67
|
-
// ── Spanish ──
|
|
68
|
-
'el', 'la', 'los', 'las', 'un', 'una', 'unos', 'unas', 'del', 'al',
|
|
69
|
-
'lo', 'que', 'en', 'es', 'por', 'con', 'para', 'como', 'pero', 'más',
|
|
70
|
-
'fue', 'ser', 'hay', 'está', 'han', 'son', 'tiene', 'había', 'era',
|
|
71
|
-
'su', 'sus', 'este', 'esta', 'estos', 'estas', 'ese', 'esa', 'esos',
|
|
72
|
-
'mi', 'tu', 'yo', 'él', 'ella', 'nosotros', 'ellos', 'ellas', 'usted',
|
|
73
|
-
'no', 'ya', 'sí', 'sin', 'sobre', 'entre', 'hasta', 'desde', 'donde',
|
|
74
|
-
'muy', 'todo', 'toda', 'todos', 'cada', 'otro', 'otra', 'otros',
|
|
75
|
-
'cuando', 'porque', 'aunque', 'también', 'solo', 'después', 'antes',
|
|
76
|
-
// ── Italian ──
|
|
77
|
-
'il', 'lo', 'la', 'li', 'le', 'gli', 'uno', 'una', 'dei', 'del',
|
|
78
|
-
'che', 'di', 'da', 'per', 'con', 'tra', 'fra', 'sul', 'nel', 'al',
|
|
79
|
-
'è', 'sono', 'ha', 'hanno', 'era', 'essere', 'fare', 'fatto', 'stato',
|
|
80
|
-
'suo', 'sua', 'suoi', 'questo', 'questa', 'questi', 'quello', 'quella',
|
|
81
|
-
'io', 'tu', 'lui', 'lei', 'noi', 'voi', 'loro', 'ci', 'si',
|
|
82
|
-
'non', 'più', 'molto', 'anche', 'solo', 'tutto', 'tutti', 'ogni',
|
|
83
|
-
'come', 'dove', 'quando', 'perché', 'ancora', 'già', 'sempre', 'mai',
|
|
84
|
-
// ── Portuguese ──
|
|
85
|
-
'um', 'uma', 'uns', 'umas', 'do', 'da', 'dos', 'das', 'no', 'na',
|
|
86
|
-
'ao', 'aos', 'em', 'por', 'com', 'para', 'sem', 'sob', 'sobre',
|
|
87
|
-
'que', 'se', 'mas', 'ou', 'como', 'mais', 'entre', 'até', 'desde',
|
|
88
|
-
'é', 'são', 'foi', 'tem', 'ser', 'ter', 'estar', 'fazer', 'havia',
|
|
89
|
-
'seu', 'sua', 'seus', 'suas', 'este', 'esta', 'esse', 'essa', 'aquele',
|
|
90
|
-
'eu', 'tu', 'ele', 'ela', 'nós', 'eles', 'elas', 'você', 'vocês',
|
|
91
|
-
'não', 'já', 'sim', 'bem', 'muito', 'também', 'ainda', 'sempre',
|
|
92
|
-
'todo', 'toda', 'todos', 'cada', 'outro', 'outra', 'quando', 'porque',
|
|
93
|
-
// ── Chinese (Simplified + Traditional) — high-frequency function characters ──
|
|
94
|
-
'的', '了', '是', '在', '不', '和', '我', '他', '这', '中', '大', '为',
|
|
95
|
-
'上', '个', '国', '以', '要', '就', '出', '说', '们', '有', '来', '到',
|
|
96
|
-
'时', '地', '年', '得', '着', '那', '过', '后', '还', '与', '也', '可',
|
|
97
|
-
'于', '从', '但', '而', '被', '把', '让', '使', '对', '很', '都', '一',
|
|
98
|
-
'会', '没', '人', '它', '这个', '那个', '什么', '如果', '因为', '所以',
|
|
99
|
-
'已经', '可以', '这些', '那些', '我们', '他们', '她们', '它们',
|
|
100
|
-
// ── Japanese — common hiragana particles and auxiliary verbs ──
|
|
101
|
-
'の', 'は', 'が', 'を', 'に', 'で', 'と', 'も', 'や', 'か', 'な', 'ね',
|
|
102
|
-
'よ', 'わ', 'て', 'い', 'う', 'え', 'お', 'き', 'く', 'け', 'こ', 'さ',
|
|
103
|
-
'し', 'す', 'せ', 'そ', 'た', 'ち', 'つ', 'ぬ', 'ん', 'から', 'まで',
|
|
104
|
-
'より', 'へ', 'です', 'ます', 'ない', 'ある', 'いる', 'する', 'こと',
|
|
105
|
-
'もの', 'ので', 'では', 'には', 'との', 'への', 'から', 'まで',
|
|
106
|
-
// ── Korean — common particles and auxiliary forms ──
|
|
107
|
-
'이', '가', '은', '는', '을', '를', '의', '에', '와', '과', '도',
|
|
108
|
-
'로', '에서', '한', '하', '있', '없', '것', '수', '않', '들',
|
|
109
|
-
'이다', '하다', '이고', '이며', '라고', '에게', '에서', '으로',
|
|
110
|
-
// ── Arabic — high-frequency function words & particles ──
|
|
111
|
-
'في', 'من', 'إلى', 'على', 'عن', 'مع', 'هذا', 'هذه', 'ذلك', 'تلك',
|
|
112
|
-
'الذي', 'التي', 'الذين', 'اللواتي', 'هو', 'هي', 'هم', 'هن', 'نحن',
|
|
113
|
-
'أنت', 'أنتم', 'أنا', 'كان', 'كانت', 'كانوا', 'يكون', 'تكون',
|
|
114
|
-
'أن', 'إن', 'لأن', 'لكن', 'أو', 'بل', 'ثم', 'حتى', 'إذا', 'كي',
|
|
115
|
-
'قد', 'لقد', 'لم', 'لن', 'ما', 'لا', 'ليس', 'غير', 'بعض', 'كل',
|
|
116
|
-
'جميع', 'أي', 'كيف', 'متى', 'أين', 'لماذا', 'ماذا', 'هل', 'ال',
|
|
117
|
-
'و', 'ف', 'ب', 'ل', 'ك', 'يا', 'أم', 'إلا', 'عند', 'بين',
|
|
118
|
-
// ── Hebrew — common particles, pronouns, conjunctions ──
|
|
119
|
-
'של', 'את', 'אל', 'על', 'עם', 'לא', 'הוא', 'היא', 'הם', 'הן',
|
|
120
|
-
'אני', 'אתה', 'אנחנו', 'אתם', 'כי', 'אם', 'אבל', 'גם', 'כבר',
|
|
121
|
-
'רק', 'עוד', 'יש', 'אין', 'מה', 'זה', 'זאת', 'אלה', 'כל', 'כן',
|
|
122
|
-
'לו', 'לה', 'להם', 'בו', 'בה', 'בהם', 'שם', 'כך', 'כן', 'מי',
|
|
123
|
-
'אשר', 'אחרי', 'לפני', 'תחת', 'בין', 'מאז', 'עד', 'כמו', 'אז',
|
|
124
|
-
// ── Farsi/Persian — common function words, prepositions, pronouns ──
|
|
125
|
-
'در', 'از', 'به', 'با', 'که', 'این', 'آن', 'را', 'است',
|
|
126
|
-
'بود', 'باشد', 'شد', 'شده', 'می', 'نه', 'نیست', 'هم', 'هر',
|
|
127
|
-
'یک', 'اما', 'و', 'یا', 'تا', 'اگر', 'برای', 'چون', 'چه',
|
|
128
|
-
'کجا', 'کی', 'چطور', 'وقتی', 'بعد', 'قبل', 'مثل', 'همه', 'بعضی',
|
|
129
|
-
'هیچ', 'آیا', 'خود', 'چند', 'دیگر', 'هنوز', 'همان', 'آنها', 'اینها',
|
|
130
|
-
'ما', 'شما', 'آنان', 'من', 'تو', 'او', 'آنان', 'ایشان',
|
|
131
|
-
'روی', 'زیر', 'بین', 'پیش', 'پس', 'طرف', 'داخل', 'خارج', 'کنار',
|
|
132
|
-
'همچنین', 'مگر', 'ولی', 'وگرنه', 'چرا', 'چگونه', 'کدام',
|
|
133
|
-
// ── Hindi — common particles, postpositions, pronouns, auxiliary verbs ──
|
|
134
|
-
'है', 'में', 'से', 'को', 'का', 'की', 'के', 'पर', 'और', 'या',
|
|
135
|
-
'नहीं', 'यह', 'वह', 'एक', 'इस', 'उस', 'भी', 'हो', 'था', 'थी',
|
|
136
|
-
'थे', 'हैं', 'हूँ', 'लिए', 'तक', 'साथ', 'बाद', 'पहले', 'जो',
|
|
137
|
-
'जब', 'कैसे', 'क्यों', 'क्या', 'कहाँ', 'कौन', 'हम', 'आप', 'वे',
|
|
138
|
-
'मैं', 'तुम', 'उन', 'इन', 'ने', 'बहुत', 'सब', 'कुछ', 'फिर',
|
|
139
|
-
'अब', 'तो', 'ही', 'तरह', 'जैसे', 'करना', 'होना', 'रहा', 'रही',
|
|
140
|
-
'रहे', 'गया', 'गई', 'गए', 'किया', 'किए', 'कर', 'हुआ', 'हुई',
|
|
141
|
-
// ── Russian — common prepositions, pronouns, auxiliary verbs ───────────────
|
|
142
|
-
'в', 'на', 'не', 'с', 'и', 'а', 'но', 'по', 'за', 'из', 'от', 'до',
|
|
143
|
-
'к', 'у', 'о', 'об', 'во', 'при', 'под', 'над', 'без', 'для',
|
|
144
|
-
'что', 'как', 'это', 'все', 'так', 'уже', 'или', 'же', 'ли',
|
|
145
|
-
'если', 'то', 'да', 'нет', 'был', 'была', 'были', 'быть', 'есть',
|
|
146
|
-
'его', 'её', 'их', 'этот', 'эта', 'эти', 'который', 'которая',
|
|
147
|
-
'которые', 'который', 'мой', 'моя', 'мои', 'ваш', 'ваша', 'ваши',
|
|
148
|
-
'он', 'она', 'они', 'мы', 'вы', 'я', 'ты', 'тот', 'та', 'те',
|
|
149
|
-
'очень', 'тоже', 'также', 'когда', 'где', 'как', 'почему', 'зачем',
|
|
150
|
-
'сейчас', 'здесь', 'там', 'потому', 'поэтому', 'чтобы', 'тут',
|
|
151
|
-
// ── Turkish — common particles, postpositions, copulas ─────────────────────
|
|
152
|
-
'bir', 'bu', 'şu', 'o', 've', 'ile', 'de', 'da', 'için', 'gibi',
|
|
153
|
-
'ama', 'fakat', 'ancak', 'ya', 'ne', 'ki', 'mi', 'mı', 'mu', 'mü',
|
|
154
|
-
'var', 'yok', 'olan', 'oldu', 'olur', 'olarak', 'ise', 'daha',
|
|
155
|
-
'çok', 'en', 'her', 'hiç', 'bazı', 'tüm', 'bütün', 'hem', 'veya',
|
|
156
|
-
'bu', 'şu', 'ben', 'sen', 'biz', 'siz', 'onlar', 'benim', 'senin',
|
|
157
|
-
'nasıl', 'neden', 'niçin', 'nerede', 'ne', 'hangi', 'kaç',
|
|
158
|
-
// ── Polish — common prepositions, pronouns, particles ─────────────────────
|
|
159
|
-
'w', 'na', 'z', 'do', 'się', 'że', 'to', 'jest', 'i', 'a', 'nie',
|
|
160
|
-
'tak', 'jak', 'czy', 'po', 'o', 'ale', 'go', 'mu', 'jej', 'ich',
|
|
161
|
-
'tego', 'tej', 'te', 'ten', 'ta', 'są', 'był', 'była', 'było', 'byli',
|
|
162
|
-
'będzie', 'będą', 'ma', 'mam', 'masz', 'mają', 'ze', 'co', 'już',
|
|
163
|
-
'przez', 'przy', 'za', 'bez', 'nad', 'pod', 'przed', 'po', 'między',
|
|
164
|
-
'kiedy', 'gdzie', 'dlaczego', 'który', 'która', 'które', 'tylko', 'też',
|
|
165
|
-
// ── Czech — common words ──────────────────────────────────────────────────
|
|
166
|
-
'v', 'na', 'z', 'do', 'se', 'že', 'to', 'je', 'a', 'ne', 'pro',
|
|
167
|
-
'ale', 'jak', 'by', 'byl', 'být', 'jsem', 'jsou', 'má', 'mám',
|
|
168
|
-
'ten', 'ta', 'ty', 'tato', 'jeho', 'její', 'jejich', 'také', 'jen',
|
|
169
|
-
'kde', 'kdy', 'proč', 'který', 'která', 'které', 'co', 'při', 'bez',
|
|
170
|
-
// ── Bengali — common particles, pronouns, verbs ───────────────────────────
|
|
171
|
-
'এই', 'এটি', 'এটা', 'এর', 'তার', 'তারা', 'আমি', 'তুমি', 'সে', 'আমরা',
|
|
172
|
-
'এবং', 'কিন্তু', 'বা', 'না', 'হ্যাঁ', 'যে', 'কি', 'কে', 'কী', 'থেকে',
|
|
173
|
-
'দিয়ে', 'জন্য', 'সাথে', 'মধ্যে', 'উপর', 'নিচে', 'আছে', 'ছিল', 'হয়',
|
|
174
|
-
'করা', 'করে', 'করেছে', 'হবে', 'হয়েছে', 'একটি', 'একটা', 'অনেক', 'সব',
|
|
175
|
-
// ── Vietnamese — common particles, pronouns, auxiliary words ─────────────
|
|
176
|
-
'tôi', 'bạn', 'anh', 'chị', 'em', 'họ', 'chúng', 'ta', 'mình',
|
|
177
|
-
'là', 'có', 'không', 'và', 'với', 'của', 'cho', 'trong', 'về',
|
|
178
|
-
'từ', 'đến', 'để', 'khi', 'nếu', 'thì', 'mà', 'nhưng', 'vì',
|
|
179
|
-
'đây', 'đó', 'này', 'kia', 'rất', 'cũng', 'đã', 'sẽ', 'đang',
|
|
180
|
-
'được', 'bị', 'những', 'các', 'một', 'hai', 'ba', 'nhiều', 'ít',
|
|
181
|
-
'nào', 'ai', 'gì', 'đâu', 'sao', 'bao', 'giờ', 'lúc', 'sau',
|
|
182
|
-
]);
|
|
183
|
-
// CJK Unicode ranges used for bigram extraction
|
|
184
|
-
const CJK_RE = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/;
|
|
185
|
-
const SEGMENT_RE = /([\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+|[^\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+)/g;
|
|
186
|
-
// RTL Unicode ranges: Arabic (U+0600–U+06FF + extended), Hebrew (U+0590–U+05FF)
|
|
187
|
-
const RTL_RE = /[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufb4f\ufb50-\ufdff\ufe70-\ufeff]/;
|
|
188
|
-
// Distinguish Arabic from Hebrew within RTL segments
|
|
189
|
-
const HEBREW_CHAR_RE = /[\u0590-\u05ff\ufb1d-\ufb4f]/;
|
|
190
|
-
const _ARABIC_CHAR_RE = /[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb50-\ufdff\ufe70-\ufeff]/;
|
|
191
|
-
// Persian/Farsi: exclusive chars not in Arabic (U+067E=پ, U+0686=چ, U+0698=ژ, U+06AF=گ, U+06CC=ی)
|
|
192
|
-
const FARSI_CHAR_RE = /[\u067e\u0686\u0698\u06af\u06cc]/;
|
|
193
|
-
// Devanagari (Hindi, Sanskrit, Marathi …) — U+0900–U+097F + extended
|
|
194
|
-
const DEVANAGARI_RE = /[\u0900-\u097f]/;
|
|
195
|
-
// Cyrillic (Russian, Bulgarian, Ukrainian, Serbian …) — U+0400–U+04FF
|
|
196
|
-
const CYRILLIC_RE = /[\u0400-\u04ff]/;
|
|
197
|
-
// Turkish uses Latin alphabet but has unique chars (ğ, ş, ı, ö, ü, ç) — detected by these
|
|
198
|
-
const TURKISH_CHAR_RE = /[\u011f\u015f\u0131\u0130\u00e7]/; // ğ ş ı İ ç
|
|
199
|
-
// Bengali (Bangla) — U+0980–U+09FF
|
|
200
|
-
const BENGALI_RE = /[\u0980-\u09ff]/;
|
|
201
|
-
// Vietnamese uses Latin + Latin Extended Additional (U+1EA0–U+1EF9) for tone marks
|
|
202
|
-
// e.g. ắ ặ ầ ổ ợ ụ ừ — detected by chars exclusive to Vietnamese diacritics
|
|
203
|
-
const _VIETNAMESE_CHAR_RE = /[\u1ea0-\u1ef9]/;
|
|
204
|
-
// ── Katakana → Romaji conversion table (Hepburn system) ──────────────────────
|
|
205
|
-
// Digraphs must be listed before single chars so they match first.
|
|
206
|
-
const KATA_ROMAJI_TABLE = [
|
|
207
|
-
// Special combinations for loanwords
|
|
208
|
-
['ファ', 'fa'], ['フィ', 'fi'], ['フェ', 'fe'], ['フォ', 'fo'],
|
|
209
|
-
['ティ', 'ti'], ['ディ', 'di'], ['トゥ', 'tu'], ['ドゥ', 'du'],
|
|
210
|
-
['ウィ', 'wi'], ['ウェ', 'we'], ['ウォ', 'wo'],
|
|
211
|
-
['チェ', 'che'], ['ジェ', 'je'], ['シェ', 'she'],
|
|
212
|
-
['イェ', 'ye'], ['ヴァ', 'va'], ['ヴィ', 'vi'], ['ヴェ', 've'], ['ヴォ', 'vo'],
|
|
213
|
-
// Digraphs (2-char → romaji)
|
|
214
|
-
['キャ', 'kya'], ['キュ', 'kyu'], ['キョ', 'kyo'],
|
|
215
|
-
['シャ', 'sha'], ['シュ', 'shu'], ['ショ', 'sho'],
|
|
216
|
-
['チャ', 'cha'], ['チュ', 'chu'], ['チョ', 'cho'],
|
|
217
|
-
['ニャ', 'nya'], ['ニュ', 'nyu'], ['ニョ', 'nyo'],
|
|
218
|
-
['ヒャ', 'hya'], ['ヒュ', 'hyu'], ['ヒョ', 'hyo'],
|
|
219
|
-
['ミャ', 'mya'], ['ミュ', 'myu'], ['ミョ', 'myo'],
|
|
220
|
-
['リャ', 'rya'], ['リュ', 'ryu'], ['リョ', 'ryo'],
|
|
221
|
-
['ギャ', 'gya'], ['ギュ', 'gyu'], ['ギョ', 'gyo'],
|
|
222
|
-
['ジャ', 'ja'], ['ジュ', 'ju'], ['ジョ', 'jo'],
|
|
223
|
-
['ビャ', 'bya'], ['ビュ', 'byu'], ['ビョ', 'byo'],
|
|
224
|
-
['ピャ', 'pya'], ['ピュ', 'pyu'], ['ピョ', 'pyo'],
|
|
225
|
-
// Single chars
|
|
226
|
-
['ア', 'a'], ['イ', 'i'], ['ウ', 'u'], ['エ', 'e'], ['オ', 'o'],
|
|
227
|
-
['カ', 'ka'], ['キ', 'ki'], ['ク', 'ku'], ['ケ', 'ke'], ['コ', 'ko'],
|
|
228
|
-
['サ', 'sa'], ['シ', 'shi'], ['ス', 'su'], ['セ', 'se'], ['ソ', 'so'],
|
|
229
|
-
['タ', 'ta'], ['チ', 'chi'], ['ツ', 'tsu'], ['テ', 'te'], ['ト', 'to'],
|
|
230
|
-
['ナ', 'na'], ['ニ', 'ni'], ['ヌ', 'nu'], ['ネ', 'ne'], ['ノ', 'no'],
|
|
231
|
-
['ハ', 'ha'], ['ヒ', 'hi'], ['フ', 'fu'], ['ヘ', 'he'], ['ホ', 'ho'],
|
|
232
|
-
['マ', 'ma'], ['ミ', 'mi'], ['ム', 'mu'], ['メ', 'me'], ['モ', 'mo'],
|
|
233
|
-
['ヤ', 'ya'], ['ユ', 'yu'], ['ヨ', 'yo'],
|
|
234
|
-
['ラ', 'ra'], ['リ', 'ri'], ['ル', 'ru'], ['レ', 're'], ['ロ', 'ro'],
|
|
235
|
-
['ワ', 'wa'], ['ヲ', 'wo'], ['ン', 'n'],
|
|
236
|
-
// Voiced
|
|
237
|
-
['ガ', 'ga'], ['ギ', 'gi'], ['グ', 'gu'], ['ゲ', 'ge'], ['ゴ', 'go'],
|
|
238
|
-
['ザ', 'za'], ['ジ', 'ji'], ['ズ', 'zu'], ['ゼ', 'ze'], ['ゾ', 'zo'],
|
|
239
|
-
['ダ', 'da'], ['ヂ', 'ji'], ['ヅ', 'zu'], ['デ', 'de'], ['ド', 'do'],
|
|
240
|
-
['バ', 'ba'], ['ビ', 'bi'], ['ブ', 'bu'], ['ベ', 'be'], ['ボ', 'bo'],
|
|
241
|
-
['パ', 'pa'], ['ピ', 'pi'], ['プ', 'pu'], ['ペ', 'pe'], ['ポ', 'po'],
|
|
242
|
-
['ヴ', 'v'],
|
|
243
|
-
// Long vowel / small chars
|
|
244
|
-
['ー', ''], ['ァ', 'a'], ['ィ', 'i'], ['ゥ', 'u'], ['ェ', 'e'], ['ォ', 'o'],
|
|
245
|
-
['ッ', ''], // handled separately (doubles next consonant)
|
|
246
|
-
];
|
|
247
|
-
const KATA_MAP = new Map(KATA_ROMAJI_TABLE);
|
|
248
|
-
/**
|
|
249
|
-
* Convert a katakana string to Hepburn romaji.
|
|
250
|
-
* Handles digraphs, geminate consonants (ッ), and long vowel marks (ー).
|
|
251
|
-
*/
|
|
252
|
-
function katakanaToRomaji(kata) {
|
|
253
|
-
let result = '';
|
|
254
|
-
let i = 0;
|
|
255
|
-
while (i < kata.length) {
|
|
256
|
-
// Geminate consonant: ッ doubles the following consonant
|
|
257
|
-
if (kata[i] === 'ッ' && i + 1 < kata.length) {
|
|
258
|
-
const next = KATA_MAP.get(kata[i + 1]) ?? KATA_MAP.get(kata[i + 1] + kata[i + 2]) ?? '';
|
|
259
|
-
if (next.length > 0)
|
|
260
|
-
result += next[0]; // double first consonant
|
|
261
|
-
i++;
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
// Try 2-char digraph first
|
|
265
|
-
if (i + 1 < kata.length) {
|
|
266
|
-
const two = kata[i] + kata[i + 1];
|
|
267
|
-
const r2 = KATA_MAP.get(two);
|
|
268
|
-
if (r2 !== undefined) {
|
|
269
|
-
result += r2;
|
|
270
|
-
i += 2;
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
// Single char
|
|
275
|
-
const r1 = KATA_MAP.get(kata[i]);
|
|
276
|
-
if (r1 !== undefined)
|
|
277
|
-
result += r1;
|
|
278
|
-
i++;
|
|
279
|
-
}
|
|
280
|
-
return result;
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* Arabic light stemmer — strips definite article and common prefix particles.
|
|
284
|
-
* Handles: ال (al-), و (wa-), ب (bi-), ل (li-), ف (fa-), ك (ka-).
|
|
285
|
-
* Runs iteratively (max 3 passes) so compound prefixes like فال- are fully
|
|
286
|
-
* resolved: فالخطأ → الخطأ → خطأ.
|
|
287
|
-
* Only strips when the result is still ≥ 3 chars to avoid over-stemming.
|
|
288
|
-
*/
|
|
289
|
-
function arabicLightStem(word) {
|
|
290
|
-
let result = word;
|
|
291
|
-
for (let i = 0; i < 3; i++) {
|
|
292
|
-
const prev = result;
|
|
293
|
-
if (result.startsWith('ال') && result.length > 4) {
|
|
294
|
-
result = result.slice(2);
|
|
295
|
-
}
|
|
296
|
-
else if (result.length > 3 && 'وبلفك'.includes(result[0]) && RTL_RE.test(result[1])) {
|
|
297
|
-
result = result.slice(1);
|
|
298
|
-
}
|
|
299
|
-
if (result === prev)
|
|
300
|
-
break; // stable — no more prefixes to strip
|
|
301
|
-
}
|
|
302
|
-
return result;
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Hebrew light stemmer — strips the definite article and common prefix particles
|
|
306
|
-
* that attach directly to words (no space) in Hebrew.
|
|
307
|
-
*
|
|
308
|
-
* Handles:
|
|
309
|
-
* ה (ha-) — definite article: הפריסה → פריסה
|
|
310
|
-
* ו (ve-/u-) — conjunction “and”: ופריסה → פריסה
|
|
311
|
-
* ב (be-/bi-) — preposition “in”: בסביבה → סביבה
|
|
312
|
-
* ל (le-/li-) — preposition “for”: לשרת → שרת
|
|
313
|
-
* מ (mi-/me-) — preposition “from”: מהשרת → השרת → שרת
|
|
314
|
-
* כ (ke-/ki-) — preposition “like”: כשרת → שרת
|
|
315
|
-
*
|
|
316
|
-
* Iterative (max 3 passes): מהפריסה → הפריסה → פריסה.
|
|
317
|
-
* Only strips when result is still ≥ 3 chars.
|
|
318
|
-
*/
|
|
319
|
-
function hebrewLightStem(word) {
|
|
320
|
-
let result = word;
|
|
321
|
-
for (let i = 0; i < 3; i++) {
|
|
322
|
-
const prev = result;
|
|
323
|
-
if (result.length > 3 && 'הובלמכ'.includes(result[0]) && HEBREW_CHAR_RE.test(result[1])) {
|
|
324
|
-
result = result.slice(1);
|
|
325
|
-
}
|
|
326
|
-
if (result === prev)
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
return result;
|
|
330
|
-
}
|
|
331
|
-
/**
|
|
332
|
-
* Farsi/Persian light stemmer — handles Persian morphology.
|
|
333
|
-
* Strips:
|
|
334
|
-
* \u0647\u0627 / \u0647\u0627\u06cc (ha/haye) — plural suffixes: \u0633\u0631\u0648\u0631\u0647\u0627 \u2192 \u0633\u0631\u0648\u0631
|
|
335
|
-
* \u0645\u06cc\u200c / \u0645\u06cc (mi-) — present-tense prefix: \u0645\u06cc\u200c\u06a9\u0646\u062f \u2192 \u06a9\u0646\u062f
|
|
336
|
-
* \u0646\u0645\u06cc\u200c (nami-) — negated present: \u0646\u0645\u06cc\u200c\u0634\u0648\u062f \u2192 \u0634\u0648\u062f
|
|
337
|
-
* Only strips when the result is still \u2265 3 chars.
|
|
338
|
-
*/
|
|
339
|
-
function farsiLightStem(word) {
|
|
340
|
-
let result = word;
|
|
341
|
-
// Suffixes first (longest first)
|
|
342
|
-
if (result.endsWith('\u0647\u0627\u06cc') && result.length > 5)
|
|
343
|
-
result = result.slice(0, -3);
|
|
344
|
-
else if (result.endsWith('\u0647\u0627') && result.length > 4)
|
|
345
|
-
result = result.slice(0, -2);
|
|
346
|
-
// Prefixes
|
|
347
|
-
if (result.startsWith('\u0646\u0645\u06cc\u200c') && result.length > 5)
|
|
348
|
-
result = result.slice(4);
|
|
349
|
-
else if (result.startsWith('\u0645\u06cc\u200c') && result.length > 4)
|
|
350
|
-
result = result.slice(3);
|
|
351
|
-
else if (result.startsWith('\u0645\u06cc') && result.length > 4)
|
|
352
|
-
result = result.slice(2);
|
|
353
|
-
return result;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Hindi light stemmer — strips the most common inflectional suffixes.
|
|
357
|
-
* Handles basic verb forms and oblique plural markers.
|
|
358
|
-
* Avoids over-stemming loanwords (most tech terms in Hindi are English loanwords).
|
|
359
|
-
* Only strips when result is still \u2265 3 chars.
|
|
360
|
-
*/
|
|
361
|
-
function hindiLightStem(word) {
|
|
362
|
-
const result = word;
|
|
363
|
-
// Infinitive / verb suffixes (longest first to avoid partial match)
|
|
364
|
-
if (result.endsWith('\u0928\u093e') && result.length > 4)
|
|
365
|
-
return result.slice(0, -2); // \u0928\u093e (nā) infinitive
|
|
366
|
-
if (result.endsWith('\u0928\u0947') && result.length > 4)
|
|
367
|
-
return result.slice(0, -2); // \u0928\u0947 (ne) ergative
|
|
368
|
-
if (result.endsWith('\u0928\u0940') && result.length > 4)
|
|
369
|
-
return result.slice(0, -2); // \u0928\u0940 (nī) fem infinitive
|
|
370
|
-
if (result.endsWith('\u0924\u093e') && result.length > 4)
|
|
371
|
-
return result.slice(0, -2); // \u0924\u093e (tā) m present participle
|
|
372
|
-
if (result.endsWith('\u0924\u0940') && result.length > 4)
|
|
373
|
-
return result.slice(0, -2); // \u0924\u0940 (tī) f present participle
|
|
374
|
-
if (result.endsWith('\u0915\u0930') && result.length > 4)
|
|
375
|
-
return result.slice(0, -2); // \u0915\u0930 (kar) conjunctive
|
|
376
|
-
if (result.endsWith('\u0913\u0902') && result.length > 4)
|
|
377
|
-
return result.slice(0, -2); // \u0913\u0902 (oṃ) oblique plural
|
|
378
|
-
if (result.endsWith('\u0907\u092f\u093e\u0902') && result.length > 5)
|
|
379
|
-
return result.slice(0, -4); // \u0907\u092f\u093e\u0902 (iyāṃ) f plural
|
|
380
|
-
if (result.endsWith('\u0940\u092f\u093e\u0902') && result.length > 5)
|
|
381
|
-
return result.slice(0, -4); // \u0940\u092f\u093e\u0102 (īyāṃ)
|
|
382
|
-
return result;
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Russian light stemmer — strips common inflectional suffixes.
|
|
386
|
-
* Handles the most frequent verb/noun/adjective endings to improve recall.
|
|
387
|
-
* Only strips when result is still ≥ 3 chars.
|
|
388
|
-
*
|
|
389
|
-
* Covers:
|
|
390
|
-
* ошибки/ошибка → ошибк (noun plural/genitive)
|
|
391
|
-
* развёртывание → развёртыва (gerund → stem)
|
|
392
|
-
* установить → установ (infinitive)
|
|
393
|
-
* настройки → настройк (genitive plural)
|
|
394
|
-
*/
|
|
395
|
-
function russianLightStem(word) {
|
|
396
|
-
const w = word;
|
|
397
|
-
// Longest first to avoid partial stripping
|
|
398
|
-
// Verb infinitives / gerunds
|
|
399
|
-
if (w.endsWith('ывание') && w.length > 7)
|
|
400
|
-
return w.slice(0, -6);
|
|
401
|
-
if (w.endsWith('ивание') && w.length > 7)
|
|
402
|
-
return w.slice(0, -6);
|
|
403
|
-
if (w.endsWith('ование') && w.length > 7)
|
|
404
|
-
return w.slice(0, -6);
|
|
405
|
-
if (w.endsWith('вание') && w.length > 6)
|
|
406
|
-
return w.slice(0, -5);
|
|
407
|
-
if (w.endsWith('ение') && w.length > 5)
|
|
408
|
-
return w.slice(0, -4);
|
|
409
|
-
if (w.endsWith('ание') && w.length > 5)
|
|
410
|
-
return w.slice(0, -4);
|
|
411
|
-
if (w.endsWith('ить') && w.length > 4)
|
|
412
|
-
return w.slice(0, -3);
|
|
413
|
-
if (w.endsWith('ать') && w.length > 4)
|
|
414
|
-
return w.slice(0, -3);
|
|
415
|
-
if (w.endsWith('еть') && w.length > 4)
|
|
416
|
-
return w.slice(0, -3);
|
|
417
|
-
if (w.endsWith('уть') && w.length > 4)
|
|
418
|
-
return w.slice(0, -3);
|
|
419
|
-
// Noun plural/genitive
|
|
420
|
-
if (w.endsWith('ки') && w.length > 4)
|
|
421
|
-
return w.slice(0, -2);
|
|
422
|
-
if (w.endsWith('ги') && w.length > 4)
|
|
423
|
-
return w.slice(0, -2);
|
|
424
|
-
if (w.endsWith('ов') && w.length > 4)
|
|
425
|
-
return w.slice(0, -2);
|
|
426
|
-
if (w.endsWith('ев') && w.length > 4)
|
|
427
|
-
return w.slice(0, -2);
|
|
428
|
-
if (w.endsWith('ей') && w.length > 4)
|
|
429
|
-
return w.slice(0, -2);
|
|
430
|
-
if (w.endsWith('ий') && w.length > 4)
|
|
431
|
-
return w.slice(0, -2);
|
|
432
|
-
if (w.endsWith('ый') && w.length > 4)
|
|
433
|
-
return w.slice(0, -2);
|
|
434
|
-
if (w.endsWith('ая') && w.length > 4)
|
|
435
|
-
return w.slice(0, -2);
|
|
436
|
-
if (w.endsWith('ое') && w.length > 4)
|
|
437
|
-
return w.slice(0, -2);
|
|
438
|
-
if (w.endsWith('ую') && w.length > 4)
|
|
439
|
-
return w.slice(0, -2);
|
|
440
|
-
// Verb present tense
|
|
441
|
-
if (w.endsWith('ет') && w.length > 4)
|
|
442
|
-
return w.slice(0, -2);
|
|
443
|
-
if (w.endsWith('ют') && w.length > 4)
|
|
444
|
-
return w.slice(0, -2);
|
|
445
|
-
if (w.endsWith('ут') && w.length > 4)
|
|
446
|
-
return w.slice(0, -2);
|
|
447
|
-
if (w.endsWith('ят') && w.length > 4)
|
|
448
|
-
return w.slice(0, -2);
|
|
449
|
-
return w;
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Turkish light stemmer — strips common agglutinative suffixes.
|
|
453
|
-
* Turkish is highly agglutinative; this covers the most common inflectional ends.
|
|
454
|
-
*
|
|
455
|
-
* Covers:
|
|
456
|
-
* hatalar → hata (-lar/-ler plural)
|
|
457
|
-
* sunucuda → sunucu (-da/-de locative)
|
|
458
|
-
* dağıtımı → dağıtım (-ı/-i/-u/-ü accusative)
|
|
459
|
-
* yüklemek → yükle (-mek/-mak infinitive)
|
|
460
|
-
*/
|
|
461
|
-
function turkishLightStem(word) {
|
|
462
|
-
const w = word;
|
|
463
|
-
// Suffixes longest-first
|
|
464
|
-
if (w.endsWith('lardaki') && w.length > 7)
|
|
465
|
-
return w.slice(0, -7);
|
|
466
|
-
if (w.endsWith('lerdeki') && w.length > 7)
|
|
467
|
-
return w.slice(0, -7);
|
|
468
|
-
if (w.endsWith('ların') && w.length > 6)
|
|
469
|
-
return w.slice(0, -5);
|
|
470
|
-
if (w.endsWith('lerin') && w.length > 6)
|
|
471
|
-
return w.slice(0, -5);
|
|
472
|
-
if (w.endsWith('larda') && w.length > 6)
|
|
473
|
-
return w.slice(0, -5);
|
|
474
|
-
if (w.endsWith('lerde') && w.length > 6)
|
|
475
|
-
return w.slice(0, -5);
|
|
476
|
-
if (w.endsWith('ları') && w.length > 5)
|
|
477
|
-
return w.slice(0, -4);
|
|
478
|
-
if (w.endsWith('leri') && w.length > 5)
|
|
479
|
-
return w.slice(0, -4);
|
|
480
|
-
if (w.endsWith('mek') && w.length > 4)
|
|
481
|
-
return w.slice(0, -3);
|
|
482
|
-
if (w.endsWith('mak') && w.length > 4)
|
|
483
|
-
return w.slice(0, -3);
|
|
484
|
-
if (w.endsWith('ler') && w.length > 4)
|
|
485
|
-
return w.slice(0, -3);
|
|
486
|
-
if (w.endsWith('lar') && w.length > 4)
|
|
487
|
-
return w.slice(0, -3);
|
|
488
|
-
if (w.endsWith('nın') && w.length > 4)
|
|
489
|
-
return w.slice(0, -3);
|
|
490
|
-
if (w.endsWith('nin') && w.length > 4)
|
|
491
|
-
return w.slice(0, -3);
|
|
492
|
-
if (w.endsWith('nun') && w.length > 4)
|
|
493
|
-
return w.slice(0, -3);
|
|
494
|
-
if (w.endsWith('nün') && w.length > 4)
|
|
495
|
-
return w.slice(0, -3);
|
|
496
|
-
if (w.endsWith('da') && w.length > 4)
|
|
497
|
-
return w.slice(0, -2);
|
|
498
|
-
if (w.endsWith('de') && w.length > 4)
|
|
499
|
-
return w.slice(0, -2);
|
|
500
|
-
if (w.endsWith('ta') && w.length > 4)
|
|
501
|
-
return w.slice(0, -2);
|
|
502
|
-
if (w.endsWith('te') && w.length > 4)
|
|
503
|
-
return w.slice(0, -2);
|
|
504
|
-
if (w.endsWith('dan') && w.length > 4)
|
|
505
|
-
return w.slice(0, -3);
|
|
506
|
-
if (w.endsWith('den') && w.length > 4)
|
|
507
|
-
return w.slice(0, -3);
|
|
508
|
-
if (w.endsWith('tan') && w.length > 4)
|
|
509
|
-
return w.slice(0, -3);
|
|
510
|
-
if (w.endsWith('ten') && w.length > 4)
|
|
511
|
-
return w.slice(0, -3);
|
|
512
|
-
if (w.endsWith('ın') && w.length > 4)
|
|
513
|
-
return w.slice(0, -2);
|
|
514
|
-
if (w.endsWith('in') && w.length > 4)
|
|
515
|
-
return w.slice(0, -2);
|
|
516
|
-
if (w.endsWith('un') && w.length > 4)
|
|
517
|
-
return w.slice(0, -2);
|
|
518
|
-
if (w.endsWith('ün') && w.length > 4)
|
|
519
|
-
return w.slice(0, -2);
|
|
520
|
-
if (w.endsWith('ı') && w.length > 4)
|
|
521
|
-
return w.slice(0, -1);
|
|
522
|
-
if (w.endsWith('i') && w.length > 4)
|
|
523
|
-
return w.slice(0, -1);
|
|
524
|
-
if (w.endsWith('u') && w.length > 4)
|
|
525
|
-
return w.slice(0, -1);
|
|
526
|
-
if (w.endsWith('ü') && w.length > 4)
|
|
527
|
-
return w.slice(0, -1);
|
|
528
|
-
return w;
|
|
529
|
-
}
|
|
530
|
-
/**
|
|
531
|
-
* Bengali (Bangla) light stemmer — strips common verbal and nominal suffixes.
|
|
532
|
-
* Bengali is an Indo-Aryan language with moderate morphological complexity.
|
|
533
|
-
* Only strips when result is still ≥ 2 chars.
|
|
534
|
-
*
|
|
535
|
-
* Covers:
|
|
536
|
-
* করছে/করেছে → কর (progressive/perfect aspect)
|
|
537
|
-
* সার্ভারগুলো → সার্ভার (-গুলো plural)
|
|
538
|
-
* সমস্যাটি → সমস্যা (-টি singular marker)
|
|
539
|
-
*/
|
|
540
|
-
function bengaliLightStem(word) {
|
|
541
|
-
const w = word;
|
|
542
|
-
// Plural / collective markers (longest first)
|
|
543
|
-
if (w.endsWith('\u0997\u09c1\u09b2\u09cb') && w.length > 5)
|
|
544
|
-
return w.slice(0, -4); // গুলো (-gulo plural)
|
|
545
|
-
if (w.endsWith('\u0997\u09c1\u09b2\u09bf') && w.length > 5)
|
|
546
|
-
return w.slice(0, -4); // গুলি (-guli plural)
|
|
547
|
-
if (w.endsWith('\u09a6\u09c7\u09b0') && w.length > 4)
|
|
548
|
-
return w.slice(0, -3); // দের (genitive plural)
|
|
549
|
-
if (w.endsWith('\u09a6\u09bf\u0997\u09c7') && w.length > 5)
|
|
550
|
-
return w.slice(0, -4); // দিগে
|
|
551
|
-
// Definiteness / case markers
|
|
552
|
-
if (w.endsWith('\u099f\u09bf') && w.length > 3)
|
|
553
|
-
return w.slice(0, -2); // টি (singular definite)
|
|
554
|
-
if (w.endsWith('\u099f\u09be') && w.length > 3)
|
|
555
|
-
return w.slice(0, -2); // টা (singular definite)
|
|
556
|
-
if (w.endsWith('\u0996\u09be\u09a8\u09be') && w.length > 5)
|
|
557
|
-
return w.slice(0, -4); // খানা
|
|
558
|
-
// Verbal suffixes
|
|
559
|
-
if (w.endsWith('\u099b\u09c7') && w.length > 3)
|
|
560
|
-
return w.slice(0, -2); // ছে (progressive)
|
|
561
|
-
if (w.endsWith('\u099b\u09bf\u09b2') && w.length > 4)
|
|
562
|
-
return w.slice(0, -3); // ছিল (past progressive)
|
|
563
|
-
if (w.endsWith('\u09af\u09be\u09ac\u09c7') && w.length > 5)
|
|
564
|
-
return w.slice(0, -4); // যাবে (future)
|
|
565
|
-
if (w.endsWith('\u0995\u09b0\u09be') && w.length > 4)
|
|
566
|
-
return w.slice(0, -3); // করা (infinitive)
|
|
567
|
-
if (w.endsWith('\u0995\u09b0\u09c7') && w.length > 4)
|
|
568
|
-
return w.slice(0, -3); // করে (present)
|
|
569
|
-
if (w.endsWith('\u09b9\u09df') && w.length > 3)
|
|
570
|
-
return w.slice(0, -2); // হয় (is/becomes)
|
|
571
|
-
if (w.endsWith('\u09b9\u09ac\u09c7') && w.length > 4)
|
|
572
|
-
return w.slice(0, -3); // হবে (will be)
|
|
573
|
-
return w;
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Pre-process text BEFORE tokenization to split code identifiers.
|
|
577
|
-
* Handles camelCase, PascalCase, snake_case, and kebab-case.
|
|
578
|
-
*
|
|
579
|
-
* Examples:
|
|
580
|
-
* deployServer → deploy Server (then lowercased → deploy server)
|
|
581
|
-
* HTMLParser → HTML Parser
|
|
582
|
-
* my_api_key → my api key
|
|
583
|
-
* get-user-by-id → get user by id (hyphens preserved in regex, spaces also fine)
|
|
584
|
-
* BackendServiceImpl → Backend Service Impl
|
|
585
|
-
*/
|
|
586
|
-
function preprocessText(text) {
|
|
587
|
-
return text
|
|
588
|
-
// camelCase boundary: lowercase/digit → uppercase
|
|
589
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
590
|
-
// Consecutive uppercase → uppercase+lowercase boundary: HTMLParser → HTML Parser
|
|
591
|
-
.replace(/([A-Z]{2,})([A-Z][a-z])/g, '$1 $2')
|
|
592
|
-
// snake_case: replace underscores with spaces
|
|
593
|
-
.replace(/_/g, ' ');
|
|
594
|
-
}
|
|
595
|
-
// Maps tokens (English, Japanese katakana, Chinese, Korean, Arabic, Hebrew)
|
|
596
|
-
// to their equivalents in other languages. Used to expand tokens at search time
|
|
597
|
-
// so "deploy" finds documents containing "デプロイ" / "部署" / "배포", and vice versa.
|
|
598
|
-
//
|
|
599
|
-
// Keys must be lowercase. CJK values will be bigram-expanded at use time.
|
|
600
|
-
import { ohneUmlaute, deutscherStamm, ohneRueckumlaut, zerlegeKompositum, DEUTSCHE_FACHWOERTER, } from './deutsch.js';
|
|
601
|
-
const CROSS_LINGUAL_MAP = new Map([
|
|
602
|
-
// ── Tech / Ecosystem synonyms (language-agnostic) ─────────────────────────
|
|
603
|
-
['javascript', ['js', 'node', 'nodejs', 'ecmascript']],
|
|
604
|
-
['js', ['javascript', 'node', 'nodejs']],
|
|
605
|
-
['typescript', ['ts', 'javascript', 'js', 'tsc']],
|
|
606
|
-
['ts', ['typescript', 'javascript', 'js']],
|
|
607
|
-
['python', ['py', 'pip', 'django', 'flask', 'fastapi']],
|
|
608
|
-
['py', ['python', 'pip']],
|
|
609
|
-
['golang', ['go', 'gopher', 'goroutine']],
|
|
610
|
-
['go', ['golang', 'goroutine']],
|
|
611
|
-
['rust', ['cargo', 'rustlang', 'crates']],
|
|
612
|
-
['cargo', ['rust', 'rustlang']],
|
|
613
|
-
['java', ['jvm', 'maven', 'gradle', 'spring']],
|
|
614
|
-
['kotlin', ['jvm', 'android', 'coroutine']],
|
|
615
|
-
['dotnet', ['csharp', 'asp', 'nuget', 'aspnet']],
|
|
616
|
-
['postgresql', ['postgres', 'pg', 'psql']],
|
|
617
|
-
['postgres', ['postgresql', 'pg', 'psql']],
|
|
618
|
-
['mysql', ['mariadb', 'sql']],
|
|
619
|
-
['mongodb', ['mongo', 'nosql', 'bson', 'mongoose']],
|
|
620
|
-
['mongo', ['mongodb', 'nosql', 'bson']],
|
|
621
|
-
['elasticsearch', ['elastic', 'opensearch', 'lucene', 'kibana']],
|
|
622
|
-
['elastic', ['elasticsearch', 'opensearch']],
|
|
623
|
-
['kubernetes', ['k8s', 'kube', 'kubectl', 'helm', 'k3s']],
|
|
624
|
-
['k8s', ['kubernetes', 'kube', 'kubectl', 'helm']],
|
|
625
|
-
['helm', ['kubernetes', 'k8s', 'chart']],
|
|
626
|
-
['terraform', ['tf', 'hcl', 'iac', 'opentofu']],
|
|
627
|
-
['ansible', ['playbook', 'automation']],
|
|
628
|
-
['grafana', ['dashboard', 'visualization', 'metrics']],
|
|
629
|
-
['prometheus', ['metrics', 'alert', 'scrape', 'grafana']],
|
|
630
|
-
['nginx', ['proxy', 'webserver', 'ingress']],
|
|
631
|
-
['traefik', ['proxy', 'ingress', 'router']],
|
|
632
|
-
['rabbitmq', ['amqp', 'queue', 'broker', 'messaging']],
|
|
633
|
-
['kafka', ['messaging', 'stream', 'broker']],
|
|
634
|
-
['grpc', ['protobuf', 'proto', 'rpc']],
|
|
635
|
-
['graphql', ['gql', 'resolver', 'schema']],
|
|
636
|
-
['react', ['jsx', 'hooks', 'component', 'redux']],
|
|
637
|
-
['nextjs', ['next', 'react', 'ssr', 'vercel']],
|
|
638
|
-
['vue', ['vuejs', 'vite', 'nuxt']],
|
|
639
|
-
['angular', ['ng', 'rxjs', 'typescript']],
|
|
640
|
-
['aws', ['amazon', 'ec2', 's3', 'lambda', 'cloudwatch', 'ecs', 'eks']],
|
|
641
|
-
['gcp', ['google cloud', 'gke', 'bigquery']],
|
|
642
|
-
['azure', ['microsoft cloud', 'aks', 'devops']],
|
|
643
|
-
['s3', ['bucket', 'object storage', 'aws']],
|
|
644
|
-
['lambda', ['serverless', 'function', 'faas', 'aws']],
|
|
645
|
-
['jwt', ['token', 'bearer', 'oauth', 'auth']],
|
|
646
|
-
['oauth', ['oidc', 'auth', 'token', 'sso']],
|
|
647
|
-
['webhook', ['callback', 'event', 'trigger']],
|
|
648
|
-
['cron', ['schedule', 'job', 'timer']],
|
|
649
|
-
['yaml', ['yml', 'config', 'manifest']],
|
|
650
|
-
['dotenv', ['env', 'environment', 'envfile']],
|
|
651
|
-
['github', ['git', 'actions', 'repo', 'ci']],
|
|
652
|
-
['gitlab', ['git', 'pipeline', 'runner']],
|
|
653
|
-
['wireguard', ['vpn', 'tunnel', 'wg']],
|
|
654
|
-
['prisma', ['orm', 'database', 'schema', 'migration']],
|
|
655
|
-
['npm', ['node', 'package', 'registry', 'yarn', 'pnpm']],
|
|
656
|
-
['yarn', ['npm', 'package', 'node']],
|
|
657
|
-
['pip', ['python', 'package', 'pypi']],
|
|
658
|
-
['brew', ['homebrew', 'macos', 'package']],
|
|
659
|
-
// English → all
|
|
660
|
-
['deploy', ['デプロイ', '部署', '배포', 'deployment', 'deploying', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellen', 'bereitstellung', 'déployer', 'déploiement', 'desplegar', 'despliegue', 'distribuire', 'distribuzione', 'implantar', 'implantação', 'развёртывание', 'развертывание', 'dağıtım', 'dağıtmak', 'triển khai']],
|
|
661
|
-
['deployment', ['デプロイ', '部署', '배포', 'deploy', 'نشر', 'פריסה', 'استقرار', 'तैनाती', 'bereitstellung', 'déploiement', 'despliegue', 'distribuzione', 'implantação', 'развёртывание', 'dağıtım', 'triển khai']],
|
|
662
|
-
['container', ['コンテナ', '容器', '컨테이너', 'docker']],
|
|
663
|
-
['server', ['サーバー', 'サーバ', '服务器', '서버', 'سيرفر', 'שרת', 'سرور', 'सर्वर', 'сервер', 'sunucu', 'máy chủ']],
|
|
664
|
-
['database', ['データベース', '数据库', '데이터베이스', 'db', 'قاعدة البيانات', 'datenbank', 'پایگاه داده', 'डेटाबेس', 'base de données', 'base de datos', 'banco de dados']],
|
|
665
|
-
['cache', ['キャッシュ', '缓存', '캐시', 'كاش', 'מטמון', 'کش', 'कैश', 'кэш', 'önbellek', 'bộ đệm']],
|
|
666
|
-
['error', ['エラー', '错误', '오류', 'خطأ', 'שגיאה', 'خطا', 'त्रुटि', 'गलती', 'exception', 'err', 'fehler', 'erreur', 'fallo', 'errore', 'erro', 'ошибка', 'hata', 'hatalı', 'lỗi']],
|
|
667
|
-
['bug', ['バグ', '缺陷', '버그', 'issue', 'defect', 'خلل', 'اشکال', 'बग']],
|
|
668
|
-
['fix', ['修正', '修复', '수정', 'bugfix', 'patch', 'hotfix', 'إصلاح', 'תיקון', 'رفع', 'सुधार', 'beheben', 'behoben', 'réparer', 'correction', 'arreglar', 'corrección', 'correggere', 'corrigir', 'исправить', 'исправление', 'düzeltmek', 'düzeltme']],
|
|
669
|
-
['build', ['ビルド', '构建', '빌드', 'بناء', 'בנייה', 'ساخت', 'निर्माण', 'bauen', 'construire', 'construir', 'costruire', 'сборка', 'собрать', 'derleme', 'derlemek']],
|
|
670
|
-
['test', ['テスト', '测试', '테스트', 'اختبار', 'בדיקה', 'آزمایش', 'परीक्षण', 'testen', 'tester', 'probar', 'testare', 'testar', 'тест', 'тестирование', 'test', 'testlemek']],
|
|
671
|
-
['auth', ['認証', '认证', '인증', 'authentication', 'login', 'oauth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', 'authentifizierung', 'authentification', 'autenticación', 'autenticazione', 'autenticação', 'аутентификация', 'авторизация', 'kimlik doğrulama', 'yetkilendirme']],
|
|
672
|
-
['authentication', ['auth', 'مصادقة', 'אימות', 'احراز هویت', 'प्रमाणीकरण', '認証', '认证', '인증', 'login', 'oauth', 'аутентификация', 'авторизация', 'kimlik doğrulama']],
|
|
673
|
-
['environment', ['環境', '环境', '환경', 'env', 'بيئة', 'סביבה', 'umgebung', 'environnement', 'entorno', 'ambiente', 'среда', 'окружение', 'ortam']],
|
|
674
|
-
['secret', ['key', 'token', 'password', 'jwt', 'مفتاح', 'מפתח', 'geheimnis', 'schlüssel', 'clave', 'clé', 'chiave', 'chave', 'секрет', 'ключ', 'gizli', 'anahtar']],
|
|
675
|
-
['problem', ['error', 'issue', 'bug', 'failure', 'مشكلة', '問題', '오류', 'fehler', 'problème', 'problema', 'проблема', 'ошибка', 'sorun', 'problem']],
|
|
676
|
-
['kubernetes', ['クベルネテス', 'k8s', 'kube']],
|
|
677
|
-
['network', ['ネットワーク', '网络', '네트워크', 'شبكة', 'רשת', 'شبکه', 'नेटवर्क', 'netzwerk', 'réseau', 'red', 'rete', 'rede', 'сеть', 'ağ']],
|
|
678
|
-
['timeout', ['タイムアウト', '超时', '타임아웃', 'مهلة']],
|
|
679
|
-
['memory', ['メモリ', '内存', '메모리', 'ram', 'ذاكرة', 'זיכרון', 'حافظه', 'मेमोरी', 'speicher', 'mémoire', 'memoria', 'memória', 'память', 'bellek', 'hafıza']],
|
|
680
|
-
['config', ['設定', '配置', '설정', 'configuration', 'settings', 'conf', 'إعدادات', 'הגדרות', 'پیکربندی', 'कॉन्फ़िग', 'konfiguration', 'einstellungen', 'configuración', 'configurazione', 'configuração', 'конфигурация', 'настройки', 'yapılandırma', 'ayarlar']],
|
|
681
|
-
['install', ['インストール', '安装', '설치', 'تثبيت', 'התקנה', 'نصب', 'इंस्टॉल', 'installieren', 'installer', 'instalar', 'installare', 'установить', 'установка', 'yüklemek', 'kurulum']],
|
|
682
|
-
['update', ['アップデート', '更新', '업데이트', 'upgrade', 'تحديث', 'עדכון', 'بهروزرسانی', 'अपडेट', 'aktualisieren', 'aktualisierung', 'actualizar', 'aggiornare', 'atualizar', 'обновление', 'обновить', 'güncelleme']],
|
|
683
|
-
['log', ['ログ', '日志', '로그', 'logging', 'سجل', 'יומן', 'ثبت', 'लॉग', 'protokoll', 'protokolle', 'journal', 'registro', 'журнал', 'лог', 'günlük']],
|
|
684
|
-
['port', ['ポート', '端口', '포트', 'منفذ', 'פורט']],
|
|
685
|
-
['file', ['ファイル', '文件', '파일', 'ملف', 'קובץ']],
|
|
686
|
-
['image', ['イメージ', '镜像', '이미지', 'صورة', 'תמונה', 'abbild', 'imagen', 'imagem']],
|
|
687
|
-
['volume', ['ボリューム', '卷', '볼륨']],
|
|
688
|
-
['cluster', ['クラスター', '集群', '클러스터']],
|
|
689
|
-
['node', ['ノード', '节点', '노드']],
|
|
690
|
-
['service', ['サービス', '服务', '서비스', 'svc', 'خدمة', 'שירות', 'dienst', 'servicio', 'servizio', 'serviço', 'сервис', 'служба', 'servis', 'hizmet']],
|
|
691
|
-
['certificate', ['証明書', '证书', '인증서', 'cert', 'ssl', 'tls', 'شهادة', 'תעודה']],
|
|
692
|
-
['password', ['パスワード', '密码', '비밀번호', 'passwd', 'pwd', 'كلمة المرور', 'סיסמה']],
|
|
693
|
-
['token', ['トークン', '令牌', '토큰', 'jwt', 'secret', 'رمز', 'אסימון']],
|
|
694
|
-
['health', ['ヘルス', '健康', '헬스', 'healthcheck', 'probe', 'صحة']],
|
|
695
|
-
['migration', ['マイグレーション', '迁移', '마이그레이션', 'migrate', 'هجرة']],
|
|
696
|
-
['backup', ['バックアップ', '备份', '백업', 'نسخ احتياطي', 'גיבוי', 'پشتیبانگیری', 'बैकअप', 'sicherung', 'sauvegarde', 'respaldo', 'cópia de segurança', 'резервная копия', 'резерв', 'yedekleme']],
|
|
697
|
-
['monitor', ['モニター', '监控', '모니터링', 'monitoring', 'metrics', 'alert', 'مراقبة', 'ניטור', 'نظارت', 'निगरानी', 'überwachung', 'surveiller', 'monitoreo', 'monitorare', 'monitorar', 'мониторинг', 'наблюдение', 'izleme']],
|
|
698
|
-
['performance', ['パフォーマンス', '性能', '성능', 'latency', 'throughput', 'عملکرد', 'प्रदर्शन', 'leistung', 'performances', 'rendimiento', 'prestazioni', 'desempenho', 'производительность', 'быстродействие', 'performans']],
|
|
699
|
-
['connection', ['接続', '连接', '연결', 'conn', 'socket', 'اتصال', 'חיבור', 'اتصال', 'कनेक्शन', 'verbindung', 'connexion', 'conexión', 'connessione', 'conexão']],
|
|
700
|
-
['queue', ['キュー', '队列', '큐', 'طابور', 'warteschlange', 'file d\'attente', 'cola', 'coda', 'fila']],
|
|
701
|
-
['redis', ['レディス', '레디스']],
|
|
702
|
-
['nginx', ['エンジンエックス']],
|
|
703
|
-
['linux', ['リナックス', 'لينكس']],
|
|
704
|
-
['api', ['エーピーアイ', '接口', 'endpoint', 'واجهة برمجية', 'ממשק']],
|
|
705
|
-
['healthcheck', ['ヘルスチェック', 'health', 'probe', 'فحص الصحة']],
|
|
706
|
-
['loadbalancer', ['ロードバランサー', '负载均衡', '로드밸런서', 'lb']],
|
|
707
|
-
['ssl', ['tls', 'https', 'certificate', 'cert']],
|
|
708
|
-
['tls', ['ssl', 'https', 'certificate', 'cert']],
|
|
709
|
-
['docker', ['container', 'コンテナ', '容器', '컨테이너', 'دوكر']],
|
|
710
|
-
['git', ['version control', 'repo', 'repository', 'commit', 'push', 'pull']],
|
|
711
|
-
['ci', ['pipeline', 'github actions', 'gitlab', 'jenkins', 'build']],
|
|
712
|
-
['cd', ['deploy', 'deployment', 'release']],
|
|
713
|
-
['debug', ['デバッグ', '调试', '디버그', 'debugging', 'breakpoint', 'تصحيح', 'איתור באגים', 'اشکالزدایی', 'डीबग', 'debuggen', 'déboguer', 'depurar', 'отладка', 'дебаг', 'hata ayıklama']],
|
|
714
|
-
['crash', ['クラッシュ', '崩溃', '크래시', 'panic', 'segfault', 'انهيار', 'קריסה', 'خرابی', 'क्रैश', 'absturz', 'panne', 'plantage', 'caída', 'falha', 'сбой', 'крэш', 'çökme', 'çöküş']],
|
|
715
|
-
['restart', ['再起動', '重启', '재시작', 'reboot', 'إعادة تشغيل', 'הפעלה מחדש', 'راهاندازی مجدد', 'पुنरारंभ', 'neustart', 'redémarrer', 'reiniciar', 'riavviare']],
|
|
716
|
-
['permission', ['権限', '权限', '권한', 'access', 'acl', 'chmod', 'صلاحية', 'הרשאה', 'مجوز', 'अनुमति', 'berechtigung', 'berechtigungen', 'permiso', 'permesso', 'permissão', 'разрешение', 'доступ', 'izin', 'yetki']],
|
|
717
|
-
// Japanese katakana → English
|
|
718
|
-
['デプロイ', ['deploy', 'deployment']],
|
|
719
|
-
['コンテナ', ['container', 'docker']],
|
|
720
|
-
['サーバー', ['server']],
|
|
721
|
-
['サーバ', ['server']],
|
|
722
|
-
['データベース', ['database', 'db']],
|
|
723
|
-
['キャッシュ', ['cache']],
|
|
724
|
-
['エラー', ['error', 'err']],
|
|
725
|
-
['バグ', ['bug', 'issue']],
|
|
726
|
-
['ビルド', ['build']],
|
|
727
|
-
['テスト', ['test']],
|
|
728
|
-
['認証', ['auth', 'authentication']],
|
|
729
|
-
['設定', ['config', 'configuration']],
|
|
730
|
-
['インストール', ['install']],
|
|
731
|
-
['アップデート', ['update', 'upgrade']],
|
|
732
|
-
['ログ', ['log', 'logs']],
|
|
733
|
-
['ポート', ['port']],
|
|
734
|
-
['ファイル', ['file']],
|
|
735
|
-
['イメージ', ['image']],
|
|
736
|
-
['クラスター', ['cluster']],
|
|
737
|
-
['ノード', ['node']],
|
|
738
|
-
['サービス', ['service']],
|
|
739
|
-
['パスワード', ['password']],
|
|
740
|
-
['トークン', ['token']],
|
|
741
|
-
['バックアップ', ['backup']],
|
|
742
|
-
['モニター', ['monitor', 'monitoring']],
|
|
743
|
-
['接続', ['connection']],
|
|
744
|
-
['キュー', ['queue']],
|
|
745
|
-
['ヘルスチェック', ['healthcheck', 'health check', 'health']],
|
|
746
|
-
['ロードバランサー', ['loadbalancer', 'load balancer']],
|
|
747
|
-
['デバッグ', ['debug']],
|
|
748
|
-
['クラッシュ', ['crash', 'panic']],
|
|
749
|
-
['再起動', ['restart', 'reboot']],
|
|
750
|
-
['権限', ['permission', 'access']],
|
|
751
|
-
// Chinese → English
|
|
752
|
-
['部署', ['deploy', 'deployment']],
|
|
753
|
-
['容器', ['container', 'docker']],
|
|
754
|
-
['服务器', ['server']],
|
|
755
|
-
['数据库', ['database']],
|
|
756
|
-
['缓存', ['cache']],
|
|
757
|
-
['错误', ['error']],
|
|
758
|
-
['修复', ['fix', 'bugfix']],
|
|
759
|
-
['构建', ['build']],
|
|
760
|
-
['测试', ['test']],
|
|
761
|
-
['认证', ['auth']],
|
|
762
|
-
['配置', ['config']],
|
|
763
|
-
['安装', ['install']],
|
|
764
|
-
['更新', ['update']],
|
|
765
|
-
['日志', ['log']],
|
|
766
|
-
['端口', ['port']],
|
|
767
|
-
['镜像', ['image']],
|
|
768
|
-
['集群', ['cluster']],
|
|
769
|
-
['节点', ['node']],
|
|
770
|
-
['服务', ['service']],
|
|
771
|
-
['密码', ['password']],
|
|
772
|
-
['令牌', ['token']],
|
|
773
|
-
['备份', ['backup']],
|
|
774
|
-
['监控', ['monitor']],
|
|
775
|
-
['连接', ['connection']],
|
|
776
|
-
['队列', ['queue']],
|
|
777
|
-
['性能', ['performance']],
|
|
778
|
-
['内存', ['memory']],
|
|
779
|
-
['调试', ['debug']],
|
|
780
|
-
['崩溃', ['crash']],
|
|
781
|
-
['重启', ['restart']],
|
|
782
|
-
['权限', ['permission']],
|
|
783
|
-
// Korean → English
|
|
784
|
-
['배포', ['deploy', 'deployment']],
|
|
785
|
-
['컨테이너', ['container']],
|
|
786
|
-
['서버', ['server']],
|
|
787
|
-
['데이터베이스', ['database']],
|
|
788
|
-
['캐시', ['cache']],
|
|
789
|
-
['오류', ['error']],
|
|
790
|
-
['수정', ['fix']],
|
|
791
|
-
['빌드', ['build']],
|
|
792
|
-
['테스트', ['test']],
|
|
793
|
-
['인증', ['auth']],
|
|
794
|
-
['설정', ['config']],
|
|
795
|
-
['설치', ['install']],
|
|
796
|
-
['업데이트', ['update']],
|
|
797
|
-
['로그', ['log']],
|
|
798
|
-
['포트', ['port']],
|
|
799
|
-
['이미지', ['image']],
|
|
800
|
-
['클러스터', ['cluster']],
|
|
801
|
-
['노드', ['node']],
|
|
802
|
-
['서비스', ['service']],
|
|
803
|
-
['토큰', ['token']],
|
|
804
|
-
['백업', ['backup']],
|
|
805
|
-
['모니터링', ['monitor']],
|
|
806
|
-
['연결', ['connection']],
|
|
807
|
-
['큐', ['queue']],
|
|
808
|
-
['성능', ['performance']],
|
|
809
|
-
['메모리', ['memory']],
|
|
810
|
-
['디버그', ['debug']],
|
|
811
|
-
['크래시', ['crash']],
|
|
812
|
-
['재시작', ['restart']],
|
|
813
|
-
['권한', ['permission']],
|
|
814
|
-
// Arabic → English
|
|
815
|
-
['خطأ', ['error']],
|
|
816
|
-
['إصلاح', ['fix']],
|
|
817
|
-
['بناء', ['build']],
|
|
818
|
-
['اختبار', ['test']],
|
|
819
|
-
['مصادقة', ['auth', 'authentication']],
|
|
820
|
-
['إعدادات', ['config', 'configuration']],
|
|
821
|
-
['تثبيت', ['install']],
|
|
822
|
-
['تحديث', ['update', 'upgrade']],
|
|
823
|
-
['سجل', ['log']],
|
|
824
|
-
['صورة', ['image']],
|
|
825
|
-
['خدمة', ['service']],
|
|
826
|
-
['نسخ احتياطي', ['backup']],
|
|
827
|
-
['مراقبة', ['monitor', 'monitoring']],
|
|
828
|
-
['اتصال', ['connection']],
|
|
829
|
-
['ذاكرة', ['memory']],
|
|
830
|
-
['تصحيح', ['debug', 'debugging']],
|
|
831
|
-
['شبكة', ['network']],
|
|
832
|
-
// Additional Arabic → English (covering blog post examples + common terms)
|
|
833
|
-
['نشر', ['deploy', 'deployment']],
|
|
834
|
-
['انهيار', ['crash', 'panic']],
|
|
835
|
-
['طابور', ['queue']],
|
|
836
|
-
['رمز', ['token', 'secret']],
|
|
837
|
-
['كاش', ['cache']],
|
|
838
|
-
['منفذ', ['port']],
|
|
839
|
-
['سيرفر', ['server']],
|
|
840
|
-
['قاعدة البيانات', ['database', 'db']],
|
|
841
|
-
['إعادة تشغيل', ['restart', 'reboot']],
|
|
842
|
-
['صلاحية', ['permission', 'access']],
|
|
843
|
-
['تطبيق', ['application', 'app']],
|
|
844
|
-
['مفتاح', ['key', 'token', 'secret']],
|
|
845
|
-
['واجهة برمجية', ['api', 'interface']],
|
|
846
|
-
['فحص الصحة', ['healthcheck', 'health']],
|
|
847
|
-
['حاوية', ['container', 'docker']],
|
|
848
|
-
['عقدة', ['node']],
|
|
849
|
-
['سرعة', ['performance', 'speed']],
|
|
850
|
-
['قرص', ['disk', 'storage']],
|
|
851
|
-
['خادم', ['server']],
|
|
852
|
-
['برنامج', ['application', 'software', 'app']],
|
|
853
|
-
// Arabic terms from blog examples
|
|
854
|
-
['مشكلة', ['error', 'issue', 'bug', 'problem', 'failure']],
|
|
855
|
-
['بيئة', ['environment', 'env']],
|
|
856
|
-
['متغيرات', ['variables', 'env', 'environment']],
|
|
857
|
-
['إنتاج', ['production', 'prod']],
|
|
858
|
-
['سري', ['secret', 'key', 'token']],
|
|
859
|
-
['مفتاح سري', ['secret', 'key']],
|
|
860
|
-
// Hebrew → English
|
|
861
|
-
['שגיאה', ['error']],
|
|
862
|
-
['תיקון', ['fix']],
|
|
863
|
-
['בנייה', ['build']],
|
|
864
|
-
['בדיקה', ['test']],
|
|
865
|
-
['אימות', ['auth', 'authentication']],
|
|
866
|
-
['הגדרות', ['config', 'configuration']],
|
|
867
|
-
['התקנה', ['install']],
|
|
868
|
-
['עדכון', ['update', 'upgrade']],
|
|
869
|
-
['יומן', ['log']],
|
|
870
|
-
['שרת', ['server']],
|
|
871
|
-
['שירות', ['service']],
|
|
872
|
-
['גיבוי', ['backup']],
|
|
873
|
-
['ניטור', ['monitor', 'monitoring']],
|
|
874
|
-
['חיבור', ['connection']],
|
|
875
|
-
['זיכרון', ['memory']],
|
|
876
|
-
['רשת', ['network']],
|
|
877
|
-
['תמונה', ['image']],
|
|
878
|
-
['סיסמה', ['password']],
|
|
879
|
-
['הרשאה', ['permission', 'access']],
|
|
880
|
-
// Additional Hebrew → English (covering blog post examples + common terms)
|
|
881
|
-
['קריסה', ['crash', 'panic']],
|
|
882
|
-
['תור', ['queue']],
|
|
883
|
-
['מטמון', ['cache']],
|
|
884
|
-
['אסימון', ['token', 'secret']],
|
|
885
|
-
['פורט', ['port']],
|
|
886
|
-
['איתור באגים', ['debug', 'debugging']],
|
|
887
|
-
['הפעלה מחדש', ['restart', 'reboot']],
|
|
888
|
-
['מיכל', ['container', 'docker']],
|
|
889
|
-
['יישום', ['application', 'app']],
|
|
890
|
-
['מפתח', ['key', 'token', 'secret']],
|
|
891
|
-
['בדיקת תקינות', ['healthcheck', 'health']],
|
|
892
|
-
['ממשק תכנות', ['api', 'interface']],
|
|
893
|
-
['ביצועים', ['performance']],
|
|
894
|
-
['אחסון', ['storage', 'disk']],
|
|
895
|
-
// Hebrew terms from blog examples
|
|
896
|
-
['פריסה', ['deploy', 'deployment']],
|
|
897
|
-
['בעיה', ['error', 'issue', 'bug', 'problem']],
|
|
898
|
-
['סביבה', ['environment', 'env']],
|
|
899
|
-
['ייצור', ['production', 'prod']],
|
|
900
|
-
['סודי', ['secret', 'key', 'token']],
|
|
901
|
-
['מפתח סודי', ['secret', 'key']],
|
|
902
|
-
// ── Farsi/Persian → English ───────────────────────────────────────────────
|
|
903
|
-
['استقرار', ['deploy', 'deployment']],
|
|
904
|
-
['خطا', ['error', 'err']], // Farsi: خطا vs Arabic: خطأ
|
|
905
|
-
['اشکال', ['bug', 'issue', 'error']],
|
|
906
|
-
['رفع اشکال', ['fix', 'debug', 'debugging']],
|
|
907
|
-
['ساخت', ['build']],
|
|
908
|
-
['آزمایش', ['test']],
|
|
909
|
-
['احراز هویت', ['auth', 'authentication']],
|
|
910
|
-
['پیکربندی', ['config', 'configuration']],
|
|
911
|
-
['نصب', ['install']],
|
|
912
|
-
['بهروزرسانی', ['update', 'upgrade']],
|
|
913
|
-
['ثبت', ['log']],
|
|
914
|
-
['سرور', ['server']],
|
|
915
|
-
['پایگاه داده', ['database', 'db']],
|
|
916
|
-
['شبکه', ['network']], // Farsi شبکه vs Arabic شبكة
|
|
917
|
-
['حافظه', ['memory', 'ram']], // Farsi حافظه vs Arabic ذاكرة
|
|
918
|
-
['کش', ['cache']],
|
|
919
|
-
['اشکالزدایی', ['debug', 'debugging']],
|
|
920
|
-
['خرابی', ['crash', 'failure', 'error']],
|
|
921
|
-
['راهاندازی مجدد', ['restart', 'reboot']],
|
|
922
|
-
['مجوز', ['permission', 'access']],
|
|
923
|
-
['پشتیبانگیری', ['backup']],
|
|
924
|
-
['عملکرد', ['performance']],
|
|
925
|
-
['مشکل', ['problem', 'issue', 'error']],
|
|
926
|
-
['سرویس', ['service']],
|
|
927
|
-
['کلید', ['key', 'token', 'secret']],
|
|
928
|
-
['محیط', ['environment', 'env']],
|
|
929
|
-
['تولید', ['production', 'prod']],
|
|
930
|
-
['رمز', ['secret', 'key', 'token']],
|
|
931
|
-
['اتصال', ['connection', 'conn']],
|
|
932
|
-
// ── Hindi (Devanagari) → English ──────────────────────────────────────────
|
|
933
|
-
['तैनाती', ['deploy', 'deployment']],
|
|
934
|
-
['तैना', ['deploy', 'deployment']], // stemmed form
|
|
935
|
-
['त्रुटि', ['error', 'err']],
|
|
936
|
-
['गलती', ['error', 'bug', 'issue']],
|
|
937
|
-
['सुधार', ['fix', 'bugfix']],
|
|
938
|
-
['निर्माण', ['build']],
|
|
939
|
-
['परीक्षण', ['test']],
|
|
940
|
-
['प्रमाणीकरण', ['auth', 'authentication']],
|
|
941
|
-
['विन्यास', ['config', 'configuration']],
|
|
942
|
-
['कॉन्फ़िगरेशन', ['config', 'configuration']],
|
|
943
|
-
['इंस्टॉल', ['install']],
|
|
944
|
-
['अपडेट', ['update', 'upgrade']],
|
|
945
|
-
['लॉग', ['log']],
|
|
946
|
-
['सर्वर', ['server']],
|
|
947
|
-
['डेटाबेस', ['database', 'db']],
|
|
948
|
-
['नेटवर्क', ['network']],
|
|
949
|
-
['मेमोरी', ['memory', 'ram']],
|
|
950
|
-
['कैश', ['cache']],
|
|
951
|
-
['डीबग', ['debug', 'debugging']],
|
|
952
|
-
['क्रैश', ['crash', 'panic']],
|
|
953
|
-
['पुनरारंभ', ['restart', 'reboot']],
|
|
954
|
-
['अनुमति', ['permission', 'access']],
|
|
955
|
-
['बैकअप', ['backup']],
|
|
956
|
-
['प्रदर्शन', ['performance']],
|
|
957
|
-
['समस्या', ['problem', 'issue', 'error']],
|
|
958
|
-
['सेवा', ['service']],
|
|
959
|
-
['कनेक्शन', ['connection', 'conn']],
|
|
960
|
-
['पासवर्ड', ['password']],
|
|
961
|
-
['टोकन', ['token', 'secret']],
|
|
962
|
-
['वातावरण', ['environment', 'env']],
|
|
963
|
-
['उत्पादन', ['production', 'prod']],
|
|
964
|
-
// ── European languages → English ─────────────────────────────────────────
|
|
965
|
-
// German (Deutsch) → English
|
|
966
|
-
['fehler', ['error', 'err']],
|
|
967
|
-
['absturz', ['crash', 'panic']],
|
|
968
|
-
['bug', ['bug', 'issue']], // same word, keep for completeness
|
|
969
|
-
['beheben', ['fix', 'bugfix']],
|
|
970
|
-
['behoben', ['fix', 'fixed']],
|
|
971
|
-
['lösung', ['solution', 'fix']],
|
|
972
|
-
['bauen', ['build']],
|
|
973
|
-
['testen', ['test']],
|
|
974
|
-
['authentifizierung', ['auth', 'authentication']],
|
|
975
|
-
['konfiguration', ['config', 'configuration']],
|
|
976
|
-
['einstellungen', ['config', 'settings']],
|
|
977
|
-
['installieren', ['install']],
|
|
978
|
-
['installiert', ['install', 'installed']],
|
|
979
|
-
['aktualisieren', ['update', 'upgrade']],
|
|
980
|
-
['aktualisierung', ['update', 'upgrade']],
|
|
981
|
-
['protokoll', ['log']],
|
|
982
|
-
['protokolle', ['log', 'logs']],
|
|
983
|
-
['abbild', ['image']],
|
|
984
|
-
['knoten', ['node']],
|
|
985
|
-
['dienst', ['service']],
|
|
986
|
-
['sicherung', ['backup']],
|
|
987
|
-
['überwachung', ['monitor', 'monitoring']],
|
|
988
|
-
['verbindung', ['connection', 'conn']],
|
|
989
|
-
['warteschlange', ['queue']],
|
|
990
|
-
['leistung', ['performance']],
|
|
991
|
-
['speicher', ['memory', 'storage']],
|
|
992
|
-
['debuggen', ['debug', 'debugging']],
|
|
993
|
-
['neustart', ['restart', 'reboot']],
|
|
994
|
-
['berechtigung', ['permission', 'access']],
|
|
995
|
-
['berechtigungen', ['permission', 'access', 'acl']],
|
|
996
|
-
['netzwerk', ['network']],
|
|
997
|
-
['datenbank', ['database', 'db']],
|
|
998
|
-
['bereitstellen', ['deploy', 'deployment']],
|
|
999
|
-
['bereitstellung', ['deploy', 'deployment']],
|
|
1000
|
-
// 'container' and 'server' are the same in German/French/Spanish/Italian/Portuguese
|
|
1001
|
-
['kaputt', ['broken', 'error', 'crash']],
|
|
1002
|
-
['funktioniert', ['works', 'working']],
|
|
1003
|
-
['geht nicht', ['not working', 'broken', 'error']],
|
|
1004
|
-
['schlüssel', ['key', 'token', 'secret']],
|
|
1005
|
-
['zertifikat', ['certificate', 'cert', 'ssl', 'tls']],
|
|
1006
|
-
['umgebung', ['environment', 'env']],
|
|
1007
|
-
['variablen', ['variables', 'env', 'environment']],
|
|
1008
|
-
['aufgabe', ['task', 'job']],
|
|
1009
|
-
['wartung', ['maintenance']],
|
|
1010
|
-
['speicherleck', ['memory leak', 'memory']],
|
|
1011
|
-
['schnittstelle', ['interface', 'api']],
|
|
1012
|
-
// French (Français) → English
|
|
1013
|
-
['erreur', ['error', 'err']],
|
|
1014
|
-
['réparer', ['fix']],
|
|
1015
|
-
['correction', ['fix', 'bugfix']],
|
|
1016
|
-
['construire', ['build']],
|
|
1017
|
-
['tester', ['test']],
|
|
1018
|
-
['authentification', ['auth', 'authentication']],
|
|
1019
|
-
['configuration', ['config', 'configuration']],
|
|
1020
|
-
['installer', ['install']],
|
|
1021
|
-
['installation', ['install']],
|
|
1022
|
-
['mettre', ['update', 'upgrade']],
|
|
1023
|
-
['journal', ['log', 'logs']],
|
|
1024
|
-
['nœud', ['node']],
|
|
1025
|
-
['sauvegarde', ['backup']],
|
|
1026
|
-
['surveiller', ['monitor', 'monitoring']],
|
|
1027
|
-
['connexion', ['connection']],
|
|
1028
|
-
['mémoire', ['memory']],
|
|
1029
|
-
['déboguer', ['debug']],
|
|
1030
|
-
['redémarrer', ['restart', 'reboot']],
|
|
1031
|
-
['réseau', ['network']],
|
|
1032
|
-
['base de données', ['database', 'db']],
|
|
1033
|
-
['déployer', ['deploy']],
|
|
1034
|
-
['déploiement', ['deploy', 'deployment']],
|
|
1035
|
-
['clé', ['key', 'token']],
|
|
1036
|
-
['certificat', ['certificate', 'cert', 'ssl']],
|
|
1037
|
-
['environnement', ['environment', 'env']],
|
|
1038
|
-
['panne', ['crash', 'outage', 'failure']],
|
|
1039
|
-
['plantage', ['crash', 'panic']],
|
|
1040
|
-
['interface', ['interface', 'api']],
|
|
1041
|
-
['performances', ['performance']],
|
|
1042
|
-
['stockage', ['storage', 'disk']],
|
|
1043
|
-
['file attente', ['queue']],
|
|
1044
|
-
// Spanish (Español) → English
|
|
1045
|
-
['arreglar', ['fix']],
|
|
1046
|
-
['corrección', ['fix', 'bugfix']],
|
|
1047
|
-
['construir', ['build']],
|
|
1048
|
-
['probar', ['test']],
|
|
1049
|
-
['autenticación', ['auth', 'authentication']],
|
|
1050
|
-
['configuración', ['config', 'configuration']],
|
|
1051
|
-
['instalar', ['install']],
|
|
1052
|
-
['actualizar', ['update', 'upgrade']],
|
|
1053
|
-
['actualización', ['update', 'upgrade']],
|
|
1054
|
-
['registro', ['log', 'registry']],
|
|
1055
|
-
['nodo', ['node']],
|
|
1056
|
-
['servicio', ['service']],
|
|
1057
|
-
['contraseña', ['password']],
|
|
1058
|
-
['copia de seguridad', ['backup']],
|
|
1059
|
-
['respaldo', ['backup']],
|
|
1060
|
-
['monitorear', ['monitor']],
|
|
1061
|
-
['monitoreo', ['monitoring']],
|
|
1062
|
-
['conexión', ['connection']],
|
|
1063
|
-
['rendimiento', ['performance']],
|
|
1064
|
-
['memoria', ['memory']],
|
|
1065
|
-
['depurar', ['debug']],
|
|
1066
|
-
['fallo', ['crash', 'failure', 'error']],
|
|
1067
|
-
['caída', ['crash', 'outage']],
|
|
1068
|
-
['reiniciar', ['restart', 'reboot']],
|
|
1069
|
-
['permiso', ['permission']],
|
|
1070
|
-
['permisos', ['permission', 'access']],
|
|
1071
|
-
['red', ['network']],
|
|
1072
|
-
['base de datos', ['database', 'db']],
|
|
1073
|
-
['desplegar', ['deploy']],
|
|
1074
|
-
['despliegue', ['deploy', 'deployment']],
|
|
1075
|
-
['clave', ['key', 'token', 'secret']],
|
|
1076
|
-
['certificado', ['certificate', 'cert', 'ssl']],
|
|
1077
|
-
['entorno', ['environment', 'env']],
|
|
1078
|
-
['cola', ['queue']],
|
|
1079
|
-
['interfaz', ['interface', 'api']],
|
|
1080
|
-
['imagen', ['image']],
|
|
1081
|
-
// Italian (Italiano) → English
|
|
1082
|
-
['errore', ['error', 'err']],
|
|
1083
|
-
['correggere', ['fix']],
|
|
1084
|
-
['costruire', ['build']],
|
|
1085
|
-
['testare', ['test']],
|
|
1086
|
-
['autenticazione', ['auth', 'authentication']],
|
|
1087
|
-
['configurazione', ['config', 'configuration']],
|
|
1088
|
-
['installare', ['install']],
|
|
1089
|
-
['aggiornare', ['update', 'upgrade']],
|
|
1090
|
-
['aggiornamento', ['update', 'upgrade']],
|
|
1091
|
-
['registro', ['log']],
|
|
1092
|
-
['nodo', ['node']],
|
|
1093
|
-
['servizio', ['service']],
|
|
1094
|
-
['password', ['password']],
|
|
1095
|
-
['backup', ['backup']],
|
|
1096
|
-
['monitorare', ['monitor']],
|
|
1097
|
-
['connessione', ['connection']],
|
|
1098
|
-
['prestazioni', ['performance']],
|
|
1099
|
-
['memoria', ['memory']],
|
|
1100
|
-
['debug', ['debug']],
|
|
1101
|
-
['arresto anomalo', ['crash']],
|
|
1102
|
-
['riavviare', ['restart']],
|
|
1103
|
-
['permesso', ['permission']],
|
|
1104
|
-
['rete', ['network']],
|
|
1105
|
-
['database', ['database', 'db']],
|
|
1106
|
-
['distribuire', ['deploy']],
|
|
1107
|
-
['distribuzione', ['deploy', 'deployment']],
|
|
1108
|
-
['chiave', ['key', 'token', 'secret']],
|
|
1109
|
-
['certificato', ['certificate', 'cert']],
|
|
1110
|
-
['ambiente', ['environment', 'env']],
|
|
1111
|
-
['coda', ['queue']],
|
|
1112
|
-
['immagine', ['image']],
|
|
1113
|
-
// Portuguese (Português) → English
|
|
1114
|
-
['erro', ['error', 'err']],
|
|
1115
|
-
['corrigir', ['fix']],
|
|
1116
|
-
['construir', ['build']],
|
|
1117
|
-
['testar', ['test']],
|
|
1118
|
-
['autenticação', ['auth', 'authentication']],
|
|
1119
|
-
['configuração', ['config', 'configuration']],
|
|
1120
|
-
['instalar', ['install']],
|
|
1121
|
-
['atualizar', ['update', 'upgrade']],
|
|
1122
|
-
['atualização', ['update', 'upgrade']],
|
|
1123
|
-
['registro', ['log']],
|
|
1124
|
-
['nó', ['node']],
|
|
1125
|
-
['serviço', ['service']],
|
|
1126
|
-
['senha', ['password']],
|
|
1127
|
-
['cópia de segurança', ['backup']],
|
|
1128
|
-
['monitorar', ['monitor']],
|
|
1129
|
-
['conexão', ['connection']],
|
|
1130
|
-
['desempenho', ['performance']],
|
|
1131
|
-
['memória', ['memory']],
|
|
1132
|
-
['depurar', ['debug']],
|
|
1133
|
-
['falha', ['crash', 'failure', 'error']],
|
|
1134
|
-
['reiniciar', ['restart']],
|
|
1135
|
-
['permissão', ['permission']],
|
|
1136
|
-
['rede', ['network']],
|
|
1137
|
-
['banco de dados', ['database', 'db']],
|
|
1138
|
-
['implantar', ['deploy']],
|
|
1139
|
-
['implantação', ['deploy', 'deployment']],
|
|
1140
|
-
['chave', ['key', 'token', 'secret']],
|
|
1141
|
-
['certificado', ['certificate', 'cert']],
|
|
1142
|
-
['ambiente', ['environment', 'env']],
|
|
1143
|
-
['fila', ['queue']],
|
|
1144
|
-
['imagem', ['image']],
|
|
1145
|
-
// ── Russian (Cyrillic) → English ──────────────────────────────────────────
|
|
1146
|
-
['ошибка', ['error', 'err']],
|
|
1147
|
-
['ошибки', ['error', 'err']],
|
|
1148
|
-
['сбой', ['crash', 'failure', 'error']],
|
|
1149
|
-
['крэш', ['crash', 'panic']],
|
|
1150
|
-
['баг', ['bug', 'issue']],
|
|
1151
|
-
['исправить', ['fix', 'bugfix']],
|
|
1152
|
-
['исправление', ['fix', 'patch']],
|
|
1153
|
-
['сборка', ['build']],
|
|
1154
|
-
['собрать', ['build']],
|
|
1155
|
-
['тест', ['test']],
|
|
1156
|
-
['тестирование', ['test', 'testing']],
|
|
1157
|
-
['аутентификация', ['auth', 'authentication']],
|
|
1158
|
-
['авторизация', ['auth', 'authorization']],
|
|
1159
|
-
['конфигурация', ['config', 'configuration']],
|
|
1160
|
-
['настройки', ['config', 'settings']],
|
|
1161
|
-
['установить', ['install']],
|
|
1162
|
-
['установка', ['install']],
|
|
1163
|
-
['обновление', ['update', 'upgrade']],
|
|
1164
|
-
['обновить', ['update', 'upgrade']],
|
|
1165
|
-
['журнал', ['log']],
|
|
1166
|
-
['лог', ['log', 'logs']],
|
|
1167
|
-
['сервер', ['server']],
|
|
1168
|
-
['база данных', ['database', 'db']],
|
|
1169
|
-
['сеть', ['network']],
|
|
1170
|
-
['память', ['memory', 'ram']],
|
|
1171
|
-
['кэш', ['cache']],
|
|
1172
|
-
['отладка', ['debug', 'debugging']],
|
|
1173
|
-
['перезапуск', ['restart', 'reboot']],
|
|
1174
|
-
['перезагрузка', ['restart', 'reboot']],
|
|
1175
|
-
['разрешение', ['permission', 'access']],
|
|
1176
|
-
['доступ', ['permission', 'access']],
|
|
1177
|
-
['резерв', ['backup']],
|
|
1178
|
-
['производительность', ['performance']],
|
|
1179
|
-
['проблема', ['problem', 'issue', 'error']],
|
|
1180
|
-
['сервис', ['service']],
|
|
1181
|
-
['служба', ['service']],
|
|
1182
|
-
['подключение', ['connection', 'conn']],
|
|
1183
|
-
['соединение', ['connection', 'conn']],
|
|
1184
|
-
['развёртывание', ['deploy', 'deployment']],
|
|
1185
|
-
['развертывание', ['deploy', 'deployment']],
|
|
1186
|
-
['развёрт', ['deploy', 'deployment']], // stemmed form
|
|
1187
|
-
['разверт', ['deploy', 'deployment']], // stemmed form
|
|
1188
|
-
['контейнер', ['container', 'docker']],
|
|
1189
|
-
['образ', ['image']],
|
|
1190
|
-
['кластер', ['cluster']],
|
|
1191
|
-
['узел', ['node']],
|
|
1192
|
-
['секрет', ['secret', 'key', 'token']],
|
|
1193
|
-
['ключ', ['key', 'token', 'secret']],
|
|
1194
|
-
['пароль', ['password']],
|
|
1195
|
-
['токен', ['token', 'secret']],
|
|
1196
|
-
['мониторинг', ['monitor', 'monitoring']],
|
|
1197
|
-
['наблюдение', ['monitor', 'monitoring']],
|
|
1198
|
-
['мигрировать', ['migrate', 'migration']],
|
|
1199
|
-
['миграция', ['migrate', 'migration']],
|
|
1200
|
-
// ── Turkish (Latin + special chars ğ/ş/ı) → English ─────────────────────
|
|
1201
|
-
['hata', ['error', 'err']],
|
|
1202
|
-
['hatalı', ['error', 'err']],
|
|
1203
|
-
['çökme', ['crash', 'panic']],
|
|
1204
|
-
['çöküş', ['crash', 'failure']],
|
|
1205
|
-
['düzeltmek', ['fix', 'bugfix']],
|
|
1206
|
-
['düzeltme', ['fix', 'patch']],
|
|
1207
|
-
['derleme', ['build']],
|
|
1208
|
-
['derlemek', ['build']],
|
|
1209
|
-
['test', ['test']],
|
|
1210
|
-
['testlemek', ['test', 'testing']],
|
|
1211
|
-
['kimlik doğrulama', ['auth', 'authentication']],
|
|
1212
|
-
['yetkilendirme', ['auth', 'authorization']],
|
|
1213
|
-
['yapılandırma', ['config', 'configuration']],
|
|
1214
|
-
['ayarlar', ['config', 'settings']],
|
|
1215
|
-
['yüklemek', ['install']],
|
|
1216
|
-
['kurulum', ['install']],
|
|
1217
|
-
['güncelleme', ['update', 'upgrade']],
|
|
1218
|
-
['günlük', ['log']],
|
|
1219
|
-
['sunucu', ['server']],
|
|
1220
|
-
['veritabanı', ['database', 'db']],
|
|
1221
|
-
['ağ', ['network']],
|
|
1222
|
-
['bellek', ['memory', 'ram']],
|
|
1223
|
-
['önbellek', ['cache']],
|
|
1224
|
-
['hata ayıklama', ['debug', 'debugging']],
|
|
1225
|
-
['yeniden başlatma', ['restart', 'reboot']],
|
|
1226
|
-
['izin', ['permission', 'access']],
|
|
1227
|
-
['yetki', ['permission', 'access', 'acl']],
|
|
1228
|
-
['yedekleme', ['backup']],
|
|
1229
|
-
['performans', ['performance']],
|
|
1230
|
-
['sorun', ['problem', 'issue', 'error']],
|
|
1231
|
-
['servis', ['service']],
|
|
1232
|
-
['hizmet', ['service']],
|
|
1233
|
-
['bağlantı', ['connection', 'conn']],
|
|
1234
|
-
['dağıtım', ['deploy', 'deployment']],
|
|
1235
|
-
['dağıtmak', ['deploy']],
|
|
1236
|
-
['konteyner', ['container', 'docker']],
|
|
1237
|
-
['küme', ['cluster']],
|
|
1238
|
-
['düğüm', ['node']],
|
|
1239
|
-
['gizli', ['secret', 'key']],
|
|
1240
|
-
['anahtar', ['key', 'token', 'secret']],
|
|
1241
|
-
['şifre', ['password']],
|
|
1242
|
-
['izleme', ['monitor', 'monitoring']],
|
|
1243
|
-
['göç', ['migrate', 'migration']],
|
|
1244
|
-
// ── Vietnamese (Latin + Latin Extended Additional U+1EA0–U+1EF9) → English ─
|
|
1245
|
-
['triển khai', ['deploy', 'deployment']],
|
|
1246
|
-
['triển', ['deploy', 'deployment']], // split token form
|
|
1247
|
-
['lỗi', ['error', 'err']],
|
|
1248
|
-
['sửa lỗi', ['fix', 'bugfix', 'debug']],
|
|
1249
|
-
['xây dựng', ['build']],
|
|
1250
|
-
['kiểm tra', ['test']],
|
|
1251
|
-
['xác thực', ['auth', 'authentication']],
|
|
1252
|
-
['cấu hình', ['config', 'configuration']],
|
|
1253
|
-
['cài đặt', ['install']],
|
|
1254
|
-
['cập nhật', ['update', 'upgrade']],
|
|
1255
|
-
['nhật ký', ['log']],
|
|
1256
|
-
['máy chủ', ['server']],
|
|
1257
|
-
['cơ sở dữ liệu', ['database', 'db']],
|
|
1258
|
-
['mạng', ['network']],
|
|
1259
|
-
['bộ nhớ', ['memory', 'ram']],
|
|
1260
|
-
['bộ đệm', ['cache']],
|
|
1261
|
-
['gỡ lỗi', ['debug', 'debugging']],
|
|
1262
|
-
['sự cố', ['crash', 'failure', 'error']],
|
|
1263
|
-
['khởi động lại', ['restart', 'reboot']],
|
|
1264
|
-
['quyền', ['permission', 'access']],
|
|
1265
|
-
['sao lưu', ['backup']],
|
|
1266
|
-
['hiệu suất', ['performance']],
|
|
1267
|
-
['vấn đề', ['problem', 'issue', 'error']],
|
|
1268
|
-
['dịch vụ', ['service']],
|
|
1269
|
-
['kết nối', ['connection', 'conn']],
|
|
1270
|
-
['vùng chứa', ['container', 'docker']],
|
|
1271
|
-
['nút', ['node']],
|
|
1272
|
-
['khóa', ['key', 'token', 'secret']],
|
|
1273
|
-
['mật khẩu', ['password']],
|
|
1274
|
-
['giám sát', ['monitor', 'monitoring']],
|
|
1275
|
-
['di chuyển', ['migrate', 'migration']],
|
|
1276
|
-
]);
|
|
1277
|
-
/**
|
|
1278
|
-
* Expand a token to its cross-lingual synonyms.
|
|
1279
|
-
* Returns synonyms to be added to the token stream (pre-tokenized).
|
|
1280
|
-
* CJK synonyms are NOT pre-bigram'd here — caller handles that.
|
|
1281
|
-
*/
|
|
1282
|
-
/**
|
|
1283
|
-
* Die deutschen Eintraege werden NACH dem Aufbau der Haupttabelle ergaenzt und
|
|
1284
|
-
* dabei umlautfrei geschrieben.
|
|
1285
|
-
*
|
|
1286
|
-
* Warum umlautfrei: die vorhandenen deutschen Eintraege standen mit echten
|
|
1287
|
-
* Umlauten (`loesung` als `lösung`), waehrend Lektionen und Fragen oft `ae/oe/ue`
|
|
1288
|
-
* tippen. Damit fand `ueberwachung` den Eintrag `überwachung` nie — zwei
|
|
1289
|
-
* Schreibweisen desselben Wortes, und die Suche hielt sie fuer verschieden.
|
|
1290
|
-
* Gemessen am 19.08.2026.
|
|
1291
|
-
*
|
|
1292
|
-
* Der bestehende Schluessel bleibt stehen; es kommt nur die umlautfreie Form
|
|
1293
|
-
* dazu. Wer `überwachung` tippt, wird beim Zerlegen ohnehin auf `ueberwachung`
|
|
1294
|
-
* gebracht.
|
|
1295
|
-
*/
|
|
1296
|
-
for (const [wort, synonyme] of CROSS_LINGUAL_MAP) {
|
|
1297
|
-
const ohne = ohneUmlaute(wort);
|
|
1298
|
-
if (ohne !== wort && !CROSS_LINGUAL_MAP.has(ohne))
|
|
1299
|
-
CROSS_LINGUAL_MAP.set(ohne, synonyme);
|
|
1300
|
-
}
|
|
1301
|
-
for (const [wort, synonyme] of DEUTSCHE_FACHWOERTER) {
|
|
1302
|
-
const vorhanden = CROSS_LINGUAL_MAP.get(wort);
|
|
1303
|
-
CROSS_LINGUAL_MAP.set(wort, vorhanden ? [...new Set([...vorhanden, ...synonyme])] : [...synonyme]);
|
|
1304
|
-
}
|
|
1305
|
-
/**
|
|
1306
|
-
* Grundwoerter fuer die Zerlegung zusammengesetzter Woerter.
|
|
1307
|
-
*
|
|
1308
|
-
* Es ist die Wortliste selbst — bewusst KEINE zweite Liste. Wer ein Wortpaar
|
|
1309
|
-
* eintraegt, macht es damit auch als Grundwort verfuegbar. Eine Wahrheit an
|
|
1310
|
-
* zwei Orten zu pflegen ist die Fehlerklasse, die uns hier am haeufigsten
|
|
1311
|
-
* trifft.
|
|
1312
|
-
*/
|
|
1313
|
-
const GRUNDWOERTER = new Set([...CROSS_LINGUAL_MAP.keys()].filter(k => k.length >= 4 && /^[a-z]+$/.test(ohneUmlaute(k))).map(ohneUmlaute));
|
|
1314
|
-
function expandCrossLingual(token) {
|
|
1315
|
-
const direkt = CROSS_LINGUAL_MAP.get(token);
|
|
1316
|
-
if (direkt)
|
|
1317
|
-
return direkt;
|
|
1318
|
-
// Umlautfreie Schreibweise probieren, bevor aufgegeben wird.
|
|
1319
|
-
const ohne = ohneUmlaute(token);
|
|
1320
|
-
return ohne !== token ? (CROSS_LINGUAL_MAP.get(ohne) ?? []) : [];
|
|
1321
|
-
}
|
|
1322
|
-
/**
|
|
1323
|
-
* Tokenize text into meaningful keywords.
|
|
1324
|
-
* Handles accented Latin, RTL (Arabic, Hebrew), and CJK (Chinese, Japanese, Korean).
|
|
1325
|
-
*
|
|
1326
|
-
* Features:
|
|
1327
|
-
* • CJK → character bigrams
|
|
1328
|
-
* • Katakana → additionally emits Hepburn romaji tokens (enables romaji queries)
|
|
1329
|
-
* • Arabic → word tokenization + iterative prefix stemming (ال/و/ب/ل/ف/ك)
|
|
1330
|
-
* • Hebrew → word tokenization + iterative prefix stemming (ה/ו/ב/ל/מ/כ)
|
|
1331
|
-
* • Farsi → word tokenization + suffix/prefix stemming (ها/های plural, می prefix)
|
|
1332
|
-
* • Hindi → Devanagari word tokenization + light suffix stemming
|
|
1333
|
-
* • All scripts → cross-lingual synonym expansion (EN↔JA↔ZH↔KO↔AR↔HE↔FA↔HI↔DE↔FR↔ES↔IT↔PT)
|
|
1334
|
-
*/
|
|
1335
|
-
/**
|
|
1336
|
-
* Tokenize text for BM25 indexing or query expansion.
|
|
1337
|
-
*
|
|
1338
|
-
* @param text - The text to tokenize
|
|
1339
|
-
* @param options.crossLingualExpand - When true (default), adds cross-lingual synonym
|
|
1340
|
-
* tokens for every base token. Set to false when indexing DOCUMENTS so that
|
|
1341
|
-
* English documents don't get indexed with all Arabic/Japanese/etc. synonyms of
|
|
1342
|
-
* every word they contain — that inflates BM25 scores catastrophically when a query
|
|
1343
|
-
* also expands the same term. Query tokenization keeps expansion enabled so a
|
|
1344
|
-
* Japanese query still finds English documents (query "デプロイ" → expands to "deploy").
|
|
1345
|
-
*/
|
|
1346
|
-
function tokenize(text, options) {
|
|
1347
|
-
const doCrossLingualExpand = options?.crossLingualExpand ?? true;
|
|
1348
|
-
const tokens = [];
|
|
1349
|
-
// Pre-process: split camelCase/PascalCase identifiers and snake_case before lowercasing
|
|
1350
|
-
const lower = preprocessText(text).toLowerCase();
|
|
1351
|
-
for (const [seg] of lower.matchAll(SEGMENT_RE)) {
|
|
1352
|
-
if (CJK_RE.test(seg)) {
|
|
1353
|
-
// CJK segment — extract overlapping character bigrams
|
|
1354
|
-
for (let i = 0; i < seg.length - 1; i++) {
|
|
1355
|
-
const bigram = seg[i] + seg[i + 1];
|
|
1356
|
-
if (!STOPWORDS.has(seg[i]) && !STOPWORDS.has(bigram)) {
|
|
1357
|
-
tokens.push(bigram);
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
// Trailing single character (for 1-char CJK terms)
|
|
1361
|
-
if (seg.length >= 1) {
|
|
1362
|
-
const last = seg[seg.length - 1];
|
|
1363
|
-
if (!STOPWORDS.has(last))
|
|
1364
|
-
tokens.push(last);
|
|
1365
|
-
}
|
|
1366
|
-
// Whole-segment cross-lingual lookup (for known tech terms like デプロイ, 部署, 배포)
|
|
1367
|
-
// This ensures CJK full-words map to their English equivalents
|
|
1368
|
-
const segSyns = expandCrossLingual(seg);
|
|
1369
|
-
for (const syn of segSyns) {
|
|
1370
|
-
if (!CJK_RE.test(syn)) {
|
|
1371
|
-
syn.split(/\s+/).filter(w => w.length > 1 && !STOPWORDS.has(w)).forEach(w => tokens.push(w));
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
// Romanization: extract katakana-only portion and emit romaji tokens.
|
|
1375
|
-
// This allows users to search "kontena" or "depuroi" to find katakana docs.
|
|
1376
|
-
const kataOnly = seg.replace(/[^\u30a0-\u30ff]/g, '');
|
|
1377
|
-
if (kataOnly.length >= 2) {
|
|
1378
|
-
const romaji = katakanaToRomaji(kataOnly);
|
|
1379
|
-
if (romaji.length >= 2 && romaji.length <= 40 && !STOPWORDS.has(romaji)) {
|
|
1380
|
-
tokens.push(romaji);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
else if (RTL_RE.test(seg)) {
|
|
1385
|
-
// RTL segment — 3-way branch: Farsi / Hebrew / Arabic
|
|
1386
|
-
const words = seg.trim().split(/\s+/);
|
|
1387
|
-
let stemFn;
|
|
1388
|
-
if (FARSI_CHAR_RE.test(seg))
|
|
1389
|
-
stemFn = farsiLightStem;
|
|
1390
|
-
else if (HEBREW_CHAR_RE.test(seg))
|
|
1391
|
-
stemFn = hebrewLightStem;
|
|
1392
|
-
else
|
|
1393
|
-
stemFn = arabicLightStem;
|
|
1394
|
-
for (const w of words) {
|
|
1395
|
-
if (w.length <= 1 || STOPWORDS.has(w))
|
|
1396
|
-
continue;
|
|
1397
|
-
const stemmed = stemFn(w);
|
|
1398
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1399
|
-
tokens.push(stemmed);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
else if (DEVANAGARI_RE.test(seg)) {
|
|
1403
|
-
// Devanagari segment (Hindi / Marathi) — naturally space-separated
|
|
1404
|
-
const words = seg.trim().split(/[\s\u200c\u200d]+/); // handle zero-width joiners
|
|
1405
|
-
for (const w of words) {
|
|
1406
|
-
const deva = w.replace(/[^\u0900-\u097f0-9]/g, '');
|
|
1407
|
-
if (deva.length <= 1 || STOPWORDS.has(deva))
|
|
1408
|
-
continue;
|
|
1409
|
-
const stemmed = hindiLightStem(deva);
|
|
1410
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1411
|
-
tokens.push(stemmed);
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
else if (BENGALI_RE.test(seg)) {
|
|
1415
|
-
// Bengali (Bangla) segment — space-separated words, Bengali script
|
|
1416
|
-
const words = seg.trim().split(/[\s\u200c\u200d]+/);
|
|
1417
|
-
for (const w of words) {
|
|
1418
|
-
const bn = w.replace(/[^\u0980-\u09ff0-9]/g, '');
|
|
1419
|
-
if (bn.length <= 1 || STOPWORDS.has(bn))
|
|
1420
|
-
continue;
|
|
1421
|
-
const stemmed = bengaliLightStem(bn);
|
|
1422
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1423
|
-
tokens.push(stemmed);
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
else if (CYRILLIC_RE.test(seg)) {
|
|
1427
|
-
// Cyrillic segment (Russian, Bulgarian, Ukrainian, Serbian …)
|
|
1428
|
-
const words = seg.trim().split(/\s+/);
|
|
1429
|
-
for (const w of words) {
|
|
1430
|
-
const cyr = w.replace(/[^\u0400-\u04ff]/g, '');
|
|
1431
|
-
if (cyr.length <= 1 || STOPWORDS.has(cyr))
|
|
1432
|
-
continue;
|
|
1433
|
-
const stemmed = russianLightStem(cyr);
|
|
1434
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1435
|
-
tokens.push(stemmed);
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
else {
|
|
1439
|
-
// Latin / other — includes Turkish (ğ/ş/ı), Polish (ą/ę/ł/ń/ó/ś/ź/ż/ć),
|
|
1440
|
-
// Czech (č/š/ž/ě/ů/ř), Hungarian (ő/ű), Romanian (ș/ț), Vietnamese (ắặầổợụừ…)
|
|
1441
|
-
const words = seg
|
|
1442
|
-
.replace(/[^a-záàâãäåæçéèêëíìîïñóòôõöúùûüýÿßœğşıİąćęłńśźżčšžěůřőűșț\u1ea0-\u1ef90-9:\-./]/g, ' ')
|
|
1443
|
-
.split(/\s+/)
|
|
1444
|
-
.filter(w => w.length > 1 && !STOPWORDS.has(w));
|
|
1445
|
-
// Turkish: apply light stemmer to words with Turkish-specific chars
|
|
1446
|
-
for (const w of words) {
|
|
1447
|
-
if (TURKISH_CHAR_RE.test(w)) {
|
|
1448
|
-
const stemmed = turkishLightStem(w);
|
|
1449
|
-
if (stemmed !== w && stemmed.length > 1 && !STOPWORDS.has(stemmed)) {
|
|
1450
|
-
tokens.push(stemmed);
|
|
1451
|
-
}
|
|
1452
|
-
}
|
|
1453
|
-
tokens.push(w);
|
|
1454
|
-
// ── Deutsch ──────────────────────────────────────────────────────────
|
|
1455
|
-
//
|
|
1456
|
-
// Drei Schritte, alle am 19.08.2026 an echten Fragen belegt. Fuer
|
|
1457
|
-
// sieben Sprachen gab es hier einen Stemmer, fuer Deutsch nicht.
|
|
1458
|
-
//
|
|
1459
|
-
// Wichtig: alles wird ZUSAETZLICH ausgegeben, nie ersetzend. Das
|
|
1460
|
-
// Originalwort bleibt der staerkste Treffer; die Ableitungen sind
|
|
1461
|
-
// Bruecken, keine Umleitungen.
|
|
1462
|
-
// 1. Umlaute vereinheitlichen. `Loesung` und `Lösung` sind dasselbe
|
|
1463
|
-
// Wort — vorher waren es zwei.
|
|
1464
|
-
const ohneU = ohneUmlaute(w);
|
|
1465
|
-
if (ohneU !== w && !STOPWORDS.has(ohneU))
|
|
1466
|
-
tokens.push(ohneU);
|
|
1467
|
-
// 2. Wortform. `Abhaengigkeiten` und `Abhaengigkeit` sollen sich
|
|
1468
|
-
// finden.
|
|
1469
|
-
const stamm = deutscherStamm(w);
|
|
1470
|
-
if (stamm !== w && stamm !== ohneU && stamm.length > 3 && !STOPWORDS.has(stamm)) {
|
|
1471
|
-
tokens.push(stamm);
|
|
1472
|
-
// Rueckumlautung: `Eintraege` -> `eintraeg` -> `eintrag`.
|
|
1473
|
-
const zurueck = ohneRueckumlaut(stamm);
|
|
1474
|
-
if (zurueck && zurueck.length > 3 && !STOPWORDS.has(zurueck))
|
|
1475
|
-
tokens.push(zurueck);
|
|
1476
|
-
}
|
|
1477
|
-
// 3. Zusammengesetzte Woerter. Die deutsche Besonderheit und die
|
|
1478
|
-
// groesste Luecke: `Arbeitsspeicher` enthaelt `speicher`, und
|
|
1479
|
-
// `speicher` stand laengst in der Wortliste — nur kam niemand
|
|
1480
|
-
// dort an.
|
|
1481
|
-
if (ohneU.length >= 10) {
|
|
1482
|
-
for (const teil of zerlegeKompositum(ohneU, GRUNDWOERTER)) {
|
|
1483
|
-
if (!STOPWORDS.has(teil))
|
|
1484
|
-
tokens.push(teil);
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
// ── Cross-lingual expansion (query mode only) ────────────────────────────
|
|
1491
|
-
// Only run when tokenizing queries. Skipped for documents to prevent the
|
|
1492
|
-
// symmetric-expansion inflation bug: if both query and document expand "error"
|
|
1493
|
-
// to 28 synonyms, BM25 counts all 28 as exact matches — a single common word
|
|
1494
|
-
// inflates any document's score 28×, burying topic-specific matches.
|
|
1495
|
-
if (!doCrossLingualExpand)
|
|
1496
|
-
return tokens;
|
|
1497
|
-
// For each token, look up synonyms in other languages and add them.
|
|
1498
|
-
// CJK synonyms are bigram-expanded inline; Latin/RTL synonyms added as-is.
|
|
1499
|
-
const expansions = [];
|
|
1500
|
-
const seen = new Set(tokens);
|
|
1501
|
-
for (const tok of tokens) {
|
|
1502
|
-
const syns = expandCrossLingual(tok);
|
|
1503
|
-
for (const syn of syns) {
|
|
1504
|
-
if (seen.has(syn))
|
|
1505
|
-
continue;
|
|
1506
|
-
seen.add(syn);
|
|
1507
|
-
if (CJK_RE.test(syn)) {
|
|
1508
|
-
// CJK synonym → expand to character bigrams
|
|
1509
|
-
for (let i = 0; i < syn.length - 1; i++) {
|
|
1510
|
-
const bg = syn[i] + syn[i + 1];
|
|
1511
|
-
if (!STOPWORDS.has(syn[i]) && !STOPWORDS.has(bg))
|
|
1512
|
-
expansions.push(bg);
|
|
1513
|
-
}
|
|
1514
|
-
if (syn.length >= 1) {
|
|
1515
|
-
const last = syn[syn.length - 1];
|
|
1516
|
-
if (!STOPWORDS.has(last))
|
|
1517
|
-
expansions.push(last);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
else if (RTL_RE.test(syn)) {
|
|
1521
|
-
// RTL synonym — apply correct stemmer per language
|
|
1522
|
-
const rtlStem = FARSI_CHAR_RE.test(syn) ? farsiLightStem
|
|
1523
|
-
: HEBREW_CHAR_RE.test(syn) ? hebrewLightStem
|
|
1524
|
-
: arabicLightStem;
|
|
1525
|
-
const stemmed = rtlStem(syn);
|
|
1526
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1527
|
-
expansions.push(stemmed);
|
|
1528
|
-
}
|
|
1529
|
-
else if (DEVANAGARI_RE.test(syn)) {
|
|
1530
|
-
// Devanagari synonym (Hindi)
|
|
1531
|
-
const stemmed = hindiLightStem(syn);
|
|
1532
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1533
|
-
expansions.push(stemmed);
|
|
1534
|
-
}
|
|
1535
|
-
else if (BENGALI_RE.test(syn)) {
|
|
1536
|
-
// Bengali synonym
|
|
1537
|
-
const stemmed = bengaliLightStem(syn);
|
|
1538
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1539
|
-
expansions.push(stemmed);
|
|
1540
|
-
}
|
|
1541
|
-
else if (CYRILLIC_RE.test(syn)) {
|
|
1542
|
-
// Cyrillic synonym (Russian)
|
|
1543
|
-
const cyr = syn.replace(/[^\u0400-\u04ff]/g, '');
|
|
1544
|
-
const stemmed = russianLightStem(cyr);
|
|
1545
|
-
if (stemmed.length > 1 && !STOPWORDS.has(stemmed))
|
|
1546
|
-
expansions.push(stemmed);
|
|
1547
|
-
}
|
|
1548
|
-
else {
|
|
1549
|
-
// Latin synonym (includes Turkish) — split in case of multi-word
|
|
1550
|
-
const parts = syn.split(/\s+/).filter(w => {
|
|
1551
|
-
if (w.length <= 1 || STOPWORDS.has(w))
|
|
1552
|
-
return false;
|
|
1553
|
-
return true;
|
|
1554
|
-
});
|
|
1555
|
-
for (const p of parts) {
|
|
1556
|
-
expansions.push(p);
|
|
1557
|
-
// Apply Turkish stemmer if it has Turkish-specific characters
|
|
1558
|
-
if (TURKISH_CHAR_RE.test(p)) {
|
|
1559
|
-
const stemmed = turkishLightStem(p);
|
|
1560
|
-
if (stemmed !== p && stemmed.length > 1 && !STOPWORDS.has(stemmed)) {
|
|
1561
|
-
expansions.push(stemmed);
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
}
|
|
1568
|
-
tokens.push(...expansions);
|
|
1569
|
-
return tokens;
|
|
1570
|
-
}
|
|
1571
|
-
/**
|
|
1572
|
-
* Split a multi-topic query into sub-queries.
|
|
1573
|
-
* Detects numbered lists, semicolons, "and also", line breaks, etc.
|
|
1574
|
-
*
|
|
1575
|
-
* Example: "deploy API fix routing and also check auth" →
|
|
1576
|
-
* ["deploy API fix routing", "check auth"]
|
|
1577
|
-
*
|
|
1578
|
-
* Example: "1. deploy 2. fix routing 3. auth" →
|
|
1579
|
-
* ["deploy", "fix routing", "auth"]
|
|
1580
|
-
*/
|
|
1581
|
-
function splitMultiQuery(query) {
|
|
1582
|
-
// Numbered list: "1. foo 2. bar 3. baz"
|
|
1583
|
-
const numberedParts = query.split(/\d+[.)]\s*/g).filter(s => s.trim().length > 2);
|
|
1584
|
-
if (numberedParts.length >= 2)
|
|
1585
|
-
return numberedParts.map(s => s.trim());
|
|
1586
|
-
// Semicolons or newlines
|
|
1587
|
-
const semiParts = query.split(/[;\n]+/).filter(s => s.trim().length > 2);
|
|
1588
|
-
if (semiParts.length >= 2)
|
|
1589
|
-
return semiParts.map(s => s.trim());
|
|
1590
|
-
// Conjunctions (EN + DE + FR + ES + IT + PT + RU + TR)
|
|
1591
|
-
const conjParts = query.split(/\b(?:and also|also noch|außerdem|plus|additionally|furthermore|de plus|además|inoltre|além disso|а также|и также|кроме того|плюс|ayrıca|bunun yanı sıra|همچنین|وأيضاً|وكذلك|وهمچنین|और भी|इसके अलावा)\b/i).filter(s => s.trim().length > 2);
|
|
1592
|
-
if (conjParts.length >= 2)
|
|
1593
|
-
return conjParts.map(s => s.trim());
|
|
1594
|
-
// Comma-separated with 3+ parts (likely a list)
|
|
1595
|
-
const commaParts = query.split(/,\s*/).filter(s => s.trim().length > 2);
|
|
1596
|
-
if (commaParts.length >= 3)
|
|
1597
|
-
return commaParts.map(s => s.trim());
|
|
1598
|
-
// Single query
|
|
1599
|
-
return [query];
|
|
1600
|
-
}
|
|
1601
|
-
// ── BM25+ Scoring ─────────────────────────────────────────────────────────────
|
|
1602
|
-
//
|
|
1603
|
-
// BM25+ fixes the "long document under-scoring" bug in classic BM25.
|
|
1604
|
-
// Paper: Lv & Zhai (2011) "Lower-Bounding Term Frequency Normalization"
|
|
1605
|
-
//
|
|
1606
|
-
// Improvements over standard BM25:
|
|
1607
|
-
// 1. δ=1 additive term → guarantees TF>0 terms always contribute positively
|
|
1608
|
-
// 2. Bigram proximity boost → adjacent query terms in doc get 2× weight
|
|
1609
|
-
// 3. Recency boost → entries with timestamps get exp-decay bonus (7d half-life)
|
|
1610
|
-
// 4. Levenshtein fuzzy match → typo-tolerant (distance ≤ 2)
|
|
1611
|
-
//
|
|
1612
|
-
/** BM25+ parameters */
|
|
1613
|
-
const BM25_K1 = 1.2; // term frequency saturation
|
|
1614
|
-
const BM25_B = 0.75; // length normalization
|
|
1615
|
-
// BM25+ gibt jedem gefundenen Wort einen Sockelbetrag, damit lange Dokumente
|
|
1616
|
-
// nicht ganz durchfallen. Bei 1.0 belohnte das Breite statt Genauigkeit: ein
|
|
1617
|
-
// Datensatz, der zehn allgemeine Woerter traf, schlug einen, der zwei genaue
|
|
1618
|
-
// traf. Gemessen 19.08.2026 an 498 Lektionen — Median-Platz 101 bei 1.0,
|
|
1619
|
-
// 95 bei 0.25, 77 bei 0.
|
|
1620
|
-
const BM25_DELTA = 0.25;
|
|
1621
|
-
// Wie stark Frische die Rangfolge bewegen darf: ±5 Prozent. Begruendung und
|
|
1622
|
-
// Messreihe stehen bei recencyBoost().
|
|
1623
|
-
const RECENCY_SPANNE = 0.05;
|
|
1624
|
-
// Wie stark ein von uns ergaenztes Synonym zaehlt, verglichen mit einem Wort,
|
|
1625
|
-
// das der Mensch getippt hat.
|
|
1626
|
-
//
|
|
1627
|
-
// Gemessen 19.08.2026 an 499 Lektionen mit 100 Fragen:
|
|
1628
|
-
//
|
|
1629
|
-
// Gewicht Platz 1 Top 3 Median
|
|
1630
|
-
// 1.0 20 31 14
|
|
1631
|
-
// 0.5 21 33 12
|
|
1632
|
-
// 0.35 22 31 13
|
|
1633
|
-
//
|
|
1634
|
-
// 0.5 ist auf drei von vier Massen vorn. Der Unterschied ist EINE Frage — das
|
|
1635
|
-
// ist kein Beleg, sondern eine Richtung. Wer hier dreht, misst nach.
|
|
1636
|
-
const SYNONYM_GEWICHT = 0.5;
|
|
1637
|
-
// Wie viele vorhandene Woerter je Fragewort als unscharfer Treffer infrage
|
|
1638
|
-
// kommen. Messreihe steht bei fuzzyKandidaten().
|
|
1639
|
-
const FUZZY_KANDIDATEN = 64;
|
|
1640
|
-
/** Recency boost: half-life in days. Entry from 7 days ago gets 0.5× boost. */
|
|
1641
|
-
const RECENCY_HALF_LIFE_DAYS = 7;
|
|
1642
|
-
const ZERO_RESULTS_LOG = [];
|
|
1643
|
-
const ZERO_RESULTS_MAX = 500;
|
|
1644
|
-
let zeroResultsTotal = 0;
|
|
1645
|
-
function logZeroResult(query) {
|
|
1646
|
-
zeroResultsTotal++;
|
|
1647
|
-
if (ZERO_RESULTS_LOG.length >= ZERO_RESULTS_MAX)
|
|
1648
|
-
ZERO_RESULTS_LOG.shift();
|
|
1649
|
-
ZERO_RESULTS_LOG.push({ query, ts: Date.now() });
|
|
1650
|
-
}
|
|
1651
|
-
/** Global index vocabulary — rebuilt on each keywordSearch call from the doc set. */
|
|
1652
|
-
let _indexVocab = new Set();
|
|
1653
|
-
/**
|
|
1654
|
-
* Levenshtein distance — edit distance between two strings.
|
|
1655
|
-
* Used for typo-tolerant fuzzy matching (distance ≤ 2 = match).
|
|
1656
|
-
* O(n*m) but strings are short (tokens), so this is fast.
|
|
1657
|
-
*/
|
|
1658
|
-
function levenshtein(a, b) {
|
|
1659
|
-
if (a === b)
|
|
1660
|
-
return 0;
|
|
1661
|
-
if (a.length === 0)
|
|
1662
|
-
return b.length;
|
|
1663
|
-
if (b.length === 0)
|
|
1664
|
-
return a.length;
|
|
1665
|
-
// Skip if length diff > 2 (can't be ≤ 2 edits)
|
|
1666
|
-
if (Math.abs(a.length - b.length) > 2)
|
|
1667
|
-
return 3;
|
|
1668
|
-
const prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
1669
|
-
for (let i = 1; i <= a.length; i++) {
|
|
1670
|
-
let corner = i - 1;
|
|
1671
|
-
prev[0] = i;
|
|
1672
|
-
for (let j = 1; j <= b.length; j++) {
|
|
1673
|
-
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
1674
|
-
const cur = Math.min(prev[j] + 1, prev[j - 1] + 1, corner + cost);
|
|
1675
|
-
corner = prev[j];
|
|
1676
|
-
prev[j] = cur;
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
return prev[b.length];
|
|
1680
|
-
}
|
|
1681
|
-
/** Extract a timestamp from JSON content (looks for "ts" or "created" fields). */
|
|
1682
|
-
function extractTimestamp(content) {
|
|
1683
|
-
// Fast regex for ISO dates in JSON: "ts":"2026-04-17T..." or "created":"..."
|
|
1684
|
-
const match = content.match(/"(?:ts|created|created_at|timestamp)"\s*:\s*"([^"]+)"/);
|
|
1685
|
-
if (match) {
|
|
1686
|
-
const ms = Date.parse(match[1]);
|
|
1687
|
-
if (!isNaN(ms))
|
|
1688
|
-
return ms;
|
|
1689
|
-
}
|
|
1690
|
-
return undefined;
|
|
1691
|
-
}
|
|
1692
|
-
/** Recency multiplier: 1.0 for now, 0.5 after half-life days, exponential decay. */
|
|
1693
|
-
// The GENTLE, ranking-only age curve — deliberately NOT the sharp staleness
|
|
1694
|
-
// curve in confidence.ts (calculateConfidence). Ranking must nudge, not punish:
|
|
1695
|
-
// a 7-day half-life bounded to [0.5,1.5] keeps a still-relevant older lesson in
|
|
1696
|
-
// contention. This is bench-tuned; swapping in the sharp confidence curve here
|
|
1697
|
-
// regressed every Cachly-Bench floor and was reverted (PR #228). If you touch
|
|
1698
|
-
// this, run `npm run bench:gate` — the rerank.test.ts guard alone is too loose.
|
|
1699
|
-
/**
|
|
1700
|
-
* Frische als STICHENTSCHEID, nicht als Treiber.
|
|
1701
|
-
*
|
|
1702
|
-
* ── Was hier schiefging, und wie lange ──────────────────────────────────────
|
|
1703
|
-
*
|
|
1704
|
-
* Bis zum 19.08.2026 lag der Bereich bei [0.5, 1.5]. Eine ganz frische Lektion
|
|
1705
|
-
* bekam damit das DREIFACHE einer 79 Tage alten — unabhaengig davon, wie gut
|
|
1706
|
-
* sie zur Frage passt. Bei einem Bestand, in dem viele Datensaetze aehnlich
|
|
1707
|
-
* mittelmaessig passen, entscheidet ein solcher Faktor die Rangfolge allein.
|
|
1708
|
-
*
|
|
1709
|
-
* Gemessen an 498 echten Lektionen mit 20 Fragen. Nur diesen Bereich zu
|
|
1710
|
-
* verschmaelern, sonst nichts:
|
|
1711
|
-
*
|
|
1712
|
-
* Bereich auf Platz 1 Median-Platz
|
|
1713
|
-
* [0.5, 1.5] 1/20 101
|
|
1714
|
-
* [0.75, 1.25] 2/20 53
|
|
1715
|
-
* [0.9, 1.1] 3/20 39
|
|
1716
|
-
* [0.95, 1.05] 5/20 36
|
|
1717
|
-
* ohne Frische 6/20 29
|
|
1718
|
-
*
|
|
1719
|
-
* ── Warum trotzdem nicht ganz weg ───────────────────────────────────────────
|
|
1720
|
-
*
|
|
1721
|
-
* Weil Lektionen einander korrigieren. kanzlei:coach-timeout-root-cause traegt
|
|
1722
|
-
* woertlich "korrigiert eine frueher falsch gespeicherte Lesson". Ohne jede
|
|
1723
|
-
* Frische gewinnt bei gleichwertigem Text die falsche alte Fassung, und zwar
|
|
1724
|
-
* fuer immer.
|
|
1725
|
-
*
|
|
1726
|
-
* ±5 Prozent heisst in der Praxis: die Reihenfolge aendert sich nur zwischen
|
|
1727
|
-
* Datensaetzen, die ohnehin fast gleich gut passen. Genau das soll ein
|
|
1728
|
-
* Stichentscheid tun.
|
|
1729
|
-
*
|
|
1730
|
-
* Ohne Frische mass sich um EINE Frage besser. Bei 20 Fragen ist das kein
|
|
1731
|
-
* Unterschied, auf den man eine Entscheidung stuetzt.
|
|
1732
|
-
*
|
|
1733
|
-
* ── Warum es Monate unentdeckt blieb ────────────────────────────────────────
|
|
1734
|
-
*
|
|
1735
|
-
* Der Fixture-Bench hat 17 Lektionen, mit Zeitstempeln und fast derselben
|
|
1736
|
-
* Altersspanne (2,7x gegen 3,0x). Am fehlenden Zeitstempel lag es also NICHT.
|
|
1737
|
-
* Es lag an der Menge: bei 16 Mitbewerbern gewinnt der Textabgleich auch gegen
|
|
1738
|
-
* den Faktor 3, weil ein seltenes Wort rund zehnmal so schwer wiegt wie ein
|
|
1739
|
-
* haeufiges. Bei 497 Mitbewerbern gibt es genug Datensaetze mit aehnlichem
|
|
1740
|
-
* Textwert — und dann entscheidet der Faktor.
|
|
1741
|
-
*
|
|
1742
|
-
* Ein Fehler, der erst ab einer gewissen Menge auftritt, ist auf einem kleinen
|
|
1743
|
-
* Pruefstand unsichtbar. Nicht schwer zu finden. Unsichtbar.
|
|
1744
|
-
*/
|
|
1745
|
-
function recencyBoost(timestampMs) {
|
|
1746
|
-
if (!timestampMs)
|
|
1747
|
-
return 1.0;
|
|
1748
|
-
const ageDays = (Date.now() - timestampMs) / (1000 * 60 * 60 * 24);
|
|
1749
|
-
const frisch = ageDays <= 0 ? 1 : Math.pow(0.5, ageDays / RECENCY_HALF_LIFE_DAYS);
|
|
1750
|
-
return 1 - RECENCY_SPANNE + 2 * RECENCY_SPANNE * frisch;
|
|
1751
|
-
}
|
|
1752
|
-
const WORTBESTAND_FRISCHE_MS = 60_000;
|
|
1753
|
-
/**
|
|
1754
|
-
* Ein Bestand JE VERBINDUNG, nicht je Muster.
|
|
1755
|
-
*
|
|
1756
|
-
* Der erste Entwurf benannte den Zwischenspeicher nur nach dem Suchmuster.
|
|
1757
|
-
* Das war falsch, und zwei Tests haben es sofort gezeigt: derselbe
|
|
1758
|
-
* MCP-Prozess bedient MEHRERE Instanzen (`getConnection(instance_id)`), und
|
|
1759
|
-
* `cachly:lesson:best:*` heisst in jeder davon etwas anderes. Ein Bestand nur
|
|
1760
|
-
* nach Muster haette die Lektionen der einen Kanzlei an die naechste
|
|
1761
|
-
* ausgeliefert.
|
|
1762
|
-
*
|
|
1763
|
-
* Deshalb eine WeakMap auf das Verbindungsobjekt: geht die Verbindung, geht
|
|
1764
|
-
* der Bestand mit — ohne dass ihn jemand aufraeumen muesste.
|
|
1765
|
-
*/
|
|
1766
|
-
const _wortbestand = new WeakMap();
|
|
1767
|
-
/** Nur fuer die Zaehlung in Tests — die WeakMap laesst sich nicht zaehlen. */
|
|
1768
|
-
let _wortbestandZaehler = 0;
|
|
1769
|
-
/**
|
|
1770
|
-
* Wirft alle Bestaende weg. Ruft der Schreibpfad auf, wenn eine Lektion neu
|
|
1771
|
-
* geschrieben wurde — ohne das waere sie bis zu eine Minute unsichtbar.
|
|
1772
|
-
*
|
|
1773
|
-
* Absichtlich ALLE und nicht nur die betroffene Verbindung: der Aufrufer
|
|
1774
|
-
* kennt die Verbindung an dieser Stelle nicht immer, und ein Bestand zu viel
|
|
1775
|
-
* neu zu bauen kostet eine Sekunde. Einen zu wenig zu entwerten kostet eine
|
|
1776
|
-
* Minute Unsichtbarkeit.
|
|
1777
|
-
*/
|
|
1778
|
-
export function wortindexEntwerten() {
|
|
1779
|
-
_entwertetAb = Date.now();
|
|
1780
|
-
_wortbestandZaehler = 0;
|
|
1781
|
-
}
|
|
1782
|
-
/** Alles, was vor diesem Zeitpunkt gebaut wurde, gilt als veraltet. */
|
|
1783
|
-
let _entwertetAb = 0;
|
|
1784
|
-
/** Nur fuer Tests: wie viele Bestaende seit dem letzten Entwerten stehen. */
|
|
1785
|
-
export function wortindexStand() {
|
|
1786
|
-
return _wortbestandZaehler;
|
|
1787
|
-
}
|
|
1788
|
-
async function keywordSearch(redis, patterns, query, topK = 10) {
|
|
1789
|
-
const bestandsSchluessel = patterns.slice().sort().join('|');
|
|
1790
|
-
const jeVerbindung = _wortbestand.get(redis);
|
|
1791
|
-
const stehend = jeVerbindung?.get(bestandsSchluessel);
|
|
1792
|
-
if (stehend
|
|
1793
|
-
&& stehend.gebaut > _entwertetAb
|
|
1794
|
-
&& Date.now() - stehend.gebaut < WORTBESTAND_FRISCHE_MS) {
|
|
1795
|
-
return keywordSearchMitBestand(stehend, query, topK);
|
|
1796
|
-
}
|
|
1797
|
-
// ── Step 1: Collect all matching keys — patterns scanned in parallel ──
|
|
1798
|
-
const keyBatches = await Promise.all(patterns.map(pattern => {
|
|
1799
|
-
const keys = [];
|
|
1800
|
-
const stream = redis.scanStream({ match: pattern, count: 500 });
|
|
1801
|
-
return new Promise((resolve, reject) => {
|
|
1802
|
-
stream.on('data', (batch) => {
|
|
1803
|
-
keys.push(...batch.filter((k) => !k.endsWith(':meta')));
|
|
1804
|
-
});
|
|
1805
|
-
stream.on('end', () => resolve(keys));
|
|
1806
|
-
stream.on('error', reject);
|
|
1807
|
-
});
|
|
1808
|
-
}));
|
|
1809
|
-
// Deduplicate across patterns (a key may match multiple globs)
|
|
1810
|
-
const allKeys = [...new Set(keyBatches.flat())];
|
|
1811
|
-
if (allKeys.length === 0)
|
|
1812
|
-
return [];
|
|
1813
|
-
// Pipeline GET for speed
|
|
1814
|
-
const pipeline = redis.pipeline();
|
|
1815
|
-
for (const key of allKeys)
|
|
1816
|
-
pipeline.get(key);
|
|
1817
|
-
const results = await pipeline.exec();
|
|
1818
|
-
const docs = [];
|
|
1819
|
-
let totalTokens = 0;
|
|
1820
|
-
for (let i = 0; i < allKeys.length; i++) {
|
|
1821
|
-
const content = results?.[i]?.[1];
|
|
1822
|
-
if (!content)
|
|
1823
|
-
continue;
|
|
1824
|
-
// Indiziert wird der ROHE Inhalt, nicht eine Auswahl von Feldern.
|
|
1825
|
-
//
|
|
1826
|
-
// Am 19.08.2026 wurde genau das versucht: nur die bedeutungstragenden
|
|
1827
|
-
// Felder indizieren (Thema dreifach, dann what_worked, what_failed, tags,
|
|
1828
|
-
// commands, file_paths) und Pruefspur, Zahlen und Feldnamen weglassen. Das
|
|
1829
|
-
// Argument dafuer war gut: die Dokumentlaenge sollte nicht von einer langen
|
|
1830
|
-
// Pruefspur aufgeblaeht werden.
|
|
1831
|
-
//
|
|
1832
|
-
// Gemessen an 499 Lektionen mit 100 Fragen kostete es in JEDER Einstellung
|
|
1833
|
-
// einen Treffer:
|
|
1834
|
-
//
|
|
1835
|
-
// Synonymgewicht mit Feldauswahl ohne
|
|
1836
|
-
// 1.0 19 20
|
|
1837
|
-
// 0.5 20 21
|
|
1838
|
-
// 0.35 21 22
|
|
1839
|
-
//
|
|
1840
|
-
// Steht hier, damit es niemand — auch ich nicht — ein zweites Mal fuer eine
|
|
1841
|
-
// gute Idee haelt. Das Argument war plausibel und falsch, und genau diese
|
|
1842
|
-
// Sorte Aenderung hat uns die `score^0.3`-Stauchung eingebracht.
|
|
1843
|
-
const tokens = tokenize(`${allKeys[i]} ${content}`, { crossLingualExpand: false });
|
|
1844
|
-
if (tokens.length === 0)
|
|
1845
|
-
continue;
|
|
1846
|
-
// Term frequency map
|
|
1847
|
-
const tokenFreq = new Map();
|
|
1848
|
-
for (const t of tokens) {
|
|
1849
|
-
tokenFreq.set(t, (tokenFreq.get(t) ?? 0) + 1);
|
|
1850
|
-
}
|
|
1851
|
-
// Bigrams — adjacent token pairs for proximity detection
|
|
1852
|
-
const bigrams = new Set();
|
|
1853
|
-
for (let j = 0; j < tokens.length - 1; j++) {
|
|
1854
|
-
bigrams.add(`${tokens[j]}|${tokens[j + 1]}`);
|
|
1855
|
-
}
|
|
1856
|
-
const timestamp = extractTimestamp(content);
|
|
1857
|
-
// Key tokens for title-boost: terms appearing in the Redis key get extra weight
|
|
1858
|
-
const keyTokens = new Set(tokenize(allKeys[i]));
|
|
1859
|
-
docs.push({ key: allKeys[i], content, tokens, tokenFreq, bigrams, keyTokens, timestamp });
|
|
1860
|
-
totalTokens += tokens.length;
|
|
1861
|
-
}
|
|
1862
|
-
if (docs.length === 0)
|
|
1863
|
-
return [];
|
|
1864
|
-
const avgDL = totalTokens / docs.length;
|
|
1865
|
-
// ── Step 2: IDF (inverse document frequency) ──
|
|
1866
|
-
const docFreq = new Map();
|
|
1867
|
-
for (const doc of docs) {
|
|
1868
|
-
const seen = new Set();
|
|
1869
|
-
for (const t of doc.tokens) {
|
|
1870
|
-
if (!seen.has(t)) {
|
|
1871
|
-
docFreq.set(t, (docFreq.get(t) ?? 0) + 1);
|
|
1872
|
-
seen.add(t);
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
const gebauter = { docs, avgDL, docFreq, gebaut: Date.now() };
|
|
1877
|
-
const fach = _wortbestand.get(redis) ?? new Map();
|
|
1878
|
-
if (!fach.has(bestandsSchluessel))
|
|
1879
|
-
_wortbestandZaehler++;
|
|
1880
|
-
fach.set(bestandsSchluessel, gebauter);
|
|
1881
|
-
_wortbestand.set(redis, fach);
|
|
1882
|
-
return keywordSearchMitBestand(gebauter, query, topK);
|
|
1883
|
-
}
|
|
1884
|
-
/**
|
|
1885
|
-
* Die Bewertung selbst — alles, was von der FRAGE abhaengt.
|
|
1886
|
-
*
|
|
1887
|
-
* Unveraendert aus keywordSearch herausgeloest: dieselbe Reihenfolge,
|
|
1888
|
-
* dieselben Formeln. Getrennt wurde nur, was je Bestand gilt, von dem, was je
|
|
1889
|
-
* Frage gilt.
|
|
1890
|
-
*/
|
|
1891
|
-
function keywordSearchMitBestand(bestand, query, topK) {
|
|
1892
|
-
const { docs, avgDL, docFreq } = bestand;
|
|
1893
|
-
const N = docs.length;
|
|
1894
|
-
function idf(term) {
|
|
1895
|
-
const df = docFreq.get(term) ?? 0;
|
|
1896
|
-
return Math.log((N - df + 0.5) / (df + 0.5) + 1);
|
|
1897
|
-
}
|
|
1898
|
-
/**
|
|
1899
|
-
* BM25+ score for a term in a document.
|
|
1900
|
-
* Classic BM25: TF_norm = tf*(k1+1) / (tf + k1*(1 - b + b*dl/avgdl))
|
|
1901
|
-
* BM25+ adds: + δ (guarantees long docs with the term still score positively)
|
|
1902
|
-
*/
|
|
1903
|
-
function bm25PlusTerm(term, doc) {
|
|
1904
|
-
const tf = doc.tokenFreq.get(term) ?? 0;
|
|
1905
|
-
if (tf === 0)
|
|
1906
|
-
return 0;
|
|
1907
|
-
const dl = doc.tokens.length;
|
|
1908
|
-
const tfNorm = (tf * (BM25_K1 + 1)) / (tf + BM25_K1 * (1 - BM25_B + BM25_B * (dl / avgDL)));
|
|
1909
|
-
return idf(term) * (tfNorm + BM25_DELTA);
|
|
1910
|
-
}
|
|
1911
|
-
// Die frueher hier stehende Funktion `fuzzyMatch(qt, docTermSet)` ist am
|
|
1912
|
-
// 19.08.2026 entfallen. Sie lief je Frage UND je Dokument und durchsuchte den
|
|
1913
|
-
// Wortvorrat des Dokuments bis zu viermal — bei 499 Lektionen rund 540 der
|
|
1914
|
-
// 788 Millisekunden je Frage.
|
|
1915
|
-
//
|
|
1916
|
-
// An ihre Stelle tritt `fuzzyKandidaten(qt)` weiter unten: die passenden
|
|
1917
|
-
// Woerter werden EINMAL je Frage gegen den Gesamtwortschatz bestimmt, danach
|
|
1918
|
-
// ist die Pruefung je Dokument ein Nachschlagen.
|
|
1919
|
-
// ── Step 3: Score each sub-query independently ──
|
|
1920
|
-
const subQueries = splitMultiQuery(query);
|
|
1921
|
-
const allMatches = new Map();
|
|
1922
|
-
for (const sq of subQueries) {
|
|
1923
|
-
const queryTokens = tokenize(sq);
|
|
1924
|
-
if (queryTokens.length === 0)
|
|
1925
|
-
continue;
|
|
1926
|
-
// ── Unscharfe Treffer einmal aufloesen, nicht je Dokument ──────────────
|
|
1927
|
-
//
|
|
1928
|
-
// Vorher stand im Bewertungsteil `fuzzyMatch(qt, new Set(doc.tokens))` —
|
|
1929
|
-
// pro Frage UND pro Dokument. Bei 499 Lektionen mit je rund 300 Woertern
|
|
1930
|
-
// und 40 Fragewoertern waren das ueber zwanzig Millionen Zeichenvergleiche,
|
|
1931
|
-
// viele davon Levenshtein.
|
|
1932
|
-
//
|
|
1933
|
-
// Gemessen am 19.08.2026: von 788 ms je Frage entfielen 249 ms auf den
|
|
1934
|
-
// Indexaufbau und rund 540 ms auf genau diese Schleife.
|
|
1935
|
-
//
|
|
1936
|
-
// Der Wortschatz ist fuer alle Dokumente derselbe. Also wird je Fragewort
|
|
1937
|
-
// EINMAL bestimmt, welche vorhandenen Woerter dazu passen — danach ist die
|
|
1938
|
-
// Pruefung je Dokument ein Nachschlagen in einer Map.
|
|
1939
|
-
//
|
|
1940
|
-
// Nebeneffekt: das Ergebnis wird VERLAESSLICHER. Vorher nahm fuzzyMatch das
|
|
1941
|
-
// erste passende Wort in der Reihenfolge, in der die Woerter eines
|
|
1942
|
-
// Dokuments zufaellig standen — dasselbe Fragewort konnte in zwei
|
|
1943
|
-
// Dokumenten auf verschiedene Woerter treffen.
|
|
1944
|
-
const fuzzySpeicher = new Map();
|
|
1945
|
-
const fuzzyKandidaten = (qt) => {
|
|
1946
|
-
const da = fuzzySpeicher.get(qt);
|
|
1947
|
-
if (da)
|
|
1948
|
-
return da;
|
|
1949
|
-
// Alle Kandidaten je Stufe sammeln — NICHT nach den ersten acht
|
|
1950
|
-
// abbrechen.
|
|
1951
|
-
//
|
|
1952
|
-
// Die erste Fassung tat genau das und kostete 15 von 100 Fragen: sie
|
|
1953
|
-
// nahm die ersten acht Woerter in der Reihenfolge, in der sie zufaellig
|
|
1954
|
-
// im Wortschatz standen, und die passten meist nicht zu dem Dokument,
|
|
1955
|
-
// um das es ging. Schneller und schlechter ist kein Fortschritt.
|
|
1956
|
-
const sammle = (passt, gewichtung) => {
|
|
1957
|
-
const aus = [];
|
|
1958
|
-
for (const dt of docFreq.keys())
|
|
1959
|
-
if (passt(dt))
|
|
1960
|
-
aus.push([dt, gewichtung]);
|
|
1961
|
-
// Seltene Woerter zuerst: sie unterscheiden. Ein Wort, das in 300 von
|
|
1962
|
-
// 499 Lektionen steht, sagt nichts darueber, welche gemeint ist.
|
|
1963
|
-
aus.sort((a, b) => (docFreq.get(a[0]) ?? 0) - (docFreq.get(b[0]) ?? 0));
|
|
1964
|
-
return aus.slice(0, FUZZY_KANDIDATEN);
|
|
1965
|
-
};
|
|
1966
|
-
let aus = [];
|
|
1967
|
-
if (qt.length >= 4) {
|
|
1968
|
-
aus = sammle((dt) => dt.length > qt.length && dt.startsWith(qt), 0.85);
|
|
1969
|
-
}
|
|
1970
|
-
if (aus.length === 0 && qt.length >= 4) {
|
|
1971
|
-
aus = sammle((dt) => dt.length >= 4 && dt.length < qt.length && qt.startsWith(dt), 0.75);
|
|
1972
|
-
}
|
|
1973
|
-
if (aus.length === 0 && qt.length > 3) {
|
|
1974
|
-
aus = sammle((dt) => dt.length > 3 && (dt.includes(qt) || qt.includes(dt)), 0.6);
|
|
1975
|
-
}
|
|
1976
|
-
if (aus.length === 0 && qt.length >= 4) {
|
|
1977
|
-
aus = sammle((dt) => dt.length >= 4 && levenshtein(qt, dt) <= 2, 0.4);
|
|
1978
|
-
}
|
|
1979
|
-
fuzzySpeicher.set(qt, aus);
|
|
1980
|
-
return aus;
|
|
1981
|
-
};
|
|
1982
|
-
// Die Woerter, die der Mensch WIRKLICH getippt hat — ohne Synonyme.
|
|
1983
|
-
//
|
|
1984
|
-
// Gebraucht wird das fuer den Titel-Bonus weiter unten. Der teilte bisher
|
|
1985
|
-
// durch die ERWEITERTE Fragelaenge, und das ist ein Fehler mit Ansage:
|
|
1986
|
-
// eine deutsche Frage wird auf ein Vielfaches aufgeblasen (Englisch,
|
|
1987
|
-
// Japanisch, Chinesisch, Koreanisch, Arabisch, Russisch ...), also sank
|
|
1988
|
-
// der Bonus mit jedem Synonym, das wir der Tabelle hinzufuegten.
|
|
1989
|
-
//
|
|
1990
|
-
// Gemessen am 19.08.2026: "Jeder Build laedt alle Abhaengigkeiten neu ..."
|
|
1991
|
-
// ergab 26 Tokens fuer 12 getippte Woerter. Ein Titeltreffer zaehlte damit
|
|
1992
|
-
// 3/26 statt 3/12 — der Bonus fiel von 1,13 auf 1,06.
|
|
1993
|
-
//
|
|
1994
|
-
// Das ist die unangenehme Sorte Fehler: die Suche zu verbessern (mehr
|
|
1995
|
-
// Synonyme) machte den Titel-Bonus schwaecher. Zwei Stellschrauben, die
|
|
1996
|
-
// gegeneinander arbeiteten, ohne dass es jemandem auffiel.
|
|
1997
|
-
const kernTokens = new Set(tokenize(sq, { crossLingualExpand: false }));
|
|
1998
|
-
// Pre-compute query bigrams for proximity boost
|
|
1999
|
-
const queryBigrams = new Set();
|
|
2000
|
-
for (let j = 0; j < queryTokens.length - 1; j++) {
|
|
2001
|
-
queryBigrams.add(`${queryTokens[j]}|${queryTokens[j + 1]}`);
|
|
2002
|
-
}
|
|
2003
|
-
for (const doc of docs) {
|
|
2004
|
-
let score = 0;
|
|
2005
|
-
const matchedWords = [];
|
|
2006
|
-
for (const qt of queryTokens) {
|
|
2007
|
-
// Ein Wort, das der Mensch getippt hat, zaehlt voll. Ein Synonym, das
|
|
2008
|
-
// WIR ergaenzt haben, zaehlt weniger.
|
|
2009
|
-
//
|
|
2010
|
-
// Grund: die Bruecke von einer Sprache in die andere landet meistens
|
|
2011
|
-
// bei allgemeinen Woertern. `Zugriffsprotokoll` wird ueber `protokoll`
|
|
2012
|
-
// zu `log`, und `log` steht in hunderten Lektionen. Zaehlt das genauso
|
|
2013
|
-
// viel wie ein getipptes seltenes Wort, gewinnt die Breite gegen die
|
|
2014
|
-
// Genauigkeit.
|
|
2015
|
-
const gewicht = kernTokens.has(qt) ? 1 : SYNONYM_GEWICHT;
|
|
2016
|
-
const exactScore = bm25PlusTerm(qt, doc);
|
|
2017
|
-
if (exactScore > 0) {
|
|
2018
|
-
score += exactScore * gewicht;
|
|
2019
|
-
matchedWords.push(qt);
|
|
2020
|
-
continue;
|
|
2021
|
-
}
|
|
2022
|
-
// Unscharfer Treffer — die Kandidaten stehen schon fest, siehe unten.
|
|
2023
|
-
for (const [term, gewichtung] of fuzzyKandidaten(qt)) {
|
|
2024
|
-
if (!doc.tokenFreq.has(term))
|
|
2025
|
-
continue;
|
|
2026
|
-
score += bm25PlusTerm(term, doc) * gewichtung * gewicht;
|
|
2027
|
-
matchedWords.push(`~${qt}`);
|
|
2028
|
-
break;
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
// Bigram proximity boost: +50% for each adjacent query term pair found in doc
|
|
2032
|
-
if (queryBigrams.size > 0) {
|
|
2033
|
-
let bigramHits = 0;
|
|
2034
|
-
for (const bg of queryBigrams) {
|
|
2035
|
-
if (doc.bigrams.has(bg))
|
|
2036
|
-
bigramHits++;
|
|
2037
|
-
}
|
|
2038
|
-
if (bigramHits > 0) {
|
|
2039
|
-
score *= 1 + 0.5 * (bigramHits / queryBigrams.size);
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
// Phrase-match boost: if the raw (lowercased) query appears verbatim in content, 2× boost
|
|
2043
|
-
// This rewards docs where the exact phrase exists (vs scattered tokens).
|
|
2044
|
-
if (!process.env.AUS_PHRASE && sq.length >= 4 && doc.content.toLowerCase().includes(sq.toLowerCase())) {
|
|
2045
|
-
score *= 2.0;
|
|
2046
|
-
}
|
|
2047
|
-
// Key/title boost: if query terms appear in the Redis key (=title), 1.5× boost
|
|
2048
|
-
// Keys often encode the primary topic (e.g. "deploy:api:server"), so key hits are high-precision.
|
|
2049
|
-
// Der Titel (Redis-Schluessel) ist das dichteste Feld, das wir haben:
|
|
2050
|
-
// `ci:node3-disk-full-zombie-deploy` traegt die Antwort im Namen. Ein
|
|
2051
|
-
// Treffer dort ist mehr wert als drei im Fliesstext.
|
|
2052
|
-
//
|
|
2053
|
-
// Bezugsgroesse sind deshalb die GETIPPTEN Woerter, nicht die erweiterten
|
|
2054
|
-
// — siehe kernTokens oben. Und die Obergrenze ist hoeher (2,0 statt 1,5),
|
|
2055
|
-
// weil der bisherige Deckel bei langen Fragen nie erreicht wurde.
|
|
2056
|
-
if (score > 0) {
|
|
2057
|
-
let keyHits = 0;
|
|
2058
|
-
let kernHits = 0;
|
|
2059
|
-
for (const qt of queryTokens) {
|
|
2060
|
-
if (!doc.keyTokens.has(qt))
|
|
2061
|
-
continue;
|
|
2062
|
-
keyHits++;
|
|
2063
|
-
if (kernTokens.has(qt))
|
|
2064
|
-
kernHits++;
|
|
2065
|
-
}
|
|
2066
|
-
if (keyHits > 0) {
|
|
2067
|
-
const anteil = kernHits / Math.max(1, kernTokens.size);
|
|
2068
|
-
score *= 1 + 1.0 * Math.min(1, anteil * 2);
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
// Recency boost
|
|
2072
|
-
score *= recencyBoost(doc.timestamp);
|
|
2073
|
-
if (score > 0) {
|
|
2074
|
-
const existing = allMatches.get(doc.key);
|
|
2075
|
-
if (!existing || score > existing.score) {
|
|
2076
|
-
allMatches.set(doc.key, {
|
|
2077
|
-
key: doc.key,
|
|
2078
|
-
content: doc.content,
|
|
2079
|
-
score,
|
|
2080
|
-
matchedWords: [...new Set(matchedWords)],
|
|
2081
|
-
subQuery: subQueries.length > 1 ? sq : undefined,
|
|
2082
|
-
});
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
// ── Step 4: Sort by score, return top-K ──
|
|
2088
|
-
const sorted = [...allMatches.values()].sort((a, b) => b.score - a.score);
|
|
2089
|
-
const topResults = sorted.slice(0, topK);
|
|
2090
|
-
// ── Step 5: Zero-results logging + Did-You-Mean ───────────────────────────
|
|
2091
|
-
if (topResults.length === 0) {
|
|
2092
|
-
logZeroResult(query);
|
|
2093
|
-
// Rebuild index vocab for Did-You-Mean suggestions
|
|
2094
|
-
_indexVocab = new Set();
|
|
2095
|
-
for (const doc of docs)
|
|
2096
|
-
for (const t of doc.tokens)
|
|
2097
|
-
_indexVocab.add(t);
|
|
2098
|
-
}
|
|
2099
|
-
return topResults;
|
|
2100
|
-
}
|
|
2101
|
-
// ── Exported for testing ──────────────────────────────────────────────────────
|
|
2102
|
-
export { tokenize, splitMultiQuery, levenshtein, recencyBoost, extractTimestamp, STOPWORDS, katakanaToRomaji, arabicLightStem, expandCrossLingual, CROSS_LINGUAL_MAP };
|
|
2103
|
-
export { keywordSearch, ZERO_RESULTS_LOG, logZeroResult, _indexVocab as indexVocab, zeroResultsTotal };
|
|
2104
|
-
//# sourceMappingURL=search.js.map
|
|
1
|
+
const h=new Set(["the","a","an","is","are","was","were","be","been","being","have","has","had","having","do","does","did","doing","will","would","could","should","may","might","shall","can","to","of","in","for","on","with","at","by","from","as","into","through","during","before","after","above","below","between","about","against","among","around","without","within","along","across","behind","beyond","upon","toward","towards","and","but","or","not","no","nor","so","if","then","than","too","very","quite","rather","just","also","only","even","it","its","this","that","these","those","here","there","my","your","his","her","our","their","mine","yours","ours","what","which","who","whom","whose","how","when","where","why","all","each","every","both","few","more","most","much","many","other","some","such","own","same","any","either","neither","been","being","because","until","while","once","again","further","already","always","never","sometimes","often","still","yet","der","die","das","den","dem","des","ein","eine","einen","einem","einer","eines","und","oder","aber","denn","weil","ist","sind","war","waren","sein","wird","werden","wurde","hat","haben","hatte","hatten","kann","k\xF6nnen","konnte","soll","sollen","sollte","muss","m\xFCssen","musste","darf","mag","m\xF6chte","wollen","wollte","w\xFCrde","k\xF6nnte","sollte","mit","f\xFCr","auf","von","aus","bei","nach","\xFCber","unter","vor","hinter","neben","zwischen","durch","gegen","ohne","um","bis","seit","w\xE4hrend","wegen","trotz","statt","wie","was","wer","wen","wem","wessen","wo","wann","warum","nicht","noch","auch","schon","nur","sehr","mehr","viel","alle","jeder","jede","jedes","dieser","diese","dieses","jener","jene","jenes","mein","dein","sein","ihr","unser","euer","kein","keine","sich","mir","dir","ihm","uns","euch","ich","du","er","sie","es","wir","ihr","man","hier","dort","da","dann","also","doch","mal","eben","ganz","le","la","les","un","une","des","du","de","au","aux","et","ou","mais","donc","car","ni","que","qui","quoi","est","sont","\xE9tait","ont","avoir","\xEAtre","fait","faire","pour","par","avec","dans","sur","sous","entre","vers","chez","sans","avant","apr\xE8s","pendant","depuis","contre","ce","cette","ces","mon","ton","son","notre","votre","leur","je","tu","il","elle","nous","vous","ils","elles","on","ne","pas","plus","tr\xE8s","bien","aussi","tout","tous","toute","m\xEAme","autre","quel","quelle","comment","quand","o\xF9","pourquoi","el","la","los","las","un","una","unos","unas","del","al","lo","que","en","es","por","con","para","como","pero","m\xE1s","fue","ser","hay","est\xE1","han","son","tiene","hab\xEDa","era","su","sus","este","esta","estos","estas","ese","esa","esos","mi","tu","yo","\xE9l","ella","nosotros","ellos","ellas","usted","no","ya","s\xED","sin","sobre","entre","hasta","desde","donde","muy","todo","toda","todos","cada","otro","otra","otros","cuando","porque","aunque","tambi\xE9n","solo","despu\xE9s","antes","il","lo","la","li","le","gli","uno","una","dei","del","che","di","da","per","con","tra","fra","sul","nel","al","\xE8","sono","ha","hanno","era","essere","fare","fatto","stato","suo","sua","suoi","questo","questa","questi","quello","quella","io","tu","lui","lei","noi","voi","loro","ci","si","non","pi\xF9","molto","anche","solo","tutto","tutti","ogni","come","dove","quando","perch\xE9","ancora","gi\xE0","sempre","mai","um","uma","uns","umas","do","da","dos","das","no","na","ao","aos","em","por","com","para","sem","sob","sobre","que","se","mas","ou","como","mais","entre","at\xE9","desde","\xE9","s\xE3o","foi","tem","ser","ter","estar","fazer","havia","seu","sua","seus","suas","este","esta","esse","essa","aquele","eu","tu","ele","ela","n\xF3s","eles","elas","voc\xEA","voc\xEAs","n\xE3o","j\xE1","sim","bem","muito","tamb\xE9m","ainda","sempre","todo","toda","todos","cada","outro","outra","quando","porque","\u7684","\u4E86","\u662F","\u5728","\u4E0D","\u548C","\u6211","\u4ED6","\u8FD9","\u4E2D","\u5927","\u4E3A","\u4E0A","\u4E2A","\u56FD","\u4EE5","\u8981","\u5C31","\u51FA","\u8BF4","\u4EEC","\u6709","\u6765","\u5230","\u65F6","\u5730","\u5E74","\u5F97","\u7740","\u90A3","\u8FC7","\u540E","\u8FD8","\u4E0E","\u4E5F","\u53EF","\u4E8E","\u4ECE","\u4F46","\u800C","\u88AB","\u628A","\u8BA9","\u4F7F","\u5BF9","\u5F88","\u90FD","\u4E00","\u4F1A","\u6CA1","\u4EBA","\u5B83","\u8FD9\u4E2A","\u90A3\u4E2A","\u4EC0\u4E48","\u5982\u679C","\u56E0\u4E3A","\u6240\u4EE5","\u5DF2\u7ECF","\u53EF\u4EE5","\u8FD9\u4E9B","\u90A3\u4E9B","\u6211\u4EEC","\u4ED6\u4EEC","\u5979\u4EEC","\u5B83\u4EEC","\u306E","\u306F","\u304C","\u3092","\u306B","\u3067","\u3068","\u3082","\u3084","\u304B","\u306A","\u306D","\u3088","\u308F","\u3066","\u3044","\u3046","\u3048","\u304A","\u304D","\u304F","\u3051","\u3053","\u3055","\u3057","\u3059","\u305B","\u305D","\u305F","\u3061","\u3064","\u306C","\u3093","\u304B\u3089","\u307E\u3067","\u3088\u308A","\u3078","\u3067\u3059","\u307E\u3059","\u306A\u3044","\u3042\u308B","\u3044\u308B","\u3059\u308B","\u3053\u3068","\u3082\u306E","\u306E\u3067","\u3067\u306F","\u306B\u306F","\u3068\u306E","\u3078\u306E","\u304B\u3089","\u307E\u3067","\uC774","\uAC00","\uC740","\uB294","\uC744","\uB97C","\uC758","\uC5D0","\uC640","\uACFC","\uB3C4","\uB85C","\uC5D0\uC11C","\uD55C","\uD558","\uC788","\uC5C6","\uAC83","\uC218","\uC54A","\uB4E4","\uC774\uB2E4","\uD558\uB2E4","\uC774\uACE0","\uC774\uBA70","\uB77C\uACE0","\uC5D0\uAC8C","\uC5D0\uC11C","\uC73C\uB85C","\u0641\u064A","\u0645\u0646","\u0625\u0644\u0649","\u0639\u0644\u0649","\u0639\u0646","\u0645\u0639","\u0647\u0630\u0627","\u0647\u0630\u0647","\u0630\u0644\u0643","\u062A\u0644\u0643","\u0627\u0644\u0630\u064A","\u0627\u0644\u062A\u064A","\u0627\u0644\u0630\u064A\u0646","\u0627\u0644\u0644\u0648\u0627\u062A\u064A","\u0647\u0648","\u0647\u064A","\u0647\u0645","\u0647\u0646","\u0646\u062D\u0646","\u0623\u0646\u062A","\u0623\u0646\u062A\u0645","\u0623\u0646\u0627","\u0643\u0627\u0646","\u0643\u0627\u0646\u062A","\u0643\u0627\u0646\u0648\u0627","\u064A\u0643\u0648\u0646","\u062A\u0643\u0648\u0646","\u0623\u0646","\u0625\u0646","\u0644\u0623\u0646","\u0644\u0643\u0646","\u0623\u0648","\u0628\u0644","\u062B\u0645","\u062D\u062A\u0649","\u0625\u0630\u0627","\u0643\u064A","\u0642\u062F","\u0644\u0642\u062F","\u0644\u0645","\u0644\u0646","\u0645\u0627","\u0644\u0627","\u0644\u064A\u0633","\u063A\u064A\u0631","\u0628\u0639\u0636","\u0643\u0644","\u062C\u0645\u064A\u0639","\u0623\u064A","\u0643\u064A\u0641","\u0645\u062A\u0649","\u0623\u064A\u0646","\u0644\u0645\u0627\u0630\u0627","\u0645\u0627\u0630\u0627","\u0647\u0644","\u0627\u0644","\u0648","\u0641","\u0628","\u0644","\u0643","\u064A\u0627","\u0623\u0645","\u0625\u0644\u0627","\u0639\u0646\u062F","\u0628\u064A\u0646","\u05E9\u05DC","\u05D0\u05EA","\u05D0\u05DC","\u05E2\u05DC","\u05E2\u05DD","\u05DC\u05D0","\u05D4\u05D5\u05D0","\u05D4\u05D9\u05D0","\u05D4\u05DD","\u05D4\u05DF","\u05D0\u05E0\u05D9","\u05D0\u05EA\u05D4","\u05D0\u05E0\u05D7\u05E0\u05D5","\u05D0\u05EA\u05DD","\u05DB\u05D9","\u05D0\u05DD","\u05D0\u05D1\u05DC","\u05D2\u05DD","\u05DB\u05D1\u05E8","\u05E8\u05E7","\u05E2\u05D5\u05D3","\u05D9\u05E9","\u05D0\u05D9\u05DF","\u05DE\u05D4","\u05D6\u05D4","\u05D6\u05D0\u05EA","\u05D0\u05DC\u05D4","\u05DB\u05DC","\u05DB\u05DF","\u05DC\u05D5","\u05DC\u05D4","\u05DC\u05D4\u05DD","\u05D1\u05D5","\u05D1\u05D4","\u05D1\u05D4\u05DD","\u05E9\u05DD","\u05DB\u05DA","\u05DB\u05DF","\u05DE\u05D9","\u05D0\u05E9\u05E8","\u05D0\u05D7\u05E8\u05D9","\u05DC\u05E4\u05E0\u05D9","\u05EA\u05D7\u05EA","\u05D1\u05D9\u05DF","\u05DE\u05D0\u05D6","\u05E2\u05D3","\u05DB\u05DE\u05D5","\u05D0\u05D6","\u062F\u0631","\u0627\u0632","\u0628\u0647","\u0628\u0627","\u06A9\u0647","\u0627\u06CC\u0646","\u0622\u0646","\u0631\u0627","\u0627\u0633\u062A","\u0628\u0648\u062F","\u0628\u0627\u0634\u062F","\u0634\u062F","\u0634\u062F\u0647","\u0645\u06CC","\u0646\u0647","\u0646\u06CC\u0633\u062A","\u0647\u0645","\u0647\u0631","\u06CC\u06A9","\u0627\u0645\u0627","\u0648","\u06CC\u0627","\u062A\u0627","\u0627\u06AF\u0631","\u0628\u0631\u0627\u06CC","\u0686\u0648\u0646","\u0686\u0647","\u06A9\u062C\u0627","\u06A9\u06CC","\u0686\u0637\u0648\u0631","\u0648\u0642\u062A\u06CC","\u0628\u0639\u062F","\u0642\u0628\u0644","\u0645\u062B\u0644","\u0647\u0645\u0647","\u0628\u0639\u0636\u06CC","\u0647\u06CC\u0686","\u0622\u06CC\u0627","\u062E\u0648\u062F","\u0686\u0646\u062F","\u062F\u06CC\u06AF\u0631","\u0647\u0646\u0648\u0632","\u0647\u0645\u0627\u0646","\u0622\u0646\u0647\u0627","\u0627\u06CC\u0646\u0647\u0627","\u0645\u0627","\u0634\u0645\u0627","\u0622\u0646\u0627\u0646","\u0645\u0646","\u062A\u0648","\u0627\u0648","\u0622\u0646\u0627\u0646","\u0627\u06CC\u0634\u0627\u0646","\u0631\u0648\u06CC","\u0632\u06CC\u0631","\u0628\u06CC\u0646","\u067E\u06CC\u0634","\u067E\u0633","\u0637\u0631\u0641","\u062F\u0627\u062E\u0644","\u062E\u0627\u0631\u062C","\u06A9\u0646\u0627\u0631","\u0647\u0645\u0686\u0646\u06CC\u0646","\u0645\u06AF\u0631","\u0648\u0644\u06CC","\u0648\u06AF\u0631\u0646\u0647","\u0686\u0631\u0627","\u0686\u06AF\u0648\u0646\u0647","\u06A9\u062F\u0627\u0645","\u0939\u0948","\u092E\u0947\u0902","\u0938\u0947","\u0915\u094B","\u0915\u093E","\u0915\u0940","\u0915\u0947","\u092A\u0930","\u0914\u0930","\u092F\u093E","\u0928\u0939\u0940\u0902","\u092F\u0939","\u0935\u0939","\u090F\u0915","\u0907\u0938","\u0909\u0938","\u092D\u0940","\u0939\u094B","\u0925\u093E","\u0925\u0940","\u0925\u0947","\u0939\u0948\u0902","\u0939\u0942\u0901","\u0932\u093F\u090F","\u0924\u0915","\u0938\u093E\u0925","\u092C\u093E\u0926","\u092A\u0939\u0932\u0947","\u091C\u094B","\u091C\u092C","\u0915\u0948\u0938\u0947","\u0915\u094D\u092F\u094B\u0902","\u0915\u094D\u092F\u093E","\u0915\u0939\u093E\u0901","\u0915\u094C\u0928","\u0939\u092E","\u0906\u092A","\u0935\u0947","\u092E\u0948\u0902","\u0924\u0941\u092E","\u0909\u0928","\u0907\u0928","\u0928\u0947","\u092C\u0939\u0941\u0924","\u0938\u092C","\u0915\u0941\u091B","\u092B\u093F\u0930","\u0905\u092C","\u0924\u094B","\u0939\u0940","\u0924\u0930\u0939","\u091C\u0948\u0938\u0947","\u0915\u0930\u0928\u093E","\u0939\u094B\u0928\u093E","\u0930\u0939\u093E","\u0930\u0939\u0940","\u0930\u0939\u0947","\u0917\u092F\u093E","\u0917\u0908","\u0917\u090F","\u0915\u093F\u092F\u093E","\u0915\u093F\u090F","\u0915\u0930","\u0939\u0941\u0906","\u0939\u0941\u0908","\u0432","\u043D\u0430","\u043D\u0435","\u0441","\u0438","\u0430","\u043D\u043E","\u043F\u043E","\u0437\u0430","\u0438\u0437","\u043E\u0442","\u0434\u043E","\u043A","\u0443","\u043E","\u043E\u0431","\u0432\u043E","\u043F\u0440\u0438","\u043F\u043E\u0434","\u043D\u0430\u0434","\u0431\u0435\u0437","\u0434\u043B\u044F","\u0447\u0442\u043E","\u043A\u0430\u043A","\u044D\u0442\u043E","\u0432\u0441\u0435","\u0442\u0430\u043A","\u0443\u0436\u0435","\u0438\u043B\u0438","\u0436\u0435","\u043B\u0438","\u0435\u0441\u043B\u0438","\u0442\u043E","\u0434\u0430","\u043D\u0435\u0442","\u0431\u044B\u043B","\u0431\u044B\u043B\u0430","\u0431\u044B\u043B\u0438","\u0431\u044B\u0442\u044C","\u0435\u0441\u0442\u044C","\u0435\u0433\u043E","\u0435\u0451","\u0438\u0445","\u044D\u0442\u043E\u0442","\u044D\u0442\u0430","\u044D\u0442\u0438","\u043A\u043E\u0442\u043E\u0440\u044B\u0439","\u043A\u043E\u0442\u043E\u0440\u0430\u044F","\u043A\u043E\u0442\u043E\u0440\u044B\u0435","\u043A\u043E\u0442\u043E\u0440\u044B\u0439","\u043C\u043E\u0439","\u043C\u043E\u044F","\u043C\u043E\u0438","\u0432\u0430\u0448","\u0432\u0430\u0448\u0430","\u0432\u0430\u0448\u0438","\u043E\u043D","\u043E\u043D\u0430","\u043E\u043D\u0438","\u043C\u044B","\u0432\u044B","\u044F","\u0442\u044B","\u0442\u043E\u0442","\u0442\u0430","\u0442\u0435","\u043E\u0447\u0435\u043D\u044C","\u0442\u043E\u0436\u0435","\u0442\u0430\u043A\u0436\u0435","\u043A\u043E\u0433\u0434\u0430","\u0433\u0434\u0435","\u043A\u0430\u043A","\u043F\u043E\u0447\u0435\u043C\u0443","\u0437\u0430\u0447\u0435\u043C","\u0441\u0435\u0439\u0447\u0430\u0441","\u0437\u0434\u0435\u0441\u044C","\u0442\u0430\u043C","\u043F\u043E\u0442\u043E\u043C\u0443","\u043F\u043E\u044D\u0442\u043E\u043C\u0443","\u0447\u0442\u043E\u0431\u044B","\u0442\u0443\u0442","bir","bu","\u015Fu","o","ve","ile","de","da","i\xE7in","gibi","ama","fakat","ancak","ya","ne","ki","mi","m\u0131","mu","m\xFC","var","yok","olan","oldu","olur","olarak","ise","daha","\xE7ok","en","her","hi\xE7","baz\u0131","t\xFCm","b\xFCt\xFCn","hem","veya","bu","\u015Fu","ben","sen","biz","siz","onlar","benim","senin","nas\u0131l","neden","ni\xE7in","nerede","ne","hangi","ka\xE7","w","na","z","do","si\u0119","\u017Ce","to","jest","i","a","nie","tak","jak","czy","po","o","ale","go","mu","jej","ich","tego","tej","te","ten","ta","s\u0105","by\u0142","by\u0142a","by\u0142o","byli","b\u0119dzie","b\u0119d\u0105","ma","mam","masz","maj\u0105","ze","co","ju\u017C","przez","przy","za","bez","nad","pod","przed","po","mi\u0119dzy","kiedy","gdzie","dlaczego","kt\xF3ry","kt\xF3ra","kt\xF3re","tylko","te\u017C","v","na","z","do","se","\u017Ee","to","je","a","ne","pro","ale","jak","by","byl","b\xFDt","jsem","jsou","m\xE1","m\xE1m","ten","ta","ty","tato","jeho","jej\xED","jejich","tak\xE9","jen","kde","kdy","pro\u010D","kter\xFD","kter\xE1","kter\xE9","co","p\u0159i","bez","\u098F\u0987","\u098F\u099F\u09BF","\u098F\u099F\u09BE","\u098F\u09B0","\u09A4\u09BE\u09B0","\u09A4\u09BE\u09B0\u09BE","\u0986\u09AE\u09BF","\u09A4\u09C1\u09AE\u09BF","\u09B8\u09C7","\u0986\u09AE\u09B0\u09BE","\u098F\u09AC\u0982","\u0995\u09BF\u09A8\u09CD\u09A4\u09C1","\u09AC\u09BE","\u09A8\u09BE","\u09B9\u09CD\u09AF\u09BE\u0981","\u09AF\u09C7","\u0995\u09BF","\u0995\u09C7","\u0995\u09C0","\u09A5\u09C7\u0995\u09C7","\u09A6\u09BF\u09AF\u09BC\u09C7","\u099C\u09A8\u09CD\u09AF","\u09B8\u09BE\u09A5\u09C7","\u09AE\u09A7\u09CD\u09AF\u09C7","\u0989\u09AA\u09B0","\u09A8\u09BF\u099A\u09C7","\u0986\u099B\u09C7","\u099B\u09BF\u09B2","\u09B9\u09AF\u09BC","\u0995\u09B0\u09BE","\u0995\u09B0\u09C7","\u0995\u09B0\u09C7\u099B\u09C7","\u09B9\u09AC\u09C7","\u09B9\u09AF\u09BC\u09C7\u099B\u09C7","\u098F\u0995\u099F\u09BF","\u098F\u0995\u099F\u09BE","\u0985\u09A8\u09C7\u0995","\u09B8\u09AC","t\xF4i","b\u1EA1n","anh","ch\u1ECB","em","h\u1ECD","ch\xFAng","ta","m\xECnh","l\xE0","c\xF3","kh\xF4ng","v\xE0","v\u1EDBi","c\u1EE7a","cho","trong","v\u1EC1","t\u1EEB","\u0111\u1EBFn","\u0111\u1EC3","khi","n\u1EBFu","th\xEC","m\xE0","nh\u01B0ng","v\xEC","\u0111\xE2y","\u0111\xF3","n\xE0y","kia","r\u1EA5t","c\u0169ng","\u0111\xE3","s\u1EBD","\u0111ang","\u0111\u01B0\u1EE3c","b\u1ECB","nh\u1EEFng","c\xE1c","m\u1ED9t","hai","ba","nhi\u1EC1u","\xEDt","n\xE0o","ai","g\xEC","\u0111\xE2u","sao","bao","gi\u1EDD","l\xFAc","sau"]),T=/[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]/,he=/([\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+|[^\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uac00-\ud7af]+)/g,M=/[\u0590-\u05ff\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb1d-\ufb4f\ufb50-\ufdff\ufe70-\ufeff]/,C=/[\u0590-\u05ff\ufb1d-\ufb4f]/,Se=/[\u0600-\u06ff\u0750-\u077f\u08a0-\u08ff\ufb50-\ufdff\ufe70-\ufeff]/,F=/[\u067e\u0686\u0698\u06af\u06cc]/,O=/[\u0900-\u097f]/,P=/[\u0400-\u04ff]/,$=/[\u011f\u015f\u0131\u0130\u00e7]/,U=/[\u0980-\u09ff]/,Ee=/[\u1ea0-\u1ef9]/,de=[["\u30D5\u30A1","fa"],["\u30D5\u30A3","fi"],["\u30D5\u30A7","fe"],["\u30D5\u30A9","fo"],["\u30C6\u30A3","ti"],["\u30C7\u30A3","di"],["\u30C8\u30A5","tu"],["\u30C9\u30A5","du"],["\u30A6\u30A3","wi"],["\u30A6\u30A7","we"],["\u30A6\u30A9","wo"],["\u30C1\u30A7","che"],["\u30B8\u30A7","je"],["\u30B7\u30A7","she"],["\u30A4\u30A7","ye"],["\u30F4\u30A1","va"],["\u30F4\u30A3","vi"],["\u30F4\u30A7","ve"],["\u30F4\u30A9","vo"],["\u30AD\u30E3","kya"],["\u30AD\u30E5","kyu"],["\u30AD\u30E7","kyo"],["\u30B7\u30E3","sha"],["\u30B7\u30E5","shu"],["\u30B7\u30E7","sho"],["\u30C1\u30E3","cha"],["\u30C1\u30E5","chu"],["\u30C1\u30E7","cho"],["\u30CB\u30E3","nya"],["\u30CB\u30E5","nyu"],["\u30CB\u30E7","nyo"],["\u30D2\u30E3","hya"],["\u30D2\u30E5","hyu"],["\u30D2\u30E7","hyo"],["\u30DF\u30E3","mya"],["\u30DF\u30E5","myu"],["\u30DF\u30E7","myo"],["\u30EA\u30E3","rya"],["\u30EA\u30E5","ryu"],["\u30EA\u30E7","ryo"],["\u30AE\u30E3","gya"],["\u30AE\u30E5","gyu"],["\u30AE\u30E7","gyo"],["\u30B8\u30E3","ja"],["\u30B8\u30E5","ju"],["\u30B8\u30E7","jo"],["\u30D3\u30E3","bya"],["\u30D3\u30E5","byu"],["\u30D3\u30E7","byo"],["\u30D4\u30E3","pya"],["\u30D4\u30E5","pyu"],["\u30D4\u30E7","pyo"],["\u30A2","a"],["\u30A4","i"],["\u30A6","u"],["\u30A8","e"],["\u30AA","o"],["\u30AB","ka"],["\u30AD","ki"],["\u30AF","ku"],["\u30B1","ke"],["\u30B3","ko"],["\u30B5","sa"],["\u30B7","shi"],["\u30B9","su"],["\u30BB","se"],["\u30BD","so"],["\u30BF","ta"],["\u30C1","chi"],["\u30C4","tsu"],["\u30C6","te"],["\u30C8","to"],["\u30CA","na"],["\u30CB","ni"],["\u30CC","nu"],["\u30CD","ne"],["\u30CE","no"],["\u30CF","ha"],["\u30D2","hi"],["\u30D5","fu"],["\u30D8","he"],["\u30DB","ho"],["\u30DE","ma"],["\u30DF","mi"],["\u30E0","mu"],["\u30E1","me"],["\u30E2","mo"],["\u30E4","ya"],["\u30E6","yu"],["\u30E8","yo"],["\u30E9","ra"],["\u30EA","ri"],["\u30EB","ru"],["\u30EC","re"],["\u30ED","ro"],["\u30EF","wa"],["\u30F2","wo"],["\u30F3","n"],["\u30AC","ga"],["\u30AE","gi"],["\u30B0","gu"],["\u30B2","ge"],["\u30B4","go"],["\u30B6","za"],["\u30B8","ji"],["\u30BA","zu"],["\u30BC","ze"],["\u30BE","zo"],["\u30C0","da"],["\u30C2","ji"],["\u30C5","zu"],["\u30C7","de"],["\u30C9","do"],["\u30D0","ba"],["\u30D3","bi"],["\u30D6","bu"],["\u30D9","be"],["\u30DC","bo"],["\u30D1","pa"],["\u30D4","pi"],["\u30D7","pu"],["\u30DA","pe"],["\u30DD","po"],["\u30F4","v"],["\u30FC",""],["\u30A1","a"],["\u30A3","i"],["\u30A5","u"],["\u30A7","e"],["\u30A9","o"],["\u30C3",""]],A=new Map(de);function Z(t){let e="",o=0;for(;o<t.length;){if(t[o]==="\u30C3"&&o+1<t.length){const m=A.get(t[o+1])??A.get(t[o+1]+t[o+2])??"";m.length>0&&(e+=m[0]),o++;continue}if(o+1<t.length){const m=t[o]+t[o+1],u=A.get(m);if(u!==void 0){e+=u,o+=2;continue}}const a=A.get(t[o]);a!==void 0&&(e+=a),o++}return e}function N(t){let e=t;for(let o=0;o<3;o++){const a=e;if(e.startsWith("\u0627\u0644")&&e.length>4?e=e.slice(2):e.length>3&&"\u0648\u0628\u0644\u0641\u0643".includes(e[0])&&M.test(e[1])&&(e=e.slice(1)),e===a)break}return e}function K(t){let e=t;for(let o=0;o<3;o++){const a=e;if(e.length>3&&"\u05D4\u05D5\u05D1\u05DC\u05DE\u05DB".includes(e[0])&&C.test(e[1])&&(e=e.slice(1)),e===a)break}return e}function G(t){let e=t;return e.endsWith("\u0647\u0627\u06CC")&&e.length>5?e=e.slice(0,-3):e.endsWith("\u0647\u0627")&&e.length>4&&(e=e.slice(0,-2)),e.startsWith("\u0646\u0645\u06CC\u200C")&&e.length>5?e=e.slice(4):e.startsWith("\u0645\u06CC\u200C")&&e.length>4?e=e.slice(3):e.startsWith("\u0645\u06CC")&&e.length>4&&(e=e.slice(2)),e}function Y(t){const e=t;return e.endsWith("\u0928\u093E")&&e.length>4||e.endsWith("\u0928\u0947")&&e.length>4||e.endsWith("\u0928\u0940")&&e.length>4||e.endsWith("\u0924\u093E")&&e.length>4||e.endsWith("\u0924\u0940")&&e.length>4||e.endsWith("\u0915\u0930")&&e.length>4||e.endsWith("\u0913\u0902")&&e.length>4?e.slice(0,-2):e.endsWith("\u0907\u092F\u093E\u0902")&&e.length>5||e.endsWith("\u0940\u092F\u093E\u0902")&&e.length>5?e.slice(0,-4):e}function V(t){const e=t;return e.endsWith("\u044B\u0432\u0430\u043D\u0438\u0435")&&e.length>7||e.endsWith("\u0438\u0432\u0430\u043D\u0438\u0435")&&e.length>7||e.endsWith("\u043E\u0432\u0430\u043D\u0438\u0435")&&e.length>7?e.slice(0,-6):e.endsWith("\u0432\u0430\u043D\u0438\u0435")&&e.length>6?e.slice(0,-5):e.endsWith("\u0435\u043D\u0438\u0435")&&e.length>5||e.endsWith("\u0430\u043D\u0438\u0435")&&e.length>5?e.slice(0,-4):e.endsWith("\u0438\u0442\u044C")&&e.length>4||e.endsWith("\u0430\u0442\u044C")&&e.length>4||e.endsWith("\u0435\u0442\u044C")&&e.length>4||e.endsWith("\u0443\u0442\u044C")&&e.length>4?e.slice(0,-3):e.endsWith("\u043A\u0438")&&e.length>4||e.endsWith("\u0433\u0438")&&e.length>4||e.endsWith("\u043E\u0432")&&e.length>4||e.endsWith("\u0435\u0432")&&e.length>4||e.endsWith("\u0435\u0439")&&e.length>4||e.endsWith("\u0438\u0439")&&e.length>4||e.endsWith("\u044B\u0439")&&e.length>4||e.endsWith("\u0430\u044F")&&e.length>4||e.endsWith("\u043E\u0435")&&e.length>4||e.endsWith("\u0443\u044E")&&e.length>4||e.endsWith("\u0435\u0442")&&e.length>4||e.endsWith("\u044E\u0442")&&e.length>4||e.endsWith("\u0443\u0442")&&e.length>4||e.endsWith("\u044F\u0442")&&e.length>4?e.slice(0,-2):e}function Q(t){const e=t;return e.endsWith("lardaki")&&e.length>7||e.endsWith("lerdeki")&&e.length>7?e.slice(0,-7):e.endsWith("lar\u0131n")&&e.length>6||e.endsWith("lerin")&&e.length>6||e.endsWith("larda")&&e.length>6||e.endsWith("lerde")&&e.length>6?e.slice(0,-5):e.endsWith("lar\u0131")&&e.length>5||e.endsWith("leri")&&e.length>5?e.slice(0,-4):e.endsWith("mek")&&e.length>4||e.endsWith("mak")&&e.length>4||e.endsWith("ler")&&e.length>4||e.endsWith("lar")&&e.length>4||e.endsWith("n\u0131n")&&e.length>4||e.endsWith("nin")&&e.length>4||e.endsWith("nun")&&e.length>4||e.endsWith("n\xFCn")&&e.length>4?e.slice(0,-3):e.endsWith("da")&&e.length>4||e.endsWith("de")&&e.length>4||e.endsWith("ta")&&e.length>4||e.endsWith("te")&&e.length>4?e.slice(0,-2):e.endsWith("dan")&&e.length>4||e.endsWith("den")&&e.length>4||e.endsWith("tan")&&e.length>4||e.endsWith("ten")&&e.length>4?e.slice(0,-3):e.endsWith("\u0131n")&&e.length>4||e.endsWith("in")&&e.length>4||e.endsWith("un")&&e.length>4||e.endsWith("\xFCn")&&e.length>4?e.slice(0,-2):e.endsWith("\u0131")&&e.length>4||e.endsWith("i")&&e.length>4||e.endsWith("u")&&e.length>4||e.endsWith("\xFC")&&e.length>4?e.slice(0,-1):e}function J(t){const e=t;return e.endsWith("\u0997\u09C1\u09B2\u09CB")&&e.length>5||e.endsWith("\u0997\u09C1\u09B2\u09BF")&&e.length>5?e.slice(0,-4):e.endsWith("\u09A6\u09C7\u09B0")&&e.length>4?e.slice(0,-3):e.endsWith("\u09A6\u09BF\u0997\u09C7")&&e.length>5?e.slice(0,-4):e.endsWith("\u099F\u09BF")&&e.length>3||e.endsWith("\u099F\u09BE")&&e.length>3?e.slice(0,-2):e.endsWith("\u0996\u09BE\u09A8\u09BE")&&e.length>5?e.slice(0,-4):e.endsWith("\u099B\u09C7")&&e.length>3?e.slice(0,-2):e.endsWith("\u099B\u09BF\u09B2")&&e.length>4?e.slice(0,-3):e.endsWith("\u09AF\u09BE\u09AC\u09C7")&&e.length>5?e.slice(0,-4):e.endsWith("\u0995\u09B0\u09BE")&&e.length>4||e.endsWith("\u0995\u09B0\u09C7")&&e.length>4?e.slice(0,-3):e.endsWith("\u09B9\u09DF")&&e.length>3?e.slice(0,-2):e.endsWith("\u09B9\u09AC\u09C7")&&e.length>4?e.slice(0,-3):e}function ge(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/([A-Z]{2,})([A-Z][a-z])/g,"$1 $2").replace(/_/g," ")}import{ohneUmlaute as R,deutscherStamm as fe,ohneRueckumlaut as me,zerlegeKompositum as pe,DEUTSCHE_FACHWOERTER as be}from"./deutsch.js";const j=new Map([["javascript",["js","node","nodejs","ecmascript"]],["js",["javascript","node","nodejs"]],["typescript",["ts","javascript","js","tsc"]],["ts",["typescript","javascript","js"]],["python",["py","pip","django","flask","fastapi"]],["py",["python","pip"]],["golang",["go","gopher","goroutine"]],["go",["golang","goroutine"]],["rust",["cargo","rustlang","crates"]],["cargo",["rust","rustlang"]],["java",["jvm","maven","gradle","spring"]],["kotlin",["jvm","android","coroutine"]],["dotnet",["csharp","asp","nuget","aspnet"]],["postgresql",["postgres","pg","psql"]],["postgres",["postgresql","pg","psql"]],["mysql",["mariadb","sql"]],["mongodb",["mongo","nosql","bson","mongoose"]],["mongo",["mongodb","nosql","bson"]],["elasticsearch",["elastic","opensearch","lucene","kibana"]],["elastic",["elasticsearch","opensearch"]],["kubernetes",["k8s","kube","kubectl","helm","k3s"]],["k8s",["kubernetes","kube","kubectl","helm"]],["helm",["kubernetes","k8s","chart"]],["terraform",["tf","hcl","iac","opentofu"]],["ansible",["playbook","automation"]],["grafana",["dashboard","visualization","metrics"]],["prometheus",["metrics","alert","scrape","grafana"]],["nginx",["proxy","webserver","ingress"]],["traefik",["proxy","ingress","router"]],["rabbitmq",["amqp","queue","broker","messaging"]],["kafka",["messaging","stream","broker"]],["grpc",["protobuf","proto","rpc"]],["graphql",["gql","resolver","schema"]],["react",["jsx","hooks","component","redux"]],["nextjs",["next","react","ssr","vercel"]],["vue",["vuejs","vite","nuxt"]],["angular",["ng","rxjs","typescript"]],["aws",["amazon","ec2","s3","lambda","cloudwatch","ecs","eks"]],["gcp",["google cloud","gke","bigquery"]],["azure",["microsoft cloud","aks","devops"]],["s3",["bucket","object storage","aws"]],["lambda",["serverless","function","faas","aws"]],["jwt",["token","bearer","oauth","auth"]],["oauth",["oidc","auth","token","sso"]],["webhook",["callback","event","trigger"]],["cron",["schedule","job","timer"]],["yaml",["yml","config","manifest"]],["dotenv",["env","environment","envfile"]],["github",["git","actions","repo","ci"]],["gitlab",["git","pipeline","runner"]],["wireguard",["vpn","tunnel","wg"]],["prisma",["orm","database","schema","migration"]],["npm",["node","package","registry","yarn","pnpm"]],["yarn",["npm","package","node"]],["pip",["python","package","pypi"]],["brew",["homebrew","macos","package"]],["deploy",["\u30C7\u30D7\u30ED\u30A4","\u90E8\u7F72","\uBC30\uD3EC","deployment","deploying","\u0646\u0634\u0631","\u05E4\u05E8\u05D9\u05E1\u05D4","\u0627\u0633\u062A\u0642\u0631\u0627\u0631","\u0924\u0948\u0928\u093E\u0924\u0940","bereitstellen","bereitstellung","d\xE9ployer","d\xE9ploiement","desplegar","despliegue","distribuire","distribuzione","implantar","implanta\xE7\xE3o","\u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435","\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435","da\u011F\u0131t\u0131m","da\u011F\u0131tmak","tri\u1EC3n khai"]],["deployment",["\u30C7\u30D7\u30ED\u30A4","\u90E8\u7F72","\uBC30\uD3EC","deploy","\u0646\u0634\u0631","\u05E4\u05E8\u05D9\u05E1\u05D4","\u0627\u0633\u062A\u0642\u0631\u0627\u0631","\u0924\u0948\u0928\u093E\u0924\u0940","bereitstellung","d\xE9ploiement","despliegue","distribuzione","implanta\xE7\xE3o","\u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435","da\u011F\u0131t\u0131m","tri\u1EC3n khai"]],["container",["\u30B3\u30F3\u30C6\u30CA","\u5BB9\u5668","\uCEE8\uD14C\uC774\uB108","docker"]],["server",["\u30B5\u30FC\u30D0\u30FC","\u30B5\u30FC\u30D0","\u670D\u52A1\u5668","\uC11C\uBC84","\u0633\u064A\u0631\u0641\u0631","\u05E9\u05E8\u05EA","\u0633\u0631\u0648\u0631","\u0938\u0930\u094D\u0935\u0930","\u0441\u0435\u0440\u0432\u0435\u0440","sunucu","m\xE1y ch\u1EE7"]],["database",["\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9","\u6570\u636E\u5E93","\uB370\uC774\uD130\uBCA0\uC774\uC2A4","db","\u0642\u0627\u0639\u062F\u0629 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A","datenbank","\u067E\u0627\u06CC\u06AF\u0627\u0647 \u062F\u0627\u062F\u0647","\u0921\u0947\u091F\u093E\u092C\u0947\u0633","base de donn\xE9es","base de datos","banco de dados"]],["cache",["\u30AD\u30E3\u30C3\u30B7\u30E5","\u7F13\u5B58","\uCE90\uC2DC","\u0643\u0627\u0634","\u05DE\u05D8\u05DE\u05D5\u05DF","\u06A9\u0634","\u0915\u0948\u0936","\u043A\u044D\u0448","\xF6nbellek","b\u1ED9 \u0111\u1EC7m"]],["error",["\u30A8\u30E9\u30FC","\u9519\u8BEF","\uC624\uB958","\u062E\u0637\u0623","\u05E9\u05D2\u05D9\u05D0\u05D4","\u062E\u0637\u0627","\u0924\u094D\u0930\u0941\u091F\u093F","\u0917\u0932\u0924\u0940","exception","err","fehler","erreur","fallo","errore","erro","\u043E\u0448\u0438\u0431\u043A\u0430","hata","hatal\u0131","l\u1ED7i"]],["bug",["\u30D0\u30B0","\u7F3A\u9677","\uBC84\uADF8","issue","defect","\u062E\u0644\u0644","\u0627\u0634\u06A9\u0627\u0644","\u092C\u0917"]],["fix",["\u4FEE\u6B63","\u4FEE\u590D","\uC218\uC815","bugfix","patch","hotfix","\u0625\u0635\u0644\u0627\u062D","\u05EA\u05D9\u05E7\u05D5\u05DF","\u0631\u0641\u0639","\u0938\u0941\u0927\u093E\u0930","beheben","behoben","r\xE9parer","correction","arreglar","correcci\xF3n","correggere","corrigir","\u0438\u0441\u043F\u0440\u0430\u0432\u0438\u0442\u044C","\u0438\u0441\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435","d\xFCzeltmek","d\xFCzeltme"]],["build",["\u30D3\u30EB\u30C9","\u6784\u5EFA","\uBE4C\uB4DC","\u0628\u0646\u0627\u0621","\u05D1\u05E0\u05D9\u05D9\u05D4","\u0633\u0627\u062E\u062A","\u0928\u093F\u0930\u094D\u092E\u093E\u0923","bauen","construire","construir","costruire","\u0441\u0431\u043E\u0440\u043A\u0430","\u0441\u043E\u0431\u0440\u0430\u0442\u044C","derleme","derlemek"]],["test",["\u30C6\u30B9\u30C8","\u6D4B\u8BD5","\uD14C\uC2A4\uD2B8","\u0627\u062E\u062A\u0628\u0627\u0631","\u05D1\u05D3\u05D9\u05E7\u05D4","\u0622\u0632\u0645\u0627\u06CC\u0634","\u092A\u0930\u0940\u0915\u094D\u0937\u0923","testen","tester","probar","testare","testar","\u0442\u0435\u0441\u0442","\u0442\u0435\u0441\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435","test","testlemek"]],["auth",["\u8A8D\u8A3C","\u8BA4\u8BC1","\uC778\uC99D","authentication","login","oauth","\u0645\u0635\u0627\u062F\u0642\u0629","\u05D0\u05D9\u05DE\u05D5\u05EA","\u0627\u062D\u0631\u0627\u0632 \u0647\u0648\u06CC\u062A","\u092A\u094D\u0930\u092E\u093E\u0923\u0940\u0915\u0930\u0923","authentifizierung","authentification","autenticaci\xF3n","autenticazione","autentica\xE7\xE3o","\u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F","\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F","kimlik do\u011Frulama","yetkilendirme"]],["authentication",["auth","\u0645\u0635\u0627\u062F\u0642\u0629","\u05D0\u05D9\u05DE\u05D5\u05EA","\u0627\u062D\u0631\u0627\u0632 \u0647\u0648\u06CC\u062A","\u092A\u094D\u0930\u092E\u093E\u0923\u0940\u0915\u0930\u0923","\u8A8D\u8A3C","\u8BA4\u8BC1","\uC778\uC99D","login","oauth","\u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F","\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F","kimlik do\u011Frulama"]],["environment",["\u74B0\u5883","\u73AF\u5883","\uD658\uACBD","env","\u0628\u064A\u0626\u0629","\u05E1\u05D1\u05D9\u05D1\u05D4","umgebung","environnement","entorno","ambiente","\u0441\u0440\u0435\u0434\u0430","\u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435","ortam"]],["secret",["key","token","password","jwt","\u0645\u0641\u062A\u0627\u062D","\u05DE\u05E4\u05EA\u05D7","geheimnis","schl\xFCssel","clave","cl\xE9","chiave","chave","\u0441\u0435\u043A\u0440\u0435\u0442","\u043A\u043B\u044E\u0447","gizli","anahtar"]],["problem",["error","issue","bug","failure","\u0645\u0634\u0643\u0644\u0629","\u554F\u984C","\uC624\uB958","fehler","probl\xE8me","problema","\u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430","\u043E\u0448\u0438\u0431\u043A\u0430","sorun","problem"]],["kubernetes",["\u30AF\u30D9\u30EB\u30CD\u30C6\u30B9","k8s","kube"]],["network",["\u30CD\u30C3\u30C8\u30EF\u30FC\u30AF","\u7F51\u7EDC","\uB124\uD2B8\uC6CC\uD06C","\u0634\u0628\u0643\u0629","\u05E8\u05E9\u05EA","\u0634\u0628\u06A9\u0647","\u0928\u0947\u091F\u0935\u0930\u094D\u0915","netzwerk","r\xE9seau","red","rete","rede","\u0441\u0435\u0442\u044C","a\u011F"]],["timeout",["\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8","\u8D85\u65F6","\uD0C0\uC784\uC544\uC6C3","\u0645\u0647\u0644\u0629"]],["memory",["\u30E1\u30E2\u30EA","\u5185\u5B58","\uBA54\uBAA8\uB9AC","ram","\u0630\u0627\u0643\u0631\u0629","\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF","\u062D\u0627\u0641\u0638\u0647","\u092E\u0947\u092E\u094B\u0930\u0940","speicher","m\xE9moire","memoria","mem\xF3ria","\u043F\u0430\u043C\u044F\u0442\u044C","bellek","haf\u0131za"]],["config",["\u8A2D\u5B9A","\u914D\u7F6E","\uC124\uC815","configuration","settings","conf","\u0625\u0639\u062F\u0627\u062F\u0627\u062A","\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA","\u067E\u06CC\u06A9\u0631\u0628\u0646\u062F\u06CC","\u0915\u0949\u0928\u094D\u092B\u093C\u093F\u0917","konfiguration","einstellungen","configuraci\xF3n","configurazione","configura\xE7\xE3o","\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F","\u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438","yap\u0131land\u0131rma","ayarlar"]],["install",["\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB","\u5B89\u88C5","\uC124\uCE58","\u062A\u062B\u0628\u064A\u062A","\u05D4\u05EA\u05E7\u05E0\u05D4","\u0646\u0635\u0628","\u0907\u0902\u0938\u094D\u091F\u0949\u0932","installieren","installer","instalar","installare","\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C","\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430","y\xFCklemek","kurulum"]],["update",["\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8","\u66F4\u65B0","\uC5C5\uB370\uC774\uD2B8","upgrade","\u062A\u062D\u062F\u064A\u062B","\u05E2\u05D3\u05DB\u05D5\u05DF","\u0628\u0647\u200C\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06CC","\u0905\u092A\u0921\u0947\u091F","aktualisieren","aktualisierung","actualizar","aggiornare","atualizar","\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435","\u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C","g\xFCncelleme"]],["log",["\u30ED\u30B0","\u65E5\u5FD7","\uB85C\uADF8","logging","\u0633\u062C\u0644","\u05D9\u05D5\u05DE\u05DF","\u062B\u0628\u062A","\u0932\u0949\u0917","protokoll","protokolle","journal","registro","\u0436\u0443\u0440\u043D\u0430\u043B","\u043B\u043E\u0433","g\xFCnl\xFCk"]],["port",["\u30DD\u30FC\u30C8","\u7AEF\u53E3","\uD3EC\uD2B8","\u0645\u0646\u0641\u0630","\u05E4\u05D5\u05E8\u05D8"]],["file",["\u30D5\u30A1\u30A4\u30EB","\u6587\u4EF6","\uD30C\uC77C","\u0645\u0644\u0641","\u05E7\u05D5\u05D1\u05E5"]],["image",["\u30A4\u30E1\u30FC\u30B8","\u955C\u50CF","\uC774\uBBF8\uC9C0","\u0635\u0648\u0631\u0629","\u05EA\u05DE\u05D5\u05E0\u05D4","abbild","imagen","imagem"]],["volume",["\u30DC\u30EA\u30E5\u30FC\u30E0","\u5377","\uBCFC\uB968"]],["cluster",["\u30AF\u30E9\u30B9\u30BF\u30FC","\u96C6\u7FA4","\uD074\uB7EC\uC2A4\uD130"]],["node",["\u30CE\u30FC\u30C9","\u8282\u70B9","\uB178\uB4DC"]],["service",["\u30B5\u30FC\u30D3\u30B9","\u670D\u52A1","\uC11C\uBE44\uC2A4","svc","\u062E\u062F\u0645\u0629","\u05E9\u05D9\u05E8\u05D5\u05EA","dienst","servicio","servizio","servi\xE7o","\u0441\u0435\u0440\u0432\u0438\u0441","\u0441\u043B\u0443\u0436\u0431\u0430","servis","hizmet"]],["certificate",["\u8A3C\u660E\u66F8","\u8BC1\u4E66","\uC778\uC99D\uC11C","cert","ssl","tls","\u0634\u0647\u0627\u062F\u0629","\u05EA\u05E2\u05D5\u05D3\u05D4"]],["password",["\u30D1\u30B9\u30EF\u30FC\u30C9","\u5BC6\u7801","\uBE44\uBC00\uBC88\uD638","passwd","pwd","\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631","\u05E1\u05D9\u05E1\u05DE\u05D4"]],["token",["\u30C8\u30FC\u30AF\u30F3","\u4EE4\u724C","\uD1A0\uD070","jwt","secret","\u0631\u0645\u0632","\u05D0\u05E1\u05D9\u05DE\u05D5\u05DF"]],["health",["\u30D8\u30EB\u30B9","\u5065\u5EB7","\uD5EC\uC2A4","healthcheck","probe","\u0635\u062D\u0629"]],["migration",["\u30DE\u30A4\u30B0\u30EC\u30FC\u30B7\u30E7\u30F3","\u8FC1\u79FB","\uB9C8\uC774\uADF8\uB808\uC774\uC158","migrate","\u0647\u062C\u0631\u0629"]],["backup",["\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7","\u5907\u4EFD","\uBC31\uC5C5","\u0646\u0633\u062E \u0627\u062D\u062A\u064A\u0627\u0637\u064A","\u05D2\u05D9\u05D1\u05D5\u05D9","\u067E\u0634\u062A\u06CC\u0628\u0627\u0646\u200C\u06AF\u06CC\u0631\u06CC","\u092C\u0948\u0915\u0905\u092A","sicherung","sauvegarde","respaldo","c\xF3pia de seguran\xE7a","\u0440\u0435\u0437\u0435\u0440\u0432\u043D\u0430\u044F \u043A\u043E\u043F\u0438\u044F","\u0440\u0435\u0437\u0435\u0440\u0432","yedekleme"]],["monitor",["\u30E2\u30CB\u30BF\u30FC","\u76D1\u63A7","\uBAA8\uB2C8\uD130\uB9C1","monitoring","metrics","alert","\u0645\u0631\u0627\u0642\u0628\u0629","\u05E0\u05D9\u05D8\u05D5\u05E8","\u0646\u0638\u0627\u0631\u062A","\u0928\u093F\u0917\u0930\u093E\u0928\u0940","\xFCberwachung","surveiller","monitoreo","monitorare","monitorar","\u043C\u043E\u043D\u0438\u0442\u043E\u0440\u0438\u043D\u0433","\u043D\u0430\u0431\u043B\u044E\u0434\u0435\u043D\u0438\u0435","izleme"]],["performance",["\u30D1\u30D5\u30A9\u30FC\u30DE\u30F3\u30B9","\u6027\u80FD","\uC131\uB2A5","latency","throughput","\u0639\u0645\u0644\u06A9\u0631\u062F","\u092A\u094D\u0930\u0926\u0930\u094D\u0936\u0928","leistung","performances","rendimiento","prestazioni","desempenho","\u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C","\u0431\u044B\u0441\u0442\u0440\u043E\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435","performans"]],["connection",["\u63A5\u7D9A","\u8FDE\u63A5","\uC5F0\uACB0","conn","socket","\u0627\u062A\u0635\u0627\u0644","\u05D7\u05D9\u05D1\u05D5\u05E8","\u0627\u062A\u0635\u0627\u0644","\u0915\u0928\u0947\u0915\u094D\u0936\u0928","verbindung","connexion","conexi\xF3n","connessione","conex\xE3o"]],["queue",["\u30AD\u30E5\u30FC","\u961F\u5217","\uD050","\u0637\u0627\u0628\u0648\u0631","warteschlange","file d'attente","cola","coda","fila"]],["redis",["\u30EC\u30C7\u30A3\u30B9","\uB808\uB514\uC2A4"]],["nginx",["\u30A8\u30F3\u30B8\u30F3\u30A8\u30C3\u30AF\u30B9"]],["linux",["\u30EA\u30CA\u30C3\u30AF\u30B9","\u0644\u064A\u0646\u0643\u0633"]],["api",["\u30A8\u30FC\u30D4\u30FC\u30A2\u30A4","\u63A5\u53E3","endpoint","\u0648\u0627\u062C\u0647\u0629 \u0628\u0631\u0645\u062C\u064A\u0629","\u05DE\u05DE\u05E9\u05E7"]],["healthcheck",["\u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF","health","probe","\u0641\u062D\u0635 \u0627\u0644\u0635\u062D\u0629"]],["loadbalancer",["\u30ED\u30FC\u30C9\u30D0\u30E9\u30F3\u30B5\u30FC","\u8D1F\u8F7D\u5747\u8861","\uB85C\uB4DC\uBC38\uB7F0\uC11C","lb"]],["ssl",["tls","https","certificate","cert"]],["tls",["ssl","https","certificate","cert"]],["docker",["container","\u30B3\u30F3\u30C6\u30CA","\u5BB9\u5668","\uCEE8\uD14C\uC774\uB108","\u062F\u0648\u0643\u0631"]],["git",["version control","repo","repository","commit","push","pull"]],["ci",["pipeline","github actions","gitlab","jenkins","build"]],["cd",["deploy","deployment","release"]],["debug",["\u30C7\u30D0\u30C3\u30B0","\u8C03\u8BD5","\uB514\uBC84\uADF8","debugging","breakpoint","\u062A\u0635\u062D\u064A\u062D","\u05D0\u05D9\u05EA\u05D5\u05E8 \u05D1\u05D0\u05D2\u05D9\u05DD","\u0627\u0634\u06A9\u0627\u0644\u200C\u0632\u062F\u0627\u06CC\u06CC","\u0921\u0940\u092C\u0917","debuggen","d\xE9boguer","depurar","\u043E\u0442\u043B\u0430\u0434\u043A\u0430","\u0434\u0435\u0431\u0430\u0433","hata ay\u0131klama"]],["crash",["\u30AF\u30E9\u30C3\u30B7\u30E5","\u5D29\u6E83","\uD06C\uB798\uC2DC","panic","segfault","\u0627\u0646\u0647\u064A\u0627\u0631","\u05E7\u05E8\u05D9\u05E1\u05D4","\u062E\u0631\u0627\u0628\u06CC","\u0915\u094D\u0930\u0948\u0936","absturz","panne","plantage","ca\xEDda","falha","\u0441\u0431\u043E\u0439","\u043A\u0440\u044D\u0448","\xE7\xF6kme","\xE7\xF6k\xFC\u015F"]],["restart",["\u518D\u8D77\u52D5","\u91CD\u542F","\uC7AC\uC2DC\uC791","reboot","\u0625\u0639\u0627\u062F\u0629 \u062A\u0634\u063A\u064A\u0644","\u05D4\u05E4\u05E2\u05DC\u05D4 \u05DE\u05D7\u05D3\u05E9","\u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u0645\u062C\u062F\u062F","\u092A\u0941\u0646\u0930\u093E\u0930\u0902\u092D","neustart","red\xE9marrer","reiniciar","riavviare"]],["permission",["\u6A29\u9650","\u6743\u9650","\uAD8C\uD55C","access","acl","chmod","\u0635\u0644\u0627\u062D\u064A\u0629","\u05D4\u05E8\u05E9\u05D0\u05D4","\u0645\u062C\u0648\u0632","\u0905\u0928\u0941\u092E\u0924\u093F","berechtigung","berechtigungen","permiso","permesso","permiss\xE3o","\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435","\u0434\u043E\u0441\u0442\u0443\u043F","izin","yetki"]],["\u30C7\u30D7\u30ED\u30A4",["deploy","deployment"]],["\u30B3\u30F3\u30C6\u30CA",["container","docker"]],["\u30B5\u30FC\u30D0\u30FC",["server"]],["\u30B5\u30FC\u30D0",["server"]],["\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9",["database","db"]],["\u30AD\u30E3\u30C3\u30B7\u30E5",["cache"]],["\u30A8\u30E9\u30FC",["error","err"]],["\u30D0\u30B0",["bug","issue"]],["\u30D3\u30EB\u30C9",["build"]],["\u30C6\u30B9\u30C8",["test"]],["\u8A8D\u8A3C",["auth","authentication"]],["\u8A2D\u5B9A",["config","configuration"]],["\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB",["install"]],["\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8",["update","upgrade"]],["\u30ED\u30B0",["log","logs"]],["\u30DD\u30FC\u30C8",["port"]],["\u30D5\u30A1\u30A4\u30EB",["file"]],["\u30A4\u30E1\u30FC\u30B8",["image"]],["\u30AF\u30E9\u30B9\u30BF\u30FC",["cluster"]],["\u30CE\u30FC\u30C9",["node"]],["\u30B5\u30FC\u30D3\u30B9",["service"]],["\u30D1\u30B9\u30EF\u30FC\u30C9",["password"]],["\u30C8\u30FC\u30AF\u30F3",["token"]],["\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7",["backup"]],["\u30E2\u30CB\u30BF\u30FC",["monitor","monitoring"]],["\u63A5\u7D9A",["connection"]],["\u30AD\u30E5\u30FC",["queue"]],["\u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF",["healthcheck","health check","health"]],["\u30ED\u30FC\u30C9\u30D0\u30E9\u30F3\u30B5\u30FC",["loadbalancer","load balancer"]],["\u30C7\u30D0\u30C3\u30B0",["debug"]],["\u30AF\u30E9\u30C3\u30B7\u30E5",["crash","panic"]],["\u518D\u8D77\u52D5",["restart","reboot"]],["\u6A29\u9650",["permission","access"]],["\u90E8\u7F72",["deploy","deployment"]],["\u5BB9\u5668",["container","docker"]],["\u670D\u52A1\u5668",["server"]],["\u6570\u636E\u5E93",["database"]],["\u7F13\u5B58",["cache"]],["\u9519\u8BEF",["error"]],["\u4FEE\u590D",["fix","bugfix"]],["\u6784\u5EFA",["build"]],["\u6D4B\u8BD5",["test"]],["\u8BA4\u8BC1",["auth"]],["\u914D\u7F6E",["config"]],["\u5B89\u88C5",["install"]],["\u66F4\u65B0",["update"]],["\u65E5\u5FD7",["log"]],["\u7AEF\u53E3",["port"]],["\u955C\u50CF",["image"]],["\u96C6\u7FA4",["cluster"]],["\u8282\u70B9",["node"]],["\u670D\u52A1",["service"]],["\u5BC6\u7801",["password"]],["\u4EE4\u724C",["token"]],["\u5907\u4EFD",["backup"]],["\u76D1\u63A7",["monitor"]],["\u8FDE\u63A5",["connection"]],["\u961F\u5217",["queue"]],["\u6027\u80FD",["performance"]],["\u5185\u5B58",["memory"]],["\u8C03\u8BD5",["debug"]],["\u5D29\u6E83",["crash"]],["\u91CD\u542F",["restart"]],["\u6743\u9650",["permission"]],["\uBC30\uD3EC",["deploy","deployment"]],["\uCEE8\uD14C\uC774\uB108",["container"]],["\uC11C\uBC84",["server"]],["\uB370\uC774\uD130\uBCA0\uC774\uC2A4",["database"]],["\uCE90\uC2DC",["cache"]],["\uC624\uB958",["error"]],["\uC218\uC815",["fix"]],["\uBE4C\uB4DC",["build"]],["\uD14C\uC2A4\uD2B8",["test"]],["\uC778\uC99D",["auth"]],["\uC124\uC815",["config"]],["\uC124\uCE58",["install"]],["\uC5C5\uB370\uC774\uD2B8",["update"]],["\uB85C\uADF8",["log"]],["\uD3EC\uD2B8",["port"]],["\uC774\uBBF8\uC9C0",["image"]],["\uD074\uB7EC\uC2A4\uD130",["cluster"]],["\uB178\uB4DC",["node"]],["\uC11C\uBE44\uC2A4",["service"]],["\uD1A0\uD070",["token"]],["\uBC31\uC5C5",["backup"]],["\uBAA8\uB2C8\uD130\uB9C1",["monitor"]],["\uC5F0\uACB0",["connection"]],["\uD050",["queue"]],["\uC131\uB2A5",["performance"]],["\uBA54\uBAA8\uB9AC",["memory"]],["\uB514\uBC84\uADF8",["debug"]],["\uD06C\uB798\uC2DC",["crash"]],["\uC7AC\uC2DC\uC791",["restart"]],["\uAD8C\uD55C",["permission"]],["\u062E\u0637\u0623",["error"]],["\u0625\u0635\u0644\u0627\u062D",["fix"]],["\u0628\u0646\u0627\u0621",["build"]],["\u0627\u062E\u062A\u0628\u0627\u0631",["test"]],["\u0645\u0635\u0627\u062F\u0642\u0629",["auth","authentication"]],["\u0625\u0639\u062F\u0627\u062F\u0627\u062A",["config","configuration"]],["\u062A\u062B\u0628\u064A\u062A",["install"]],["\u062A\u062D\u062F\u064A\u062B",["update","upgrade"]],["\u0633\u062C\u0644",["log"]],["\u0635\u0648\u0631\u0629",["image"]],["\u062E\u062F\u0645\u0629",["service"]],["\u0646\u0633\u062E \u0627\u062D\u062A\u064A\u0627\u0637\u064A",["backup"]],["\u0645\u0631\u0627\u0642\u0628\u0629",["monitor","monitoring"]],["\u0627\u062A\u0635\u0627\u0644",["connection"]],["\u0630\u0627\u0643\u0631\u0629",["memory"]],["\u062A\u0635\u062D\u064A\u062D",["debug","debugging"]],["\u0634\u0628\u0643\u0629",["network"]],["\u0646\u0634\u0631",["deploy","deployment"]],["\u0627\u0646\u0647\u064A\u0627\u0631",["crash","panic"]],["\u0637\u0627\u0628\u0648\u0631",["queue"]],["\u0631\u0645\u0632",["token","secret"]],["\u0643\u0627\u0634",["cache"]],["\u0645\u0646\u0641\u0630",["port"]],["\u0633\u064A\u0631\u0641\u0631",["server"]],["\u0642\u0627\u0639\u062F\u0629 \u0627\u0644\u0628\u064A\u0627\u0646\u0627\u062A",["database","db"]],["\u0625\u0639\u0627\u062F\u0629 \u062A\u0634\u063A\u064A\u0644",["restart","reboot"]],["\u0635\u0644\u0627\u062D\u064A\u0629",["permission","access"]],["\u062A\u0637\u0628\u064A\u0642",["application","app"]],["\u0645\u0641\u062A\u0627\u062D",["key","token","secret"]],["\u0648\u0627\u062C\u0647\u0629 \u0628\u0631\u0645\u062C\u064A\u0629",["api","interface"]],["\u0641\u062D\u0635 \u0627\u0644\u0635\u062D\u0629",["healthcheck","health"]],["\u062D\u0627\u0648\u064A\u0629",["container","docker"]],["\u0639\u0642\u062F\u0629",["node"]],["\u0633\u0631\u0639\u0629",["performance","speed"]],["\u0642\u0631\u0635",["disk","storage"]],["\u062E\u0627\u062F\u0645",["server"]],["\u0628\u0631\u0646\u0627\u0645\u062C",["application","software","app"]],["\u0645\u0634\u0643\u0644\u0629",["error","issue","bug","problem","failure"]],["\u0628\u064A\u0626\u0629",["environment","env"]],["\u0645\u062A\u063A\u064A\u0631\u0627\u062A",["variables","env","environment"]],["\u0625\u0646\u062A\u0627\u062C",["production","prod"]],["\u0633\u0631\u064A",["secret","key","token"]],["\u0645\u0641\u062A\u0627\u062D \u0633\u0631\u064A",["secret","key"]],["\u05E9\u05D2\u05D9\u05D0\u05D4",["error"]],["\u05EA\u05D9\u05E7\u05D5\u05DF",["fix"]],["\u05D1\u05E0\u05D9\u05D9\u05D4",["build"]],["\u05D1\u05D3\u05D9\u05E7\u05D4",["test"]],["\u05D0\u05D9\u05DE\u05D5\u05EA",["auth","authentication"]],["\u05D4\u05D2\u05D3\u05E8\u05D5\u05EA",["config","configuration"]],["\u05D4\u05EA\u05E7\u05E0\u05D4",["install"]],["\u05E2\u05D3\u05DB\u05D5\u05DF",["update","upgrade"]],["\u05D9\u05D5\u05DE\u05DF",["log"]],["\u05E9\u05E8\u05EA",["server"]],["\u05E9\u05D9\u05E8\u05D5\u05EA",["service"]],["\u05D2\u05D9\u05D1\u05D5\u05D9",["backup"]],["\u05E0\u05D9\u05D8\u05D5\u05E8",["monitor","monitoring"]],["\u05D7\u05D9\u05D1\u05D5\u05E8",["connection"]],["\u05D6\u05D9\u05DB\u05E8\u05D5\u05DF",["memory"]],["\u05E8\u05E9\u05EA",["network"]],["\u05EA\u05DE\u05D5\u05E0\u05D4",["image"]],["\u05E1\u05D9\u05E1\u05DE\u05D4",["password"]],["\u05D4\u05E8\u05E9\u05D0\u05D4",["permission","access"]],["\u05E7\u05E8\u05D9\u05E1\u05D4",["crash","panic"]],["\u05EA\u05D5\u05E8",["queue"]],["\u05DE\u05D8\u05DE\u05D5\u05DF",["cache"]],["\u05D0\u05E1\u05D9\u05DE\u05D5\u05DF",["token","secret"]],["\u05E4\u05D5\u05E8\u05D8",["port"]],["\u05D0\u05D9\u05EA\u05D5\u05E8 \u05D1\u05D0\u05D2\u05D9\u05DD",["debug","debugging"]],["\u05D4\u05E4\u05E2\u05DC\u05D4 \u05DE\u05D7\u05D3\u05E9",["restart","reboot"]],["\u05DE\u05D9\u05DB\u05DC",["container","docker"]],["\u05D9\u05D9\u05E9\u05D5\u05DD",["application","app"]],["\u05DE\u05E4\u05EA\u05D7",["key","token","secret"]],["\u05D1\u05D3\u05D9\u05E7\u05EA \u05EA\u05E7\u05D9\u05E0\u05D5\u05EA",["healthcheck","health"]],["\u05DE\u05DE\u05E9\u05E7 \u05EA\u05DB\u05E0\u05D5\u05EA",["api","interface"]],["\u05D1\u05D9\u05E6\u05D5\u05E2\u05D9\u05DD",["performance"]],["\u05D0\u05D7\u05E1\u05D5\u05DF",["storage","disk"]],["\u05E4\u05E8\u05D9\u05E1\u05D4",["deploy","deployment"]],["\u05D1\u05E2\u05D9\u05D4",["error","issue","bug","problem"]],["\u05E1\u05D1\u05D9\u05D1\u05D4",["environment","env"]],["\u05D9\u05D9\u05E6\u05D5\u05E8",["production","prod"]],["\u05E1\u05D5\u05D3\u05D9",["secret","key","token"]],["\u05DE\u05E4\u05EA\u05D7 \u05E1\u05D5\u05D3\u05D9",["secret","key"]],["\u0627\u0633\u062A\u0642\u0631\u0627\u0631",["deploy","deployment"]],["\u062E\u0637\u0627",["error","err"]],["\u0627\u0634\u06A9\u0627\u0644",["bug","issue","error"]],["\u0631\u0641\u0639 \u0627\u0634\u06A9\u0627\u0644",["fix","debug","debugging"]],["\u0633\u0627\u062E\u062A",["build"]],["\u0622\u0632\u0645\u0627\u06CC\u0634",["test"]],["\u0627\u062D\u0631\u0627\u0632 \u0647\u0648\u06CC\u062A",["auth","authentication"]],["\u067E\u06CC\u06A9\u0631\u0628\u0646\u062F\u06CC",["config","configuration"]],["\u0646\u0635\u0628",["install"]],["\u0628\u0647\u200C\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06CC",["update","upgrade"]],["\u062B\u0628\u062A",["log"]],["\u0633\u0631\u0648\u0631",["server"]],["\u067E\u0627\u06CC\u06AF\u0627\u0647 \u062F\u0627\u062F\u0647",["database","db"]],["\u0634\u0628\u06A9\u0647",["network"]],["\u062D\u0627\u0641\u0638\u0647",["memory","ram"]],["\u06A9\u0634",["cache"]],["\u0627\u0634\u06A9\u0627\u0644\u200C\u0632\u062F\u0627\u06CC\u06CC",["debug","debugging"]],["\u062E\u0631\u0627\u0628\u06CC",["crash","failure","error"]],["\u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u0645\u062C\u062F\u062F",["restart","reboot"]],["\u0645\u062C\u0648\u0632",["permission","access"]],["\u067E\u0634\u062A\u06CC\u0628\u0627\u0646\u200C\u06AF\u06CC\u0631\u06CC",["backup"]],["\u0639\u0645\u0644\u06A9\u0631\u062F",["performance"]],["\u0645\u0634\u06A9\u0644",["problem","issue","error"]],["\u0633\u0631\u0648\u06CC\u0633",["service"]],["\u06A9\u0644\u06CC\u062F",["key","token","secret"]],["\u0645\u062D\u06CC\u0637",["environment","env"]],["\u062A\u0648\u0644\u06CC\u062F",["production","prod"]],["\u0631\u0645\u0632",["secret","key","token"]],["\u0627\u062A\u0635\u0627\u0644",["connection","conn"]],["\u0924\u0948\u0928\u093E\u0924\u0940",["deploy","deployment"]],["\u0924\u0948\u0928\u093E",["deploy","deployment"]],["\u0924\u094D\u0930\u0941\u091F\u093F",["error","err"]],["\u0917\u0932\u0924\u0940",["error","bug","issue"]],["\u0938\u0941\u0927\u093E\u0930",["fix","bugfix"]],["\u0928\u093F\u0930\u094D\u092E\u093E\u0923",["build"]],["\u092A\u0930\u0940\u0915\u094D\u0937\u0923",["test"]],["\u092A\u094D\u0930\u092E\u093E\u0923\u0940\u0915\u0930\u0923",["auth","authentication"]],["\u0935\u093F\u0928\u094D\u092F\u093E\u0938",["config","configuration"]],["\u0915\u0949\u0928\u094D\u092B\u093C\u093F\u0917\u0930\u0947\u0936\u0928",["config","configuration"]],["\u0907\u0902\u0938\u094D\u091F\u0949\u0932",["install"]],["\u0905\u092A\u0921\u0947\u091F",["update","upgrade"]],["\u0932\u0949\u0917",["log"]],["\u0938\u0930\u094D\u0935\u0930",["server"]],["\u0921\u0947\u091F\u093E\u092C\u0947\u0938",["database","db"]],["\u0928\u0947\u091F\u0935\u0930\u094D\u0915",["network"]],["\u092E\u0947\u092E\u094B\u0930\u0940",["memory","ram"]],["\u0915\u0948\u0936",["cache"]],["\u0921\u0940\u092C\u0917",["debug","debugging"]],["\u0915\u094D\u0930\u0948\u0936",["crash","panic"]],["\u092A\u0941\u0928\u0930\u093E\u0930\u0902\u092D",["restart","reboot"]],["\u0905\u0928\u0941\u092E\u0924\u093F",["permission","access"]],["\u092C\u0948\u0915\u0905\u092A",["backup"]],["\u092A\u094D\u0930\u0926\u0930\u094D\u0936\u0928",["performance"]],["\u0938\u092E\u0938\u094D\u092F\u093E",["problem","issue","error"]],["\u0938\u0947\u0935\u093E",["service"]],["\u0915\u0928\u0947\u0915\u094D\u0936\u0928",["connection","conn"]],["\u092A\u093E\u0938\u0935\u0930\u094D\u0921",["password"]],["\u091F\u094B\u0915\u0928",["token","secret"]],["\u0935\u093E\u0924\u093E\u0935\u0930\u0923",["environment","env"]],["\u0909\u0924\u094D\u092A\u093E\u0926\u0928",["production","prod"]],["fehler",["error","err"]],["absturz",["crash","panic"]],["bug",["bug","issue"]],["beheben",["fix","bugfix"]],["behoben",["fix","fixed"]],["l\xF6sung",["solution","fix"]],["bauen",["build"]],["testen",["test"]],["authentifizierung",["auth","authentication"]],["konfiguration",["config","configuration"]],["einstellungen",["config","settings"]],["installieren",["install"]],["installiert",["install","installed"]],["aktualisieren",["update","upgrade"]],["aktualisierung",["update","upgrade"]],["protokoll",["log"]],["protokolle",["log","logs"]],["abbild",["image"]],["knoten",["node"]],["dienst",["service"]],["sicherung",["backup"]],["\xFCberwachung",["monitor","monitoring"]],["verbindung",["connection","conn"]],["warteschlange",["queue"]],["leistung",["performance"]],["speicher",["memory","storage"]],["debuggen",["debug","debugging"]],["neustart",["restart","reboot"]],["berechtigung",["permission","access"]],["berechtigungen",["permission","access","acl"]],["netzwerk",["network"]],["datenbank",["database","db"]],["bereitstellen",["deploy","deployment"]],["bereitstellung",["deploy","deployment"]],["kaputt",["broken","error","crash"]],["funktioniert",["works","working"]],["geht nicht",["not working","broken","error"]],["schl\xFCssel",["key","token","secret"]],["zertifikat",["certificate","cert","ssl","tls"]],["umgebung",["environment","env"]],["variablen",["variables","env","environment"]],["aufgabe",["task","job"]],["wartung",["maintenance"]],["speicherleck",["memory leak","memory"]],["schnittstelle",["interface","api"]],["erreur",["error","err"]],["r\xE9parer",["fix"]],["correction",["fix","bugfix"]],["construire",["build"]],["tester",["test"]],["authentification",["auth","authentication"]],["configuration",["config","configuration"]],["installer",["install"]],["installation",["install"]],["mettre",["update","upgrade"]],["journal",["log","logs"]],["n\u0153ud",["node"]],["sauvegarde",["backup"]],["surveiller",["monitor","monitoring"]],["connexion",["connection"]],["m\xE9moire",["memory"]],["d\xE9boguer",["debug"]],["red\xE9marrer",["restart","reboot"]],["r\xE9seau",["network"]],["base de donn\xE9es",["database","db"]],["d\xE9ployer",["deploy"]],["d\xE9ploiement",["deploy","deployment"]],["cl\xE9",["key","token"]],["certificat",["certificate","cert","ssl"]],["environnement",["environment","env"]],["panne",["crash","outage","failure"]],["plantage",["crash","panic"]],["interface",["interface","api"]],["performances",["performance"]],["stockage",["storage","disk"]],["file attente",["queue"]],["arreglar",["fix"]],["correcci\xF3n",["fix","bugfix"]],["construir",["build"]],["probar",["test"]],["autenticaci\xF3n",["auth","authentication"]],["configuraci\xF3n",["config","configuration"]],["instalar",["install"]],["actualizar",["update","upgrade"]],["actualizaci\xF3n",["update","upgrade"]],["registro",["log","registry"]],["nodo",["node"]],["servicio",["service"]],["contrase\xF1a",["password"]],["copia de seguridad",["backup"]],["respaldo",["backup"]],["monitorear",["monitor"]],["monitoreo",["monitoring"]],["conexi\xF3n",["connection"]],["rendimiento",["performance"]],["memoria",["memory"]],["depurar",["debug"]],["fallo",["crash","failure","error"]],["ca\xEDda",["crash","outage"]],["reiniciar",["restart","reboot"]],["permiso",["permission"]],["permisos",["permission","access"]],["red",["network"]],["base de datos",["database","db"]],["desplegar",["deploy"]],["despliegue",["deploy","deployment"]],["clave",["key","token","secret"]],["certificado",["certificate","cert","ssl"]],["entorno",["environment","env"]],["cola",["queue"]],["interfaz",["interface","api"]],["imagen",["image"]],["errore",["error","err"]],["correggere",["fix"]],["costruire",["build"]],["testare",["test"]],["autenticazione",["auth","authentication"]],["configurazione",["config","configuration"]],["installare",["install"]],["aggiornare",["update","upgrade"]],["aggiornamento",["update","upgrade"]],["registro",["log"]],["nodo",["node"]],["servizio",["service"]],["password",["password"]],["backup",["backup"]],["monitorare",["monitor"]],["connessione",["connection"]],["prestazioni",["performance"]],["memoria",["memory"]],["debug",["debug"]],["arresto anomalo",["crash"]],["riavviare",["restart"]],["permesso",["permission"]],["rete",["network"]],["database",["database","db"]],["distribuire",["deploy"]],["distribuzione",["deploy","deployment"]],["chiave",["key","token","secret"]],["certificato",["certificate","cert"]],["ambiente",["environment","env"]],["coda",["queue"]],["immagine",["image"]],["erro",["error","err"]],["corrigir",["fix"]],["construir",["build"]],["testar",["test"]],["autentica\xE7\xE3o",["auth","authentication"]],["configura\xE7\xE3o",["config","configuration"]],["instalar",["install"]],["atualizar",["update","upgrade"]],["atualiza\xE7\xE3o",["update","upgrade"]],["registro",["log"]],["n\xF3",["node"]],["servi\xE7o",["service"]],["senha",["password"]],["c\xF3pia de seguran\xE7a",["backup"]],["monitorar",["monitor"]],["conex\xE3o",["connection"]],["desempenho",["performance"]],["mem\xF3ria",["memory"]],["depurar",["debug"]],["falha",["crash","failure","error"]],["reiniciar",["restart"]],["permiss\xE3o",["permission"]],["rede",["network"]],["banco de dados",["database","db"]],["implantar",["deploy"]],["implanta\xE7\xE3o",["deploy","deployment"]],["chave",["key","token","secret"]],["certificado",["certificate","cert"]],["ambiente",["environment","env"]],["fila",["queue"]],["imagem",["image"]],["\u043E\u0448\u0438\u0431\u043A\u0430",["error","err"]],["\u043E\u0448\u0438\u0431\u043A\u0438",["error","err"]],["\u0441\u0431\u043E\u0439",["crash","failure","error"]],["\u043A\u0440\u044D\u0448",["crash","panic"]],["\u0431\u0430\u0433",["bug","issue"]],["\u0438\u0441\u043F\u0440\u0430\u0432\u0438\u0442\u044C",["fix","bugfix"]],["\u0438\u0441\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435",["fix","patch"]],["\u0441\u0431\u043E\u0440\u043A\u0430",["build"]],["\u0441\u043E\u0431\u0440\u0430\u0442\u044C",["build"]],["\u0442\u0435\u0441\u0442",["test"]],["\u0442\u0435\u0441\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435",["test","testing"]],["\u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F",["auth","authentication"]],["\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F",["auth","authorization"]],["\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F",["config","configuration"]],["\u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438",["config","settings"]],["\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C",["install"]],["\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430",["install"]],["\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435",["update","upgrade"]],["\u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C",["update","upgrade"]],["\u0436\u0443\u0440\u043D\u0430\u043B",["log"]],["\u043B\u043E\u0433",["log","logs"]],["\u0441\u0435\u0440\u0432\u0435\u0440",["server"]],["\u0431\u0430\u0437\u0430 \u0434\u0430\u043D\u043D\u044B\u0445",["database","db"]],["\u0441\u0435\u0442\u044C",["network"]],["\u043F\u0430\u043C\u044F\u0442\u044C",["memory","ram"]],["\u043A\u044D\u0448",["cache"]],["\u043E\u0442\u043B\u0430\u0434\u043A\u0430",["debug","debugging"]],["\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A",["restart","reboot"]],["\u043F\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0430",["restart","reboot"]],["\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435",["permission","access"]],["\u0434\u043E\u0441\u0442\u0443\u043F",["permission","access"]],["\u0440\u0435\u0437\u0435\u0440\u0432",["backup"]],["\u043F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C",["performance"]],["\u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430",["problem","issue","error"]],["\u0441\u0435\u0440\u0432\u0438\u0441",["service"]],["\u0441\u043B\u0443\u0436\u0431\u0430",["service"]],["\u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435",["connection","conn"]],["\u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435",["connection","conn"]],["\u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435",["deploy","deployment"]],["\u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u0435",["deploy","deployment"]],["\u0440\u0430\u0437\u0432\u0451\u0440\u0442",["deploy","deployment"]],["\u0440\u0430\u0437\u0432\u0435\u0440\u0442",["deploy","deployment"]],["\u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440",["container","docker"]],["\u043E\u0431\u0440\u0430\u0437",["image"]],["\u043A\u043B\u0430\u0441\u0442\u0435\u0440",["cluster"]],["\u0443\u0437\u0435\u043B",["node"]],["\u0441\u0435\u043A\u0440\u0435\u0442",["secret","key","token"]],["\u043A\u043B\u044E\u0447",["key","token","secret"]],["\u043F\u0430\u0440\u043E\u043B\u044C",["password"]],["\u0442\u043E\u043A\u0435\u043D",["token","secret"]],["\u043C\u043E\u043D\u0438\u0442\u043E\u0440\u0438\u043D\u0433",["monitor","monitoring"]],["\u043D\u0430\u0431\u043B\u044E\u0434\u0435\u043D\u0438\u0435",["monitor","monitoring"]],["\u043C\u0438\u0433\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C",["migrate","migration"]],["\u043C\u0438\u0433\u0440\u0430\u0446\u0438\u044F",["migrate","migration"]],["hata",["error","err"]],["hatal\u0131",["error","err"]],["\xE7\xF6kme",["crash","panic"]],["\xE7\xF6k\xFC\u015F",["crash","failure"]],["d\xFCzeltmek",["fix","bugfix"]],["d\xFCzeltme",["fix","patch"]],["derleme",["build"]],["derlemek",["build"]],["test",["test"]],["testlemek",["test","testing"]],["kimlik do\u011Frulama",["auth","authentication"]],["yetkilendirme",["auth","authorization"]],["yap\u0131land\u0131rma",["config","configuration"]],["ayarlar",["config","settings"]],["y\xFCklemek",["install"]],["kurulum",["install"]],["g\xFCncelleme",["update","upgrade"]],["g\xFCnl\xFCk",["log"]],["sunucu",["server"]],["veritaban\u0131",["database","db"]],["a\u011F",["network"]],["bellek",["memory","ram"]],["\xF6nbellek",["cache"]],["hata ay\u0131klama",["debug","debugging"]],["yeniden ba\u015Flatma",["restart","reboot"]],["izin",["permission","access"]],["yetki",["permission","access","acl"]],["yedekleme",["backup"]],["performans",["performance"]],["sorun",["problem","issue","error"]],["servis",["service"]],["hizmet",["service"]],["ba\u011Flant\u0131",["connection","conn"]],["da\u011F\u0131t\u0131m",["deploy","deployment"]],["da\u011F\u0131tmak",["deploy"]],["konteyner",["container","docker"]],["k\xFCme",["cluster"]],["d\xFC\u011F\xFCm",["node"]],["gizli",["secret","key"]],["anahtar",["key","token","secret"]],["\u015Fifre",["password"]],["izleme",["monitor","monitoring"]],["g\xF6\xE7",["migrate","migration"]],["tri\u1EC3n khai",["deploy","deployment"]],["tri\u1EC3n",["deploy","deployment"]],["l\u1ED7i",["error","err"]],["s\u1EEDa l\u1ED7i",["fix","bugfix","debug"]],["x\xE2y d\u1EF1ng",["build"]],["ki\u1EC3m tra",["test"]],["x\xE1c th\u1EF1c",["auth","authentication"]],["c\u1EA5u h\xECnh",["config","configuration"]],["c\xE0i \u0111\u1EB7t",["install"]],["c\u1EADp nh\u1EADt",["update","upgrade"]],["nh\u1EADt k\xFD",["log"]],["m\xE1y ch\u1EE7",["server"]],["c\u01A1 s\u1EDF d\u1EEF li\u1EC7u",["database","db"]],["m\u1EA1ng",["network"]],["b\u1ED9 nh\u1EDB",["memory","ram"]],["b\u1ED9 \u0111\u1EC7m",["cache"]],["g\u1EE1 l\u1ED7i",["debug","debugging"]],["s\u1EF1 c\u1ED1",["crash","failure","error"]],["kh\u1EDFi \u0111\u1ED9ng l\u1EA1i",["restart","reboot"]],["quy\u1EC1n",["permission","access"]],["sao l\u01B0u",["backup"]],["hi\u1EC7u su\u1EA5t",["performance"]],["v\u1EA5n \u0111\u1EC1",["problem","issue","error"]],["d\u1ECBch v\u1EE5",["service"]],["k\u1EBFt n\u1ED1i",["connection","conn"]],["v\xF9ng ch\u1EE9a",["container","docker"]],["n\xFAt",["node"]],["kh\xF3a",["key","token","secret"]],["m\u1EADt kh\u1EA9u",["password"]],["gi\xE1m s\xE1t",["monitor","monitoring"]],["di chuy\u1EC3n",["migrate","migration"]]]);for(const[t,e]of j){const o=R(t);o!==t&&!j.has(o)&&j.set(o,e)}for(const[t,e]of be){const o=j.get(t);j.set(t,o?[...new Set([...o,...e])]:[...e])}const ke=new Set([...j.keys()].filter(t=>t.length>=4&&/^[a-z]+$/.test(R(t))).map(R));function D(t){const e=j.get(t);if(e)return e;const o=R(t);return o!==t?j.get(o)??[]:[]}function q(t,e){const o=e?.crossLingualExpand??!0,a=[],m=ge(t).toLowerCase();for(const[c]of m.matchAll(he))if(T.test(c)){for(let n=0;n<c.length-1;n++){const r=c[n]+c[n+1];!h.has(c[n])&&!h.has(r)&&a.push(r)}if(c.length>=1){const n=c[c.length-1];h.has(n)||a.push(n)}const g=D(c);for(const n of g)T.test(n)||n.split(/\s+/).filter(r=>r.length>1&&!h.has(r)).forEach(r=>a.push(r));const i=c.replace(/[^\u30a0-\u30ff]/g,"");if(i.length>=2){const n=Z(i);n.length>=2&&n.length<=40&&!h.has(n)&&a.push(n)}}else if(M.test(c)){const g=c.trim().split(/\s+/);let i;F.test(c)?i=G:C.test(c)?i=K:i=N;for(const n of g){if(n.length<=1||h.has(n))continue;const r=i(n);r.length>1&&!h.has(r)&&a.push(r)}}else if(O.test(c)){const g=c.trim().split(/[\s\u200c\u200d]+/);for(const i of g){const n=i.replace(/[^\u0900-\u097f0-9]/g,"");if(n.length<=1||h.has(n))continue;const r=Y(n);r.length>1&&!h.has(r)&&a.push(r)}}else if(U.test(c)){const g=c.trim().split(/[\s\u200c\u200d]+/);for(const i of g){const n=i.replace(/[^\u0980-\u09ff0-9]/g,"");if(n.length<=1||h.has(n))continue;const r=J(n);r.length>1&&!h.has(r)&&a.push(r)}}else if(P.test(c)){const g=c.trim().split(/\s+/);for(const i of g){const n=i.replace(/[^\u0400-\u04ff]/g,"");if(n.length<=1||h.has(n))continue;const r=V(n);r.length>1&&!h.has(r)&&a.push(r)}}else{const g=c.replace(/[^a-záàâãäåæçéèêëíìîïñóòôõöúùûüýÿßœğşıİąćęłńśźżčšžěůřőűșț\u1ea0-\u1ef90-9:\-./]/g," ").split(/\s+/).filter(i=>i.length>1&&!h.has(i));for(const i of g){if($.test(i)){const f=Q(i);f!==i&&f.length>1&&!h.has(f)&&a.push(f)}a.push(i);const n=R(i);n!==i&&!h.has(n)&&a.push(n);const r=fe(i);if(r!==i&&r!==n&&r.length>3&&!h.has(r)){a.push(r);const f=me(r);f&&f.length>3&&!h.has(f)&&a.push(f)}if(n.length>=10)for(const f of pe(n,ke))h.has(f)||a.push(f)}}if(!o)return a;const u=[],z=new Set(a);for(const c of a){const g=D(c);for(const i of g)if(!z.has(i))if(z.add(i),T.test(i)){for(let n=0;n<i.length-1;n++){const r=i[n]+i[n+1];!h.has(i[n])&&!h.has(r)&&u.push(r)}if(i.length>=1){const n=i[i.length-1];h.has(n)||u.push(n)}}else if(M.test(i)){const r=(F.test(i)?G:C.test(i)?K:N)(i);r.length>1&&!h.has(r)&&u.push(r)}else if(O.test(i)){const n=Y(i);n.length>1&&!h.has(n)&&u.push(n)}else if(U.test(i)){const n=J(i);n.length>1&&!h.has(n)&&u.push(n)}else if(P.test(i)){const n=i.replace(/[^\u0400-\u04ff]/g,""),r=V(n);r.length>1&&!h.has(r)&&u.push(r)}else{const n=i.split(/\s+/).filter(r=>!(r.length<=1||h.has(r)));for(const r of n)if(u.push(r),$.test(r)){const f=Q(r);f!==r&&f.length>1&&!h.has(f)&&u.push(f)}}}return a.push(...u),a}function X(t){const e=t.split(/\d+[.)]\s*/g).filter(u=>u.trim().length>2);if(e.length>=2)return e.map(u=>u.trim());const o=t.split(/[;\n]+/).filter(u=>u.trim().length>2);if(o.length>=2)return o.map(u=>u.trim());const a=t.split(/\b(?:and also|also noch|außerdem|plus|additionally|furthermore|de plus|además|inoltre|além disso|а также|и также|кроме того|плюс|ayrıca|bunun yanı sıra|همچنین|وأيضاً|وكذلك|وهمچنین|और भी|इसके अलावा)\b/i).filter(u=>u.trim().length>2);if(a.length>=2)return a.map(u=>u.trim());const m=t.split(/,\s*/).filter(u=>u.trim().length>2);return m.length>=3?m.map(u=>u.trim()):[t]}const ee=1.2,te=.75,ye=.25,ne=.05,we=.5,ve=64,We=7,L=[],ze=500;let re=0;function ie(t){re++,L.length>=ze&&L.shift(),L.push({query:t,ts:Date.now()})}let H=new Set;function oe(t,e){if(t===e)return 0;if(t.length===0)return e.length;if(e.length===0)return t.length;if(Math.abs(t.length-e.length)>2)return 3;const o=Array.from({length:e.length+1},(a,m)=>m);for(let a=1;a<=t.length;a++){let m=a-1;o[0]=a;for(let u=1;u<=e.length;u++){const z=t[a-1]===e[u-1]?0:1,c=Math.min(o[u]+1,o[u-1]+1,m+z);m=o[u],o[u]=c}}return o[e.length]}function se(t){const e=t.match(/"(?:ts|created|created_at|timestamp)"\s*:\s*"([^"]+)"/);if(e){const o=Date.parse(e[1]);if(!isNaN(o))return o}}function ae(t){if(!t)return 1;const e=(Date.now()-t)/(1e3*60*60*24),o=e<=0?1:Math.pow(.5,e/We);return 1-ne+2*ne*o}const xe=6e4,I=new WeakMap;let B=0;function Re(){ue=Date.now(),B=0}let ue=0;function qe(){return B}async function je(t,e,o,a=10){const m=e.slice().sort().join("|"),z=I.get(t)?.get(m);if(z&&z.gebaut>ue&&Date.now()-z.gebaut<xe)return ce(z,o,a);const c=await Promise.all(e.map(k=>{const v=[],s=t.scanStream({match:k,count:500});return new Promise((b,W)=>{s.on("data",l=>{v.push(...l.filter(d=>!d.endsWith(":meta")))}),s.on("end",()=>b(v)),s.on("error",W)})})),g=[...new Set(c.flat())];if(g.length===0)return[];const i=t.pipeline();for(const k of g)i.get(k);const n=await i.exec(),r=[];let f=0;for(let k=0;k<g.length;k++){const v=n?.[k]?.[1];if(!v)continue;const s=q(`${g[k]} ${v}`,{crossLingualExpand:!1});if(s.length===0)continue;const b=new Map;for(const y of s)b.set(y,(b.get(y)??0)+1);const W=new Set;for(let y=0;y<s.length-1;y++)W.add(`${s[y]}|${s[y+1]}`);const l=se(v),d=new Set(q(g[k]));r.push({key:g[k],content:v,tokens:s,tokenFreq:b,bigrams:W,keyTokens:d,timestamp:l}),f+=s.length}if(r.length===0)return[];const w=f/r.length,p=new Map;for(const k of r){const v=new Set;for(const s of k.tokens)v.has(s)||(p.set(s,(p.get(s)??0)+1),v.add(s))}const x={docs:r,avgDL:w,docFreq:p,gebaut:Date.now()},S=I.get(t)??new Map;return S.has(m)||B++,S.set(m,x),I.set(t,S),ce(x,o,a)}function ce(t,e,o){const{docs:a,avgDL:m,docFreq:u}=t,z=a.length;function c(w){const p=u.get(w)??0;return Math.log((z-p+.5)/(p+.5)+1)}function g(w,p){const x=p.tokenFreq.get(w)??0;if(x===0)return 0;const S=p.tokens.length,k=x*(ee+1)/(x+ee*(1-te+te*(S/m)));return c(w)*(k+ye)}const i=X(e),n=new Map;for(const w of i){const p=q(w);if(p.length===0)continue;const x=new Map,S=s=>{const b=x.get(s);if(b)return b;const W=(d,y)=>{const E=[];for(const _ of u.keys())d(_)&&E.push([_,y]);return E.sort((_,le)=>(u.get(_[0])??0)-(u.get(le[0])??0)),E.slice(0,ve)};let l=[];return s.length>=4&&(l=W(d=>d.length>s.length&&d.startsWith(s),.85)),l.length===0&&s.length>=4&&(l=W(d=>d.length>=4&&d.length<s.length&&s.startsWith(d),.75)),l.length===0&&s.length>3&&(l=W(d=>d.length>3&&(d.includes(s)||s.includes(d)),.6)),l.length===0&&s.length>=4&&(l=W(d=>d.length>=4&&oe(s,d)<=2,.4)),x.set(s,l),l},k=new Set(q(w,{crossLingualExpand:!1})),v=new Set;for(let s=0;s<p.length-1;s++)v.add(`${p[s]}|${p[s+1]}`);for(const s of a){let b=0;const W=[];for(const l of p){const d=k.has(l)?1:we,y=g(l,s);if(y>0){b+=y*d,W.push(l);continue}for(const[E,_]of S(l))if(s.tokenFreq.has(E)){b+=g(E,s)*_*d,W.push(`~${l}`);break}}if(v.size>0){let l=0;for(const d of v)s.bigrams.has(d)&&l++;l>0&&(b*=1+.5*(l/v.size))}if(!process.env.AUS_PHRASE&&w.length>=4&&s.content.toLowerCase().includes(w.toLowerCase())&&(b*=2),b>0){let l=0,d=0;for(const y of p)s.keyTokens.has(y)&&(l++,k.has(y)&&d++);if(l>0){const y=d/Math.max(1,k.size);b*=1+1*Math.min(1,y*2)}}if(b*=ae(s.timestamp),b>0){const l=n.get(s.key);(!l||b>l.score)&&n.set(s.key,{key:s.key,content:s.content,score:b,matchedWords:[...new Set(W)],subQuery:i.length>1?w:void 0})}}}const f=[...n.values()].sort((w,p)=>p.score-w.score).slice(0,o);if(f.length===0){ie(e),H=new Set;for(const w of a)for(const p of w.tokens)H.add(p)}return f}export{j as CROSS_LINGUAL_MAP,h as STOPWORDS,L as ZERO_RESULTS_LOG,N as arabicLightStem,D as expandCrossLingual,se as extractTimestamp,H as indexVocab,Z as katakanaToRomaji,je as keywordSearch,oe as levenshtein,ie as logZeroResult,ae as recencyBoost,X as splitMultiQuery,q as tokenize,Re as wortindexEntwerten,qe as wortindexStand,re as zeroResultsTotal};
|