neurain 0.1.0-alpha.3 → 0.1.0-alpha.5
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/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/docs/development-status.en.md +2 -2
- package/docs/development-status.kr.md +2 -2
- package/package.json +1 -1
- package/src/cli.mjs +64 -110
- package/src/core/recall.mjs +7 -1
- package/src/core/recall_lexical.mjs +4 -1
- package/src/core/semantic.mjs +35 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
- No unreleased changes recorded.
|
|
6
6
|
|
|
7
|
+
## 0.1.0-alpha.5
|
|
8
|
+
|
|
9
|
+
- Performance (recall processing): cut recall/search processing time without changing results. The semantic scorer now prepares the query once and precomputes per-doc trigrams (instead of re-tokenizing the query and rebuilding `charTrigrams` per document), and the lexical BM25 counts term frequency with an index loop instead of `String.split`. Measured: `recall hybrid-search` ~1234ms -> ~970ms, `semantic-search` ~1031ms -> ~750ms (warm median), with byte-identical ranking/scores/matched_terms (golden-verified) and npm test 153/153.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## 0.1.0-alpha.4
|
|
13
|
+
|
|
14
|
+
- Performance: lazy dynamic-import CLI dispatch. Each command now imports only its own `core/*.mjs` module on demand instead of loading all ~54 command modules on every invocation. Engine subprocess latency drops ~60-75ms across the board (`tidy` 150->90ms, `structure-audit` 120->60ms, `--help`/`--version` 50ms), with no change to the command surface or behavior (npm test 153/153; reviewed).
|
|
15
|
+
|
|
16
|
+
|
|
7
17
|
## 0.1.0-alpha.3
|
|
8
18
|
|
|
9
19
|
- Destination resolver (`resolve_target.mjs`): `capture` and `compile` now derive one canonical target path from area, write intent, and sensitivity instead of leaving placement to the caller. Private, multi-area, and decision-required items still gate on the `<N>건 저장 진행` confirmation and are never auto-filed.
|
package/README.md
CHANGED
|
@@ -204,7 +204,7 @@ It exposes read/capture/scan/preview tools only. It does not silently compile, p
|
|
|
204
204
|
|
|
205
205
|
## Status
|
|
206
206
|
|
|
207
|
-
This is `0.1.0-alpha.
|
|
207
|
+
This is `0.1.0-alpha.5`. It is not a public SaaS GA release. The alpha exists to prove installability, local-first onboarding, Codex, Claude, Gemini, and Runtime connectivity, plus safety receipts.
|
|
208
208
|
|
|
209
209
|
Alpha publish command:
|
|
210
210
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Version: v0.1
|
|
4
4
|
Last updated: 2026-06-19 KST
|
|
5
|
-
Package: `neurain@0.1.0-alpha.
|
|
6
|
-
Latest documented commit: `
|
|
5
|
+
Package: `neurain@0.1.0-alpha.5`
|
|
6
|
+
Latest documented commit: `6305d3d perf(recall): cut recall processing time, results byte-identical`
|
|
7
7
|
|
|
8
8
|
This document is the canonical product development snapshot for the public package. It tracks what is shipped, what has evidence, and what must not be claimed yet.
|
|
9
9
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Version: v0.1
|
|
4
4
|
Last updated: 2026-06-19 KST
|
|
5
|
-
Package: `neurain@0.1.0-alpha.
|
|
6
|
-
Latest documented commit: `
|
|
5
|
+
Package: `neurain@0.1.0-alpha.5`
|
|
6
|
+
Latest documented commit: `6305d3d perf(recall): cut recall processing time, results byte-identical`
|
|
7
7
|
|
|
8
8
|
이 문서는 public package 기준의 canonical 개발 상태 스냅샷입니다. 무엇이 shipped인지, 어떤 증거가 있는지, 아직 주장하면 안 되는 것이 무엇인지 함께 기록합니다.
|
|
9
9
|
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -1,60 +1,62 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
3
|
+
|
|
4
|
+
const COMMAND_HANDLERS = {
|
|
5
|
+
init: async (args) => (await import('./core/init.mjs')).initCommand(args),
|
|
6
|
+
onboard: async (args) => (await import('./core/onboard.mjs')).onboardCommand(args),
|
|
7
|
+
answer: async (args) => (await import('./core/answer_eval.mjs')).answerCommand(args),
|
|
8
|
+
doctor: async (args) => (await import('./core/doctor.mjs')).doctorCommand(args),
|
|
9
|
+
search: async (args) => (await import('./core/search.mjs')).searchCommand(args),
|
|
10
|
+
connect: async (args) => (await import('./core/connect.mjs')).connectCommand(args),
|
|
11
|
+
journal: async (args) => (await import('./core/journal.mjs')).journalCommand(args),
|
|
12
|
+
lifecycle: async (args) => (await import('./core/lifecycle.mjs')).lifecycleCommand(args),
|
|
13
|
+
'live-cases': async (args) => (await import('./core/live_cases.mjs')).liveCasesCommand(args),
|
|
14
|
+
lessons: async (args) => (await import('./core/lessons.mjs')).lessonsCommand(args),
|
|
15
|
+
curator: async (args) => (await import('./core/curator.mjs')).curatorCommand(args),
|
|
16
|
+
daemon: async (args) => (await import('./core/daemon.mjs')).daemonCommand(args),
|
|
17
|
+
recall: async (args) => (await import('./core/recall.mjs')).recallCommand(args),
|
|
18
|
+
reindex: async (args) => (await import('./core/reindex.mjs')).reindexCommand(args),
|
|
19
|
+
status: async (args) => (await import('./core/status.mjs')).statusCommand(args),
|
|
20
|
+
digest: async (args) => (await import('./core/digest.mjs')).digestCommand(args),
|
|
21
|
+
queue: async (args) => (await import('./core/queue.mjs')).queueCommand(args),
|
|
22
|
+
'review-queue': async (args) => (await import('./core/review_queue.mjs')).reviewQueueCommand(args),
|
|
23
|
+
route: async (args) => (await import('./core/route.mjs')).routeCommand(args),
|
|
24
|
+
'plan-writeback': async (args) => (await import('./core/plan_writeback.mjs')).planWritebackCommand(args),
|
|
25
|
+
flush: async (args) => (await import('./core/flush.mjs')).flushCommand(args),
|
|
26
|
+
'session-flush': async (args) => (await import('./core/flush.mjs')).sessionFlushCommand(args),
|
|
27
|
+
compile: async (args) => (await import('./core/compile_desk.mjs')).compileCommand(args),
|
|
28
|
+
'plan-receipt': async (args) => (await import('./core/plan_receipt.mjs')).planReceiptCommand(args),
|
|
29
|
+
'source-digest': async (args) => (await import('./core/source_digest_gen.mjs')).sourceDigestCommand(args),
|
|
30
|
+
stage: async (args) => (await import('./core/stage.mjs')).stageCommand(args),
|
|
31
|
+
'queue-archive': async (args) => (await import('./core/queue_archive.mjs')).queueArchiveCommand(args),
|
|
32
|
+
capture: async (args) => (await import('./core/capture_durable.mjs')).captureCommand(args),
|
|
33
|
+
complete: async (args) => (await import('./core/complete.mjs')).completeCommand(args),
|
|
34
|
+
'link-check': async (args) => (await import('./core/link_check.mjs')).linkCheckCommand(args),
|
|
35
|
+
'session-lint': async (args) => (await import('./core/session_lint.mjs')).sessionLintCommand(args),
|
|
36
|
+
label: async (args) => (await import('./core/label.mjs')).labelCommand(args),
|
|
37
|
+
orphans: async (args) => (await import('./core/orphans.mjs')).orphansCommand(args),
|
|
38
|
+
hubs: async (args) => (await import('./core/hubs.mjs')).hubsCommand(args),
|
|
39
|
+
'area-index': async (args) => (await import('./core/area_index.mjs')).areaIndexCommand(args),
|
|
40
|
+
lint: async (args) => (await import('./core/lint.mjs')).lintCommand(args),
|
|
41
|
+
tidy: async (args) => (await import('./core/tidy.mjs')).tidyCommand(args),
|
|
42
|
+
'structure-audit': async (args) => (await import('./core/structure_audit.mjs')).structureAuditCommand(args),
|
|
43
|
+
file: async (args) => (await import('./core/file_loose.mjs')).fileCommand(args),
|
|
44
|
+
organize: async (args) => (await import('./core/organize.mjs')).organizeCommand(args),
|
|
45
|
+
'session-pulse': async (args) => (await import('./core/session_pulse.mjs')).sessionPulseCommand(args),
|
|
46
|
+
sync: async (args) => (await import('./core/sync.mjs')).syncCommand(args),
|
|
47
|
+
health: async (args) => (await import('./core/health.mjs')).healthCommand(args),
|
|
48
|
+
memory: async (args) => (await import('./core/memory.mjs')).memoryCommand(args),
|
|
49
|
+
retention: async (args) => (await import('./core/retention.mjs')).retentionCommand(args),
|
|
50
|
+
freeze: async (args) => (await import('./core/freeze.mjs')).freezeCommand(args),
|
|
51
|
+
'memory-write': async (args) => (await import('./core/memory_write_cli.mjs')).memoryWriteCommand(args),
|
|
52
|
+
backup: async (args) => (await import('./core/backup.mjs')).backupCommand(args),
|
|
53
|
+
capabilities: async (args) => (await import('./core/capabilities.mjs')).capabilitiesCommand(args),
|
|
54
|
+
recap: async (args) => (await import('./core/recap.mjs')).recapCommand(args),
|
|
55
|
+
watch: async (args) => (await import('./core/watch.mjs')).watchCommand(args),
|
|
56
|
+
review: async (args) => (await import('./core/review_worker.mjs')).reviewCommand(args),
|
|
57
|
+
scheduler: async (args) => (await import('./core/scheduler.mjs')).schedulerCommand(args),
|
|
58
|
+
wrap: async (args) => (await import('./core/wrap.mjs')).wrapCommand(args),
|
|
59
|
+
};
|
|
58
60
|
|
|
59
61
|
export async function runCli(argv) {
|
|
60
62
|
const [command, ...rest] = argv;
|
|
@@ -69,65 +71,17 @@ export async function runCli(argv) {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
const args = parseArgs(rest);
|
|
72
|
-
if (command === 'init') return render(await initCommand(args));
|
|
73
|
-
if (command === 'onboard') return render(await onboardCommand(args));
|
|
74
74
|
if (command === 'adopt') {
|
|
75
|
+
const { adoptCommand, rollbackAdoption } = await import('./core/adopt.mjs');
|
|
75
76
|
if (args.rollback) return render(await rollbackAdoption(args));
|
|
76
77
|
return render(await adoptCommand(args));
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
if (command === '
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (command === 'live-cases') return render(await liveCasesCommand(args));
|
|
85
|
-
if (command === 'lessons') return render(await lessonsCommand(args));
|
|
86
|
-
if (command === 'curator') return render(await curatorCommand(args));
|
|
87
|
-
if (command === 'daemon') return render(await daemonCommand(args));
|
|
88
|
-
if (command === 'recall') return render(await recallCommand(args));
|
|
89
|
-
if (command === 'reindex') return render(await reindexCommand(args));
|
|
90
|
-
if (command === 'status') return render(await statusCommand(args));
|
|
91
|
-
if (command === 'digest') return render(await digestCommand(args));
|
|
92
|
-
if (command === 'queue') return render(await queueCommand(args));
|
|
93
|
-
if (command === 'review-queue') return render(await reviewQueueCommand(args));
|
|
94
|
-
if (command === 'route') return render(await routeCommand(args));
|
|
95
|
-
if (command === 'plan-writeback') return render(await planWritebackCommand(args));
|
|
96
|
-
if (command === 'flush') return render(await flushCommand(args));
|
|
97
|
-
if (command === 'session-flush') return render(await sessionFlushCommand(args));
|
|
98
|
-
if (command === 'compile') return render(await compileCommand(args));
|
|
99
|
-
if (command === 'plan-receipt') return render(await planReceiptCommand(args));
|
|
100
|
-
if (command === 'source-digest') return render(await sourceDigestCommand(args));
|
|
101
|
-
if (command === 'stage') return render(await stageCommand(args));
|
|
102
|
-
if (command === 'queue-archive') return render(await queueArchiveCommand(args));
|
|
103
|
-
if (command === 'capture') return render(await captureCommand(args));
|
|
104
|
-
if (command === 'complete') return render(await completeCommand(args));
|
|
105
|
-
if (command === 'link-check') return render(await linkCheckCommand(args));
|
|
106
|
-
if (command === 'session-lint') return render(await sessionLintCommand(args));
|
|
107
|
-
if (command === 'label') return render(await labelCommand(args));
|
|
108
|
-
if (command === 'orphans') return render(await orphansCommand(args));
|
|
109
|
-
if (command === 'hubs') return render(await hubsCommand(args));
|
|
110
|
-
if (command === 'area-index') return render(await areaIndexCommand(args));
|
|
111
|
-
if (command === 'lint') return render(await lintCommand(args));
|
|
112
|
-
if (command === 'tidy') return render(await tidyCommand(args));
|
|
113
|
-
if (command === 'structure-audit') return render(await structureAuditCommand(args));
|
|
114
|
-
if (command === 'file') return render(await fileCommand(args));
|
|
115
|
-
if (command === 'organize') return render(await organizeCommand(args));
|
|
116
|
-
if (command === 'session-pulse') return render(await sessionPulseCommand(args));
|
|
117
|
-
if (command === 'sync') return render(await syncCommand(args));
|
|
118
|
-
if (command === 'health') return render(await healthCommand(args));
|
|
119
|
-
if (command === 'memory') return render(await memoryCommand(args));
|
|
120
|
-
if (command === 'retention') return render(await retentionCommand(args));
|
|
121
|
-
if (command === 'freeze') return render(await freezeCommand(args));
|
|
122
|
-
if (command === 'memory-write') return render(await memoryWriteCommand(args));
|
|
123
|
-
if (command === 'backup') return render(await backupCommand(args));
|
|
124
|
-
if (command === 'capabilities') return render(await capabilitiesCommand(args));
|
|
125
|
-
if (command === 'recap') return render(await recapCommand(args));
|
|
126
|
-
if (command === 'watch') return render(await watchCommand(args));
|
|
127
|
-
if (command === 'review') return render(await reviewCommand(args));
|
|
128
|
-
if (command === 'scheduler') return render(await schedulerCommand(args));
|
|
129
|
-
if (command === 'wrap') return render(await wrapCommand(args));
|
|
130
|
-
if (command === 'mcp') return startMcpServer(args);
|
|
79
|
+
const handler = COMMAND_HANDLERS[command];
|
|
80
|
+
if (handler) return render(await handler(args));
|
|
81
|
+
if (command === 'mcp') {
|
|
82
|
+
const { startMcpServer } = await import('./mcp/server.mjs');
|
|
83
|
+
return startMcpServer(args);
|
|
84
|
+
}
|
|
131
85
|
if (command === 'selftest') return runSelftest();
|
|
132
86
|
|
|
133
87
|
throw new Error(`Unknown command: ${command}\n\n${helpText()}`);
|
package/src/core/recall.mjs
CHANGED
|
@@ -195,9 +195,15 @@ export async function semanticSearchRecall(root, query, { top = 10, host = '', p
|
|
|
195
195
|
.filter((doc) => doc.sensitivity !== 'private')
|
|
196
196
|
.filter((doc) => !hostFilter || doc.host === hostFilter)
|
|
197
197
|
.filter((doc) => !scopeFilter || doc.scope === scopeFilter);
|
|
198
|
+
// Prepare the query ONCE, then score every doc against it (avoids re-tokenizing the
|
|
199
|
+
// query per document). Falls back to provider.score for providers without the fast path.
|
|
200
|
+
const preparedQuery = prov.prepareQuery ? prov.prepareQuery(text) : null;
|
|
198
201
|
const scored = docs
|
|
199
202
|
.map((doc) => {
|
|
200
|
-
const
|
|
203
|
+
const docText = `${doc.title} ${doc.body}`;
|
|
204
|
+
const scoredDoc = (preparedQuery && prov.scorePrepared)
|
|
205
|
+
? prov.scorePrepared(preparedQuery, docText)
|
|
206
|
+
: prov.score(text, docText);
|
|
201
207
|
return { doc, score: Number(scoredDoc.score || 0), matched_terms: scoredDoc.matched_terms || [] };
|
|
202
208
|
})
|
|
203
209
|
.filter((item) => item.score >= floor)
|
|
@@ -192,7 +192,10 @@ export function lexicalSearchWithContext(ctx, query, { top = 10, maxPerLayer = 3
|
|
|
192
192
|
|
|
193
193
|
let bm25 = 0;
|
|
194
194
|
for (const term of searchTerms) {
|
|
195
|
-
|
|
195
|
+
// Non-overlapping occurrence count (identical to `lower.split(term).length - 1`)
|
|
196
|
+
// without allocating the split array on every doc/term pair.
|
|
197
|
+
let tf = 0;
|
|
198
|
+
for (let i = lower.indexOf(term); i !== -1; i = lower.indexOf(term, i + term.length)) tf += 1;
|
|
196
199
|
if (tf === 0) continue;
|
|
197
200
|
const denom = tf + BM25_K1 * (1 - BM25_B + (BM25_B * length) / avgLength);
|
|
198
201
|
bm25 += (idf[term] || 0) * ((tf * (BM25_K1 + 1)) / denom);
|
package/src/core/semantic.mjs
CHANGED
|
@@ -117,9 +117,13 @@ function charTrigrams(token) {
|
|
|
117
117
|
export function fuzzyOverlap(a, b) {
|
|
118
118
|
if (!a || !b) return 0;
|
|
119
119
|
if (a === b) return 1;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
return trigramJaccard(charTrigrams(a), charTrigrams(b));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Jaccard over two PRE-COMPUTED trigram sets (same math as fuzzyOverlap's tail),
|
|
124
|
+
// so the per-doc fuzzy loop can reuse cached trigrams instead of rebuilding them.
|
|
125
|
+
function trigramJaccard(ga, gb) {
|
|
126
|
+
if (!ga || !gb || !ga.size || !gb.size) return 0;
|
|
123
127
|
let inter = 0;
|
|
124
128
|
for (const g of ga) if (gb.has(g)) inter += 1;
|
|
125
129
|
return inter / (ga.size + gb.size - inter);
|
|
@@ -127,13 +131,25 @@ export function fuzzyOverlap(a, b) {
|
|
|
127
131
|
|
|
128
132
|
// Deterministic lexical-semantic score of a query against a document body.
|
|
129
133
|
// Returns { score: 0..1 normalized by query length, matched_terms: [...] }.
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
// Prepare a query ONCE (tokenize + expand) so a corpus scan can reuse it across all
|
|
135
|
+
// docs instead of re-tokenizing the query per document (the per-doc hot path).
|
|
136
|
+
export function prepareSemanticQuery(query) {
|
|
137
|
+
// Precompute each term's trigrams ONCE so the per-doc fuzzy loop never rebuilds them.
|
|
138
|
+
return tokenize(query).map(expandToken).map((q) => ({ ...q, trigrams: charTrigrams(q.stem) }));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Score a pre-prepared query against a document body. Behaviour is identical to
|
|
142
|
+
// lexicalSemanticScore; only the query preparation is hoisted out.
|
|
143
|
+
export function scorePreparedSemantic(queryExpanded, docText) {
|
|
132
144
|
if (!queryExpanded.length) return { score: 0, matched_terms: [] };
|
|
133
145
|
const docTokens = tokenize(docText).map(expandToken);
|
|
134
146
|
if (!docTokens.length) return { score: 0, matched_terms: [] };
|
|
135
147
|
const docStems = new Set(docTokens.map((d) => d.stem));
|
|
136
148
|
const docCanons = new Set(docTokens.map((d) => d.canon).filter(Boolean));
|
|
149
|
+
// Build each unique doc-stem's trigrams ONCE per doc (was recomputed per query term
|
|
150
|
+
// inside fuzzyOverlap -> the charTrigrams hot path).
|
|
151
|
+
const docStemTrigrams = new Map();
|
|
152
|
+
for (const s of docStems) docStemTrigrams.set(s, charTrigrams(s));
|
|
137
153
|
const matched = [];
|
|
138
154
|
let total = 0;
|
|
139
155
|
for (const q of queryExpanded) {
|
|
@@ -142,9 +158,11 @@ export function lexicalSemanticScore(query, docText) {
|
|
|
142
158
|
if (docStems.has(q.stem)) { best = 1; how = 'exact'; }
|
|
143
159
|
else if (q.canon && docCanons.has(q.canon)) { best = 0.75; how = 'synonym'; }
|
|
144
160
|
else {
|
|
145
|
-
// fuzzy: best trigram overlap against any doc stem (typos / variants)
|
|
161
|
+
// fuzzy: best trigram overlap against any doc stem (typos / variants), using
|
|
162
|
+
// the precomputed query + doc-stem trigrams instead of rebuilding them.
|
|
163
|
+
const qTri = q.trigrams || charTrigrams(q.stem);
|
|
146
164
|
for (const d of docStems) {
|
|
147
|
-
const ov =
|
|
165
|
+
const ov = trigramJaccard(qTri, docStemTrigrams.get(d));
|
|
148
166
|
if (ov > best) { best = ov; how = 'fuzzy'; }
|
|
149
167
|
}
|
|
150
168
|
if (best < 0.6) best = 0;
|
|
@@ -155,6 +173,10 @@ export function lexicalSemanticScore(query, docText) {
|
|
|
155
173
|
return { score: Number((total / queryExpanded.length).toFixed(4)), matched_terms: matched };
|
|
156
174
|
}
|
|
157
175
|
|
|
176
|
+
export function lexicalSemanticScore(query, docText) {
|
|
177
|
+
return scorePreparedSemantic(prepareSemanticQuery(query), docText);
|
|
178
|
+
}
|
|
179
|
+
|
|
158
180
|
const PROVIDERS = new Map();
|
|
159
181
|
|
|
160
182
|
export function registerProvider(name, impl) {
|
|
@@ -181,6 +203,12 @@ registerProvider('local-lexical', {
|
|
|
181
203
|
expandQuery(query) {
|
|
182
204
|
return tokenize(query).map(expandToken);
|
|
183
205
|
},
|
|
206
|
+
prepareQuery(query) {
|
|
207
|
+
return prepareSemanticQuery(query);
|
|
208
|
+
},
|
|
209
|
+
scorePrepared(prepared, docText) {
|
|
210
|
+
return scorePreparedSemantic(prepared, docText);
|
|
211
|
+
},
|
|
184
212
|
score(query, docText) {
|
|
185
213
|
return lexicalSemanticScore(query, docText);
|
|
186
214
|
},
|