@delali/narsil 0.3.1-next.73 → 0.3.1-next.75
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/dist/{capabilities-CYeAWYxQ.d.ts → capabilities-BHNksicw.d.ts} +16 -2
- package/dist/{chunk-PU43WDY4.mjs → chunk-2E35UM3G.mjs} +1 -13
- package/dist/{chunk-AK3BLGCI.mjs → chunk-356UOTK2.mjs} +15 -48
- package/dist/chunk-7ODNRREZ.mjs +2050 -0
- package/dist/chunk-AIUOAN7Y.mjs +658 -0
- package/dist/{chunk-WVDFG45M.mjs → chunk-AMGDG4ZJ.mjs} +3 -2
- package/dist/{chunk-AFKH4ZK3.mjs → chunk-BT62MUM5.mjs} +1 -1
- package/dist/{chunk-LPBWCHBE.mjs → chunk-BT6BI4GV.mjs} +42 -4
- package/dist/{chunk-LJYTW7GT.mjs → chunk-IBR6634K.mjs} +1 -1
- package/dist/chunk-KEHK2O6P.mjs +13 -0
- package/dist/{chunk-CVFAFZSN.mjs → chunk-LOARLB4F.mjs} +46 -34
- package/dist/{chunk-3YKWSO54.mjs → chunk-NAMGDK45.mjs} +228 -649
- package/dist/{chunk-2WLD2NFW.mjs → chunk-PXDY5VRT.mjs} +3 -3
- package/dist/chunk-UOJIV2NG.mjs +593 -0
- package/dist/chunk-V3B24XR7.mjs +54 -0
- package/dist/{chunk-ZULSEZCE.mjs → chunk-WL2GDSCV.mjs} +100 -19
- package/dist/{chunk-THMSFOJO.mjs → chunk-YOVS4EV5.mjs} +582 -598
- package/dist/{client-D698E5ge.d.ts → client-D4sXFS9f.d.ts} +3 -3
- package/dist/client.d.ts +8 -8
- package/dist/{config-Bv8etwUZ.d.ts → config-B-GRonqw.d.ts} +2 -2
- package/dist/{config-QXU3HMpq.d.ts → config-C1kbq1X2.d.ts} +2 -2
- package/dist/direct-executor-AVNWB73C.mjs +16 -0
- package/dist/distribution/coordinator/etcd.d.ts +2 -2
- package/dist/distribution/coordinator/etcd.mjs +1 -1
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution/coordinator/in-memory.mjs +1 -1
- package/dist/distribution.d.ts +8 -8
- package/dist/distribution.mjs +23 -13
- package/dist/{engine-D_OzKZ-6.d.ts → engine-DcGSd5vh.d.ts} +2 -2
- package/dist/index.browser.mjs +1272 -834
- package/dist/index.d.ts +27 -8
- package/dist/index.mjs +14 -11
- package/dist/invalidation/filesystem.mjs +1 -1
- package/dist/{memory-B4jMmygw.d.ts → memory-M9kPmYP8.d.ts} +1257 -1178
- package/dist/partial-words-DTIHO8G4.d.ts +19 -0
- package/dist/partial-words.d.ts +22 -0
- package/dist/partial-words.mjs +11 -0
- package/dist/pattern.mjs +2 -2
- package/dist/persistence/durability/checkpoint-worker.d.ts +33 -13
- package/dist/persistence/durability/checkpoint-worker.mjs +14 -11
- package/dist/react.d.ts +7 -7
- package/dist/{schema-BBOCdhND.d.ts → schema-DgyDijhf.d.ts} +6 -2
- package/dist/server.d.ts +10 -10
- package/dist/server.mjs +36 -11
- package/dist/{tasks-DpgCpW1x.d.ts → tasks-A8se0J98.d.ts} +1 -1
- package/dist/{thread-3LNVA43V.mjs → thread-BSIKT6ED.mjs} +16 -9
- package/dist/{types-BiUmaiWT.d.ts → types-ChrVy4lH.d.ts} +1 -1
- package/dist/vector/search-worker.d.ts +1 -1
- package/dist/vector/search-worker.mjs +4 -3
- package/dist/workers/entry.mjs +3 -3
- package/package.json +16 -7
- package/dist/chunk-XW25X6AU.mjs +0 -614
- package/dist/chunk-ZKRV5M2P.mjs +0 -75
- package/dist/direct-executor-5SRDFZAS.mjs +0 -13
|
@@ -1,1421 +1,1500 @@
|
|
|
1
|
-
import { A as AnyDocument,
|
|
1
|
+
import { A as AnyDocument, d as ScoringMode, S as SchemaDefinition } from './schema-DgyDijhf.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Match on the code rather than on the message, because a code is stable and a
|
|
8
|
-
* message is not. The HTTP server maps each code to a status, so a code also
|
|
9
|
-
* tells you whether the caller or the engine is at fault.
|
|
4
|
+
* Compares one field against a value. Setting several keys narrows the match,
|
|
5
|
+
* because a document has to satisfy all of them.
|
|
10
6
|
*
|
|
11
7
|
* @public
|
|
12
8
|
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
readonly PERSISTENCE_SAVE_FAILED: "PERSISTENCE_SAVE_FAILED";
|
|
33
|
-
readonly PERSISTENCE_LOAD_FAILED: "PERSISTENCE_LOAD_FAILED";
|
|
34
|
-
readonly PERSISTENCE_DELETE_FAILED: "PERSISTENCE_DELETE_FAILED";
|
|
35
|
-
readonly PERSISTENCE_CRC_MISMATCH: "PERSISTENCE_CRC_MISMATCH";
|
|
36
|
-
readonly PERSISTENCE_WAL_CORRUPT: "PERSISTENCE_WAL_CORRUPT";
|
|
37
|
-
readonly PERSISTENCE_FSYNC_FAILED: "PERSISTENCE_FSYNC_FAILED";
|
|
38
|
-
readonly SEARCH_INVALID_FIELD: "SEARCH_INVALID_FIELD";
|
|
39
|
-
readonly VECTOR_DIMENSION_MISMATCH: "VECTOR_DIMENSION_MISMATCH";
|
|
40
|
-
readonly SEARCH_INVALID_FILTER: "SEARCH_INVALID_FILTER";
|
|
41
|
-
readonly SEARCH_INVALID_MODE: "SEARCH_INVALID_MODE";
|
|
42
|
-
readonly SEARCH_INVALID_CURSOR: "SEARCH_INVALID_CURSOR";
|
|
43
|
-
readonly SEARCH_RESULT_WINDOW_EXCEEDED: "SEARCH_RESULT_WINDOW_EXCEEDED";
|
|
44
|
-
readonly SEARCH_WORK_CAP_EXCEEDED: "SEARCH_WORK_CAP_EXCEEDED";
|
|
45
|
-
readonly LANGUAGE_NOT_SUPPORTED: "LANGUAGE_NOT_SUPPORTED";
|
|
46
|
-
readonly ENVELOPE_VERSION_MISMATCH: "ENVELOPE_VERSION_MISMATCH";
|
|
47
|
-
readonly ENVELOPE_INVALID_MAGIC: "ENVELOPE_INVALID_MAGIC";
|
|
48
|
-
readonly PARTITION_CAPACITY_EXCEEDED: "PARTITION_CAPACITY_EXCEEDED";
|
|
49
|
-
readonly EMBEDDING_FAILED: "EMBEDDING_FAILED";
|
|
50
|
-
readonly EMBEDDING_DIMENSION_MISMATCH: "EMBEDDING_DIMENSION_MISMATCH";
|
|
51
|
-
readonly EMBEDDING_NO_SOURCE: "EMBEDDING_NO_SOURCE";
|
|
52
|
-
readonly EMBEDDING_CONFIG_INVALID: "EMBEDDING_CONFIG_INVALID";
|
|
53
|
-
readonly DOC_MISSING_REQUIRED_FIELD: "DOC_MISSING_REQUIRED_FIELD";
|
|
54
|
-
readonly CONFIG_INVALID: "CONFIG_INVALID";
|
|
55
|
-
readonly QUERY_ROUTING_FAILED: "QUERY_ROUTING_FAILED";
|
|
56
|
-
readonly QUERY_PARTIAL_FAILURE: "QUERY_PARTIAL_FAILURE";
|
|
57
|
-
readonly QUERY_NODE_TIMEOUT: "QUERY_NODE_TIMEOUT";
|
|
58
|
-
readonly QUERY_NO_ACTIVE_REPLICA: "QUERY_NO_ACTIVE_REPLICA";
|
|
59
|
-
readonly CLUSTER_OPERATION_UNSUPPORTED: "CLUSTER_OPERATION_UNSUPPORTED";
|
|
60
|
-
readonly ALLOCATION_NO_DATA_NODES: "ALLOCATION_NO_DATA_NODES";
|
|
61
|
-
readonly ALLOCATION_INVALID_CONFIG: "ALLOCATION_INVALID_CONFIG";
|
|
62
|
-
readonly ALLOCATION_FAILED: "ALLOCATION_FAILED";
|
|
63
|
-
readonly CONTROLLER_METADATA_INVALID: "CONTROLLER_METADATA_INVALID";
|
|
64
|
-
readonly NODE_BOOTSTRAP_FAILED: "NODE_BOOTSTRAP_FAILED";
|
|
65
|
-
readonly NODE_ALREADY_JOINED: "NODE_ALREADY_JOINED";
|
|
66
|
-
readonly NODE_NOT_JOINED: "NODE_NOT_JOINED";
|
|
67
|
-
readonly NODE_NOT_READY: "NODE_NOT_READY";
|
|
68
|
-
readonly NODE_NOT_CONTROLLER: "NODE_NOT_CONTROLLER";
|
|
69
|
-
readonly COORDINATOR_DEPENDENCY_MISSING: "COORDINATOR_DEPENDENCY_MISSING";
|
|
70
|
-
readonly TRANSPORT_DEPENDENCY_MISSING: "TRANSPORT_DEPENDENCY_MISSING";
|
|
71
|
-
readonly REPLICATION_ENTRY_INVALID: "REPLICATION_ENTRY_INVALID";
|
|
72
|
-
readonly REPLICATION_INSYNC_REMOVAL_FAILED: "REPLICATION_INSYNC_REMOVAL_FAILED";
|
|
73
|
-
readonly REPLICATION_ROLLBACK_FAILED: "REPLICATION_ROLLBACK_FAILED";
|
|
74
|
-
readonly REPLICATION_LOG_FULL: "REPLICATION_LOG_FULL";
|
|
75
|
-
readonly REPLICATION_ENTRY_CORRUPT: "REPLICATION_ENTRY_CORRUPT";
|
|
76
|
-
readonly REPLICATION_SNAPSHOT_CORRUPT: "REPLICATION_SNAPSHOT_CORRUPT";
|
|
77
|
-
readonly REPLICATION_TERM_MISMATCH: "REPLICATION_TERM_MISMATCH";
|
|
78
|
-
readonly REPLICATION_SYNC_FAILED: "REPLICATION_SYNC_FAILED";
|
|
79
|
-
readonly PARTITION_NOT_PRIMARY: "PARTITION_NOT_PRIMARY";
|
|
80
|
-
readonly PARTITION_UNASSIGNED: "PARTITION_UNASSIGNED";
|
|
81
|
-
readonly INSUFFICIENT_REPLICAS: "INSUFFICIENT_REPLICAS";
|
|
82
|
-
readonly SNAPSHOT_SYNC_UNAUTHORIZED: "SNAPSHOT_SYNC_UNAUTHORIZED";
|
|
83
|
-
readonly SNAPSHOT_SYNC_REQUEST_INVALID: "SNAPSHOT_SYNC_REQUEST_INVALID";
|
|
84
|
-
readonly SNAPSHOT_SYNC_INDEX_NOT_FOUND: "SNAPSHOT_SYNC_INDEX_NOT_FOUND";
|
|
85
|
-
readonly SNAPSHOT_SYNC_CAPACITY_EXHAUSTED: "SNAPSHOT_SYNC_CAPACITY_EXHAUSTED";
|
|
86
|
-
readonly SNAPSHOT_SYNC_SNAPSHOT_FAILED: "SNAPSHOT_SYNC_SNAPSHOT_FAILED";
|
|
87
|
-
readonly SNAPSHOT_SYNC_DECODE_FAILED: "SNAPSHOT_SYNC_DECODE_FAILED";
|
|
88
|
-
readonly SNAPSHOT_SYNC_FRAME_INVALID: "SNAPSHOT_SYNC_FRAME_INVALID";
|
|
89
|
-
readonly SNAPSHOT_SYNC_HEADER_INVALID: "SNAPSHOT_SYNC_HEADER_INVALID";
|
|
90
|
-
readonly SNAPSHOT_SYNC_HEADER_MISMATCH: "SNAPSHOT_SYNC_HEADER_MISMATCH";
|
|
91
|
-
readonly SNAPSHOT_SYNC_CHUNK_OUT_OF_ORDER: "SNAPSHOT_SYNC_CHUNK_OUT_OF_ORDER";
|
|
92
|
-
readonly SNAPSHOT_SYNC_CHUNK_OVERFLOW: "SNAPSHOT_SYNC_CHUNK_OVERFLOW";
|
|
93
|
-
readonly SNAPSHOT_SYNC_CHUNK_SIZE_EXCEEDED: "SNAPSHOT_SYNC_CHUNK_SIZE_EXCEEDED";
|
|
94
|
-
readonly SNAPSHOT_SYNC_CHUNK_MISSING: "SNAPSHOT_SYNC_CHUNK_MISSING";
|
|
95
|
-
readonly SNAPSHOT_SYNC_END_MISSING: "SNAPSHOT_SYNC_END_MISSING";
|
|
96
|
-
readonly SNAPSHOT_SYNC_CHECKSUM_MISMATCH: "SNAPSHOT_SYNC_CHECKSUM_MISMATCH";
|
|
97
|
-
readonly SNAPSHOT_SYNC_PRIMARY_ERROR: "SNAPSHOT_SYNC_PRIMARY_ERROR";
|
|
98
|
-
readonly SNAPSHOT_SYNC_NO_TARGETS: "SNAPSHOT_SYNC_NO_TARGETS";
|
|
99
|
-
readonly SNAPSHOT_SYNC_TRANSPORT_FAILED: "SNAPSHOT_SYNC_TRANSPORT_FAILED";
|
|
100
|
-
readonly SNAPSHOT_SYNC_SCHEMA_UNAVAILABLE: "SNAPSHOT_SYNC_SCHEMA_UNAVAILABLE";
|
|
101
|
-
readonly SNAPSHOT_SYNC_RESTORE_FAILED: "SNAPSHOT_SYNC_RESTORE_FAILED";
|
|
102
|
-
readonly SNAPSHOT_SYNC_RESTORE_CLEANUP_FAILED: "SNAPSHOT_SYNC_RESTORE_CLEANUP_FAILED";
|
|
103
|
-
readonly SNAPSHOT_SYNC_TIMEOUT: "SNAPSHOT_SYNC_TIMEOUT";
|
|
104
|
-
readonly SNAPSHOT_SYNC_ALLOCATION_UNAVAILABLE: "SNAPSHOT_SYNC_ALLOCATION_UNAVAILABLE";
|
|
105
|
-
readonly SNAPSHOT_SYNC_NOT_ASSIGNED: "SNAPSHOT_SYNC_NOT_ASSIGNED";
|
|
106
|
-
readonly SNAPSHOT_SYNC_ABORTED: "SNAPSHOT_SYNC_ABORTED";
|
|
9
|
+
type ComparisonFilter = {
|
|
10
|
+
/** This matches a field equal to the value, or a list field where one element equals it. */
|
|
11
|
+
eq?: number | string | boolean;
|
|
12
|
+
/**
|
|
13
|
+
* This matches a document that holds the field with a value other than this
|
|
14
|
+
* one, or a list field where every element differs from it, which an empty
|
|
15
|
+
* list does.
|
|
16
|
+
*/
|
|
17
|
+
ne?: number | string | boolean;
|
|
18
|
+
/** This matches a field greater than the number. */
|
|
19
|
+
gt?: number;
|
|
20
|
+
/** This matches a field less than the number. */
|
|
21
|
+
lt?: number;
|
|
22
|
+
/** This matches a field greater than or equal to the number. */
|
|
23
|
+
gte?: number;
|
|
24
|
+
/** This matches a field less than or equal to the number. */
|
|
25
|
+
lte?: number;
|
|
26
|
+
/** This matches a field inside the inclusive range, given as `[low, high]`. */
|
|
27
|
+
between?: [number, number];
|
|
107
28
|
};
|
|
108
29
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
30
|
+
* The engine tests a text field against this filter for equality, for a text
|
|
31
|
+
* range, or with the set, prefix, and pattern tests.
|
|
111
32
|
*
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
*
|
|
117
|
-
* the engine call, such as parsing the body, enforcing a limit, or routing.
|
|
33
|
+
* On a `string[]`, `verbatim[]`, or `enum[]` field, the engine tests each
|
|
34
|
+
* element of the list on its own. A document passes `eq`, `in`, `startsWith`,
|
|
35
|
+
* `endsWith`, `contains`, `wildcard`, or `regex` when one element passes the
|
|
36
|
+
* test. However, a document passes `ne` or `nin` only when every element
|
|
37
|
+
* differs from the values.
|
|
118
38
|
*
|
|
119
|
-
* The engine
|
|
120
|
-
*
|
|
39
|
+
* The engine applies the range tests `gt`, `gte`, `lt`, `lte`, and `between`
|
|
40
|
+
* to a single `string` or `verbatim` field whose type includes `sortable`. It
|
|
41
|
+
* throws `SEARCH_INVALID_FILTER` for a text range on any other field. It
|
|
42
|
+
* orders the values as a sort on the field does, so it compares their case
|
|
43
|
+
* folds first and compares their raw code points only where the folds are
|
|
44
|
+
* equal.
|
|
121
45
|
*
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
readonly PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE";
|
|
129
|
-
readonly NOT_FOUND: "NOT_FOUND";
|
|
130
|
-
readonly TASK_NOT_FOUND: "TASK_NOT_FOUND";
|
|
131
|
-
readonly TASK_NOT_CANCELLABLE: "TASK_NOT_CANCELLABLE";
|
|
132
|
-
readonly TASK_OWNED_BY_ANOTHER_INSTANCE: "TASK_OWNED_BY_ANOTHER_INSTANCE";
|
|
133
|
-
readonly TASK_INTERRUPTED: "TASK_INTERRUPTED";
|
|
134
|
-
readonly TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS";
|
|
135
|
-
readonly HOOK_ERROR: "HOOK_ERROR";
|
|
136
|
-
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
137
|
-
};
|
|
138
|
-
/**
|
|
139
|
-
* Any one of the codes in {@link ServerErrorCodes}.
|
|
46
|
+
* A pattern field is a `verbatim` or `verbatim[]` field, or a `string` or
|
|
47
|
+
* `string[]` field whose type includes `pattern`. On a pattern field, the
|
|
48
|
+
* engine answers `eq`, `ne`, `in`, `nin`, `startsWith`, `endsWith`,
|
|
49
|
+
* `contains`, `wildcard`, and `regex` from the field's pattern index, and
|
|
50
|
+
* `caseFold` applies to each of those tests. The engine compares the code
|
|
51
|
+
* points of each value as they are stored, with no Unicode normalisation.
|
|
140
52
|
*
|
|
141
|
-
*
|
|
142
|
-
|
|
143
|
-
type
|
|
144
|
-
|
|
145
|
-
*
|
|
146
|
-
* a server, or where the caller cannot read the answer.
|
|
53
|
+
* On an `enum` or `enum[]` field, the engine answers `eq`, `ne`, `in`, `nin`,
|
|
54
|
+
* `startsWith`, and `endsWith` from the field's index of values. A `string` or
|
|
55
|
+
* `string[]` field whose type leaves out `pattern` keeps no index of whole
|
|
56
|
+
* values, so the engine throws `SEARCH_INVALID_FILTER` for those six tests,
|
|
57
|
+
* and for `matchesAny` and `containsAll`, on such a field.
|
|
147
58
|
*
|
|
148
|
-
* The
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
59
|
+
* The engine also throws `SEARCH_INVALID_FILTER` in these cases:
|
|
60
|
+
*
|
|
61
|
+
* - The filter sets `contains`, `wildcard`, `regex`, or `caseFold` on a field
|
|
62
|
+
* that is not a pattern field.
|
|
63
|
+
* - The text or the pattern of a test on a pattern field holds more than 1,024
|
|
64
|
+
* code points.
|
|
65
|
+
* - A literal test under `caseFold` has a text whose case fold holds more than
|
|
66
|
+
* 2,048 code points.
|
|
67
|
+
* - A `wildcard` or `regex` pattern breaks its syntax or one of its limits.
|
|
154
68
|
*
|
|
155
69
|
* @public
|
|
156
70
|
*/
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
71
|
+
type StringFilter = Pick<ComparisonFilter, 'eq' | 'ne'> & {
|
|
72
|
+
/** This matches a value that comes after the text in sort order. */
|
|
73
|
+
gt?: string;
|
|
74
|
+
/** This matches a value that comes before the text in sort order. */
|
|
75
|
+
lt?: string;
|
|
76
|
+
/** This matches a value equal to the text or after it in sort order. */
|
|
77
|
+
gte?: string;
|
|
78
|
+
/** This matches a value equal to the text or before it in sort order. */
|
|
79
|
+
lte?: string;
|
|
80
|
+
/** This matches a value inside the inclusive range in sort order, given as `[low, high]`. */
|
|
81
|
+
between?: [string, string];
|
|
82
|
+
/** This matches a field equal to any value in the list, which holds at most 65,536 values. */
|
|
83
|
+
in?: string[];
|
|
84
|
+
/** This matches a field that differs from every value in the list, which holds at most 65,536 values. */
|
|
85
|
+
nin?: string[];
|
|
86
|
+
/** This matches a field starting with the text. */
|
|
87
|
+
startsWith?: string;
|
|
88
|
+
/** This matches a field ending with the text. */
|
|
89
|
+
endsWith?: string;
|
|
90
|
+
/** This matches a pattern field whose value holds the text anywhere in it. */
|
|
91
|
+
contains?: string;
|
|
92
|
+
/**
|
|
93
|
+
* This matches a pattern field when the whole value matches the wildcard
|
|
94
|
+
* pattern. For example, `INV-*-2024` matches `INV-0042-2024`.
|
|
95
|
+
*
|
|
96
|
+
* In the pattern, `*` matches any sequence of code points, including an
|
|
97
|
+
* empty one, and `?` matches exactly one code point. Write `\` before a code
|
|
98
|
+
* point to match that code point itself, so `\*` matches an asterisk.
|
|
99
|
+
*
|
|
100
|
+
* The engine throws `SEARCH_INVALID_FILTER` for a pattern that ends in a
|
|
101
|
+
* `\` with no code point after it. It throws the same error for a pattern
|
|
102
|
+
* with more than 2,048 positions. Each `*`, each `?`, and each other code
|
|
103
|
+
* point counts as one position, except that under `caseFold` a code point
|
|
104
|
+
* counts once for each code point of its case fold.
|
|
105
|
+
*/
|
|
106
|
+
wildcard?: string;
|
|
107
|
+
/**
|
|
108
|
+
* This matches a pattern field when some part of the value matches the
|
|
109
|
+
* regular expression. `^` and `$` match only at the start and at the end of
|
|
110
|
+
* the whole value.
|
|
111
|
+
*
|
|
112
|
+
* The engine accepts literal code points, `.`, `\d`, `\w`, and `\s`, sets
|
|
113
|
+
* such as `[a-z]` and `[^0-9]`, groups, and `|`. It also accepts the repeats
|
|
114
|
+
* `*`, `+`, `?`, `{n}`, `{n,}`, and `{n,m}`, the anchors `^` and `$`, the
|
|
115
|
+
* word edge `\b`, and number ranges such as `<1-65535>`. A number range
|
|
116
|
+
* matches the digits of any whole number from its low end to its high end.
|
|
117
|
+
* Write `\` before an ASCII punctuation mark to match the mark itself. The
|
|
118
|
+
* `.` matches any code point, including a line break.
|
|
119
|
+
*
|
|
120
|
+
* The matcher never backtracks, so it checks a value in at most as many
|
|
121
|
+
* steps as the value's code points multiplied by the pattern's positions.
|
|
122
|
+
*
|
|
123
|
+
* The engine throws `SEARCH_INVALID_FILTER` for any construct outside that
|
|
124
|
+
* syntax, such as a back-reference, a lookaround, a lazy repeat, or an inline
|
|
125
|
+
* flag. It throws the same error when the groups of a pattern nest more than
|
|
126
|
+
* 32 deep, when a count is above 2,048, and when a pattern holds more than
|
|
127
|
+
* 2,048 positions. When the operator of an HTTP server sets its `allowRegex`
|
|
128
|
+
* option to false, the server refuses every `regex` test.
|
|
129
|
+
*/
|
|
130
|
+
regex?: string;
|
|
131
|
+
/**
|
|
132
|
+
* When this is true, the engine compares the case fold of each value of a
|
|
133
|
+
* pattern field with the case fold of the text, so a test for `error`
|
|
134
|
+
* matches `ERROR`. It applies to `eq`, `ne`, `in`, `nin`, `startsWith`,
|
|
135
|
+
* `endsWith`, `contains`, `wildcard`, and `regex`.
|
|
136
|
+
*
|
|
137
|
+
* Under `caseFold`, a set that does not open with `^` can also match a
|
|
138
|
+
* sequence of code points. When a member that the set holds on its own folds
|
|
139
|
+
* to several code points, the set matches that whole fold, so `[ß]` matches
|
|
140
|
+
* `ss`.
|
|
141
|
+
*/
|
|
142
|
+
caseFold?: boolean;
|
|
164
143
|
};
|
|
165
144
|
/**
|
|
166
|
-
*
|
|
145
|
+
* Tests the contents of a list field, which is a `number[]`, `boolean[]`,
|
|
146
|
+
* `enum[]`, `verbatim[]`, or `string[]` field.
|
|
147
|
+
*
|
|
148
|
+
* The engine throws `SEARCH_INVALID_FILTER` for these tests on any other
|
|
149
|
+
* field, for a value whose type differs from the type of the list's elements,
|
|
150
|
+
* and for `containsAll` or `matchesAny` on a `string[]` field whose type leaves
|
|
151
|
+
* out `pattern`.
|
|
167
152
|
*
|
|
168
153
|
* @public
|
|
169
154
|
*/
|
|
170
|
-
type
|
|
155
|
+
type ArrayFilter = {
|
|
156
|
+
/** This matches a list holding every one of the values, at most 65,536 of them, so an empty set of values matches every list. */
|
|
157
|
+
containsAll?: (string | number | boolean)[];
|
|
158
|
+
/** This matches a list holding at least one of the values, at most 65,536 of them. */
|
|
159
|
+
matchesAny?: (string | number | boolean)[];
|
|
160
|
+
/** This compares the number of elements in the list. */
|
|
161
|
+
size?: ComparisonFilter;
|
|
162
|
+
};
|
|
171
163
|
/**
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* The last arm exists for a server's `onRequest` hook, which rejects a request
|
|
176
|
-
* under a code of its own, such as `UNAUTHORIZED`, and the client then passes
|
|
177
|
-
* that code through unchanged. An editor still completes every code Narsil
|
|
178
|
-
* defines.
|
|
164
|
+
* Tests whether a field carries a value at all, without looking at what it
|
|
165
|
+
* holds.
|
|
179
166
|
*
|
|
180
167
|
* @public
|
|
181
168
|
*/
|
|
182
|
-
type
|
|
169
|
+
type PresenceFilter = {
|
|
170
|
+
/** This matches a document where the field holds a value other than null. */
|
|
171
|
+
exists?: boolean;
|
|
172
|
+
/** This matches a document where the field is absent or null. */
|
|
173
|
+
notExists?: boolean;
|
|
174
|
+
/** This matches a document where the field is absent, null, an empty string, or an empty list. */
|
|
175
|
+
isEmpty?: boolean;
|
|
176
|
+
/** This matches a document where the field holds a value other than an empty string or an empty list. */
|
|
177
|
+
isNotEmpty?: boolean;
|
|
178
|
+
};
|
|
183
179
|
/**
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* Catch it, read {@link NarsilError.code} to decide what to do, and read
|
|
187
|
-
* {@link NarsilError.details} for the values that caused it. The engine lets
|
|
188
|
-
* this error propagate unchanged, so the code you catch is the code the
|
|
189
|
-
* failing operation raised.
|
|
180
|
+
* Matches a `geopoint` field against a circle drawn on the earth.
|
|
190
181
|
*
|
|
191
182
|
* @public
|
|
192
183
|
*/
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
184
|
+
type GeoRadiusFilter = {
|
|
185
|
+
/** The engine tests the field against this circle. */
|
|
186
|
+
radius: {
|
|
187
|
+
/** The centre has this latitude, in degrees from -90 to 90. For any other value, the engine throws `SEARCH_INVALID_FILTER`. */
|
|
188
|
+
lat: number;
|
|
189
|
+
/** The centre has this longitude, in degrees from -180 to 180. For any other value, the engine throws `SEARCH_INVALID_FILTER`. */
|
|
190
|
+
lon: number;
|
|
191
|
+
/** The circle has this radius, measured in `unit`. */
|
|
192
|
+
distance: number;
|
|
193
|
+
/**
|
|
194
|
+
* The engine measures `distance` in kilometres under `'km'`, in miles
|
|
195
|
+
* under `'mi'`, and in metres under `'m'`. For any other unit, it throws
|
|
196
|
+
* `SEARCH_INVALID_FILTER`.
|
|
197
|
+
*/
|
|
198
|
+
unit: 'km' | 'mi' | 'm';
|
|
199
|
+
/** The engine matches the points inside the circle while this is true, which is the default, and the points outside it while this is false. */
|
|
200
|
+
inside?: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* The engine measures each distance with the Haversine formula on a sphere
|
|
203
|
+
* by default, and with Vincenty's formula on the WGS-84 ellipsoid while
|
|
204
|
+
* this is true. Vincenty's formula iterates, so the engine takes longer
|
|
205
|
+
* to compute each distance. The two formulas differ by less than 0.3% under about
|
|
206
|
+
* 100 km, while across a continent they can differ by up to 0.5%.
|
|
207
|
+
*/
|
|
208
|
+
highPrecision?: boolean;
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
211
|
/**
|
|
212
|
-
*
|
|
213
|
-
* another entry point of this package raises.
|
|
212
|
+
* Matches a `geopoint` field against a polygon drawn on the earth.
|
|
214
213
|
*
|
|
215
|
-
*
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
* @public
|
|
215
|
+
*/
|
|
216
|
+
type GeoPolygonFilter = {
|
|
217
|
+
/** The engine tests the field against this polygon. */
|
|
218
|
+
polygon: {
|
|
219
|
+
/**
|
|
220
|
+
* The engine closes the ring through these corners in the order that you
|
|
221
|
+
* list them, so you can leave the first point off the end. It throws
|
|
222
|
+
* `SEARCH_INVALID_FILTER` for a ring of fewer than three corners, which
|
|
223
|
+
* encloses no area, and for a corner whose latitude is outside -90 to 90
|
|
224
|
+
* or whose longitude is outside -180 to 180. It also throws that error for
|
|
225
|
+
* a ring of more than 65,536 corners. List the corners counter-clockwise
|
|
226
|
+
* around the area, as in an exterior ring of GeoJSON. Where the corners
|
|
227
|
+
* span 180 degrees of longitude or more, the engine matches the area on
|
|
228
|
+
* the left of that path, so a ring listed that way can cross the
|
|
229
|
+
* antimeridian or span more than half the globe.
|
|
230
|
+
*/
|
|
231
|
+
points: Array<{
|
|
232
|
+
lat: number;
|
|
233
|
+
lon: number;
|
|
234
|
+
}>;
|
|
235
|
+
/** The engine matches the points inside the polygon while this is true, which is the default, and the points outside it while this is false. */
|
|
236
|
+
inside?: boolean;
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* Either shape a `geopoint` field is matched against.
|
|
220
241
|
*
|
|
221
|
-
* @
|
|
222
|
-
|
|
242
|
+
* @public
|
|
243
|
+
*/
|
|
244
|
+
type GeoFilter = GeoRadiusFilter | GeoPolygonFilter;
|
|
245
|
+
/**
|
|
246
|
+
* The filter one field accepts. Which of these forms applies follows from the
|
|
247
|
+
* field's declared type.
|
|
223
248
|
*
|
|
224
249
|
* @public
|
|
225
250
|
*/
|
|
226
|
-
|
|
251
|
+
type FieldFilter = ComparisonFilter | StringFilter | ArrayFilter | PresenceFilter | GeoFilter;
|
|
252
|
+
/**
|
|
253
|
+
* The filter that a query runs, built from per-field tests and the boolean
|
|
254
|
+
* operators that combine them.
|
|
255
|
+
*
|
|
256
|
+
* The engine answers every test from an index that it keeps for the field. It
|
|
257
|
+
* applies the filter before scoring, so a narrow filter makes a search
|
|
258
|
+
* cheaper. A filter nests at most 30 levels deep and holds at most 1,024
|
|
259
|
+
* tests, counted across every field and nested expression. Past either limit,
|
|
260
|
+
* the engine throws `SEARCH_INVALID_FILTER`, while it throws
|
|
261
|
+
* `SEARCH_INVALID_FIELD` for a test on a field that the schema leaves out.
|
|
262
|
+
*
|
|
263
|
+
* @public
|
|
264
|
+
*/
|
|
265
|
+
type FilterExpression = {
|
|
266
|
+
/** These per-field tests are keyed by field name, and a document has to satisfy every entry. */
|
|
267
|
+
fields?: Record<string, FieldFilter>;
|
|
268
|
+
/** Every nested expression has to match. */
|
|
269
|
+
and?: FilterExpression[];
|
|
270
|
+
/** At least one nested expression has to match. */
|
|
271
|
+
or?: FilterExpression[];
|
|
272
|
+
/** The nested expression has to fail. */
|
|
273
|
+
not?: FilterExpression;
|
|
274
|
+
};
|
|
227
275
|
|
|
228
276
|
/**
|
|
229
|
-
*
|
|
230
|
-
* one.
|
|
277
|
+
* Everything {@link Narsil.suggest} accepts.
|
|
231
278
|
*
|
|
232
|
-
*
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
279
|
+
* @public
|
|
280
|
+
*/
|
|
281
|
+
interface SuggestParams {
|
|
282
|
+
/** The returned terms complete this text. */
|
|
283
|
+
prefix: string;
|
|
284
|
+
/** The lookup returns this many completions, most widely used first, and 10 by default. */
|
|
285
|
+
limit?: number;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Everything {@link Narsil.listDocuments} accepts.
|
|
289
|
+
*
|
|
290
|
+
* {@link Narsil.listDocuments} reads the stored documents without ranking them,
|
|
291
|
+
* which is how you page through a whole index. Leave `cursor` out to start at
|
|
292
|
+
* the first document, then pass back the cursor each result carries until it
|
|
293
|
+
* comes back null.
|
|
294
|
+
*
|
|
295
|
+
* A cursor belongs to the sort it was made under, so pass the same `sort` back
|
|
296
|
+
* with it. Changing `sort` invalidates the cursor, and the engine then throws
|
|
297
|
+
* `SEARCH_INVALID_CURSOR` rather than returning a page from the wrong order.
|
|
237
298
|
*
|
|
238
299
|
* @public
|
|
239
300
|
*/
|
|
240
|
-
|
|
301
|
+
interface ListParams {
|
|
241
302
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* `compactVectors`, `optimizeVectors`, `createIndex`, and `dropIndex`. The
|
|
246
|
-
* engine emits the event after a call that throws as well, because a call can
|
|
247
|
-
* change the index before it throws. It also emits the event after it reloads
|
|
248
|
-
* an index, once a shared invalidation adapter reports that another instance
|
|
249
|
-
* saved that index. The engine emits one event per batch, however many
|
|
250
|
-
* documents the batch holds.
|
|
251
|
-
*
|
|
252
|
-
* The engine emits the event once a query can see the change, which means
|
|
253
|
-
* after every worker copy applies the change and after any rebalance in
|
|
254
|
-
* progress replays it. A query that a listener sends from its handler
|
|
255
|
-
* therefore returns results that include the change. The engine waits for the
|
|
256
|
-
* change to become visible only while a listener is registered for the event.
|
|
303
|
+
* This cursor comes from a previous result, and continues where it stopped.
|
|
304
|
+
* The engine ties a cursor to the sort that produced it, and it throws
|
|
305
|
+
* `SEARCH_INVALID_CURSOR` for a cursor sent back under a different sort.
|
|
257
306
|
*/
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
307
|
+
cursor?: string;
|
|
308
|
+
/** The page carries this many documents, and 10 by default. The engine raises a value below one to one. */
|
|
309
|
+
limit?: number;
|
|
310
|
+
/** This narrows the listing to the documents the filter accepts. */
|
|
311
|
+
filters?: FilterExpression;
|
|
262
312
|
/**
|
|
263
|
-
*
|
|
264
|
-
* the
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
* index.
|
|
313
|
+
* This orders the listing by field value rather than by document id, and the
|
|
314
|
+
* engine applies the fields in the order they are listed. Pass an object
|
|
315
|
+
* keyed by field, or a list of fields in the order they apply. It breaks a
|
|
316
|
+
* tie on document id, and it sorts by at most eight fields. The engine uses
|
|
317
|
+
* document-id order when you leave this out.
|
|
269
318
|
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
* main thread serves every query, because it holds every document. The first
|
|
273
|
-
* request after the delay then starts a new pool. The delay starts at one
|
|
274
|
-
* second and doubles up to a minute while replacements keep failing.
|
|
319
|
+
* The engine reads every document the listing covers to build a sorted page,
|
|
320
|
+
* so a sorted listing costs more than the default order on a large index.
|
|
275
321
|
*/
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
* partitions. */
|
|
306
|
-
partitionRebalance: {
|
|
307
|
-
/** This is the name of the index that the engine rebalanced. */
|
|
308
|
-
indexName: string;
|
|
309
|
-
/** This is the number of partitions before the rebalance. */
|
|
310
|
-
oldCount: number;
|
|
311
|
-
/** This is the number of partitions after the rebalance. */
|
|
312
|
-
newCount: number;
|
|
313
|
-
};
|
|
322
|
+
sort?: SortSpec;
|
|
323
|
+
/** This chooses how much of each stored document comes back, and the whole document by default. */
|
|
324
|
+
document?: DocumentProjection;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Which engine answers a query: keyword matching, vector similarity, or both
|
|
329
|
+
* merged into one ranking.
|
|
330
|
+
*
|
|
331
|
+
* @public
|
|
332
|
+
*/
|
|
333
|
+
type SearchMode = 'fulltext' | 'vector' | 'hybrid';
|
|
334
|
+
/**
|
|
335
|
+
* How many of a query's terms a document has to carry. `all` demands every
|
|
336
|
+
* term, `any` accepts one, and a number demands that many.
|
|
337
|
+
*
|
|
338
|
+
* @public
|
|
339
|
+
*/
|
|
340
|
+
type TermMatchPolicy = 'all' | 'any' | number;
|
|
341
|
+
/**
|
|
342
|
+
* One field of a sort, and the direction that field orders by.
|
|
343
|
+
*
|
|
344
|
+
* @public
|
|
345
|
+
*/
|
|
346
|
+
interface SortField {
|
|
347
|
+
/** The field the engine reads, which may name a nested field with dots. */
|
|
348
|
+
field: string;
|
|
349
|
+
/** Ascending or descending order for this field. */
|
|
350
|
+
direction: 'asc' | 'desc';
|
|
314
351
|
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
/** This is the number of documents in the index, or in the partition on a
|
|
324
|
-
* cluster node. */
|
|
325
|
-
documentCount: number;
|
|
326
|
-
/** This is the number of documents that the current partitions of the
|
|
327
|
-
* index can hold, or that the partition can hold on a cluster node. */
|
|
328
|
-
capacity: number;
|
|
329
|
-
/** This is the number of partitions in the index. */
|
|
330
|
-
partitionCount: number;
|
|
331
|
-
/** On a cluster node, this is the partition that crossed the mark, while
|
|
332
|
-
* outside a cluster the field is absent. */
|
|
333
|
-
partitionId?: number;
|
|
334
|
-
};
|
|
335
|
-
/**
|
|
336
|
-
* The process uses nine tenths of its heap, as measured during a write or a
|
|
337
|
-
* load, so the next large index can end the process with an out-of-memory
|
|
338
|
-
* error.
|
|
339
|
-
*
|
|
340
|
-
* Where `--max-old-space-size` or `--max-old-space-size-percentage` sets a
|
|
341
|
-
* limit, on the command line or in `NODE_OPTIONS`, the engine measures the
|
|
342
|
-
* used bytes against that limit, which `heapLimit` then reports. Where
|
|
343
|
-
* neither flag sets a limit, the engine measures the share of the heap that
|
|
344
|
-
* V8 reports as no longer available. V8 reports a limit about 192 MB above
|
|
345
|
-
* the true ceiling, so a process on a default heap below about 2 GB can end before
|
|
346
|
-
* this event fires.
|
|
347
|
-
*
|
|
348
|
-
* The engine emits the event once per crossing, then arms it again once the
|
|
349
|
-
* free share of the heap recovers to two tenths. Raise the limit with
|
|
350
|
-
* `--max-old-space-size-percentage` or `--max-old-space-size`, or close an
|
|
351
|
-
* idle index; see {@link ProcessMemoryReport.heapLimit}.
|
|
352
|
+
* Where a document's field holds a list, the engine sorts that document by
|
|
353
|
+
* one value from the list: the smallest under `'min'`, the largest under
|
|
354
|
+
* `'max'`, and the mean or the median of the list's numbers under `'avg'`
|
|
355
|
+
* or `'median'`. Where you leave this out, the engine uses `'min'` for an
|
|
356
|
+
* ascending sort and `'max'` for a descending one. It sorts by a field that
|
|
357
|
+
* holds a single value as that value stands, under every mode. It throws
|
|
358
|
+
* `SEARCH_INVALID_FIELD` for `'avg'` or `'median'` on a field that the
|
|
359
|
+
* schema declares as anything other than `number` or `number[]`.
|
|
352
360
|
*/
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
* reached that point. */
|
|
356
|
-
indexName: string;
|
|
357
|
-
/** This is the heap that the process uses, in bytes. */
|
|
358
|
-
heapUsed: number;
|
|
359
|
-
/** This is the size in bytes that the heap can grow to. */
|
|
360
|
-
heapLimit: number;
|
|
361
|
-
/** This is the estimate of the bytes that the index holds. */
|
|
362
|
-
estimatedMemoryBytes: number;
|
|
363
|
-
};
|
|
364
|
-
/** The engine started, completed, or failed a rebuild that brings the terms
|
|
365
|
-
* of an index up to the current analysis of its language module. */
|
|
366
|
-
analysisRebuild: {
|
|
367
|
-
/** This is the name of the index under rebuild. */
|
|
368
|
-
indexName: string;
|
|
369
|
-
/** This is the stage that the rebuild has reached. */
|
|
370
|
-
status: 'started' | 'completed' | 'failed';
|
|
371
|
-
/** This is the number of partitions that the rebuild has covered so far. */
|
|
372
|
-
partitionsRebuilt: number;
|
|
373
|
-
/** This is the number of partitions that the rebuild covers in total. */
|
|
374
|
-
partitionCount: number;
|
|
375
|
-
/** This is the error that stopped the rebuild, which only a `failed`
|
|
376
|
-
* status includes. */
|
|
377
|
-
error?: Error;
|
|
378
|
-
};
|
|
379
|
-
/** The engine started, completed, or failed the rewrite of an index that you
|
|
380
|
-
* saved with an earlier release. The engine rewrites the index as it
|
|
381
|
-
* recovers it, before it serves the index's first request. Because the
|
|
382
|
-
* engine writes the new manifest last, the earlier files stay intact through
|
|
383
|
-
* a failed rewrite. The engine then starts the rewrite again the next time
|
|
384
|
-
* it recovers the index. Without index lifecycle settings, the engine
|
|
385
|
-
* recovers every index before {@link createNarsil} returns, so pass the
|
|
386
|
-
* listener in the `events` setting of {@link createNarsil}. */
|
|
387
|
-
layoutUpgrade: {
|
|
388
|
-
/** This is the name of the index under rewrite. */
|
|
389
|
-
indexName: string;
|
|
390
|
-
/** This is the stage that the rewrite has reached. */
|
|
391
|
-
status: 'started' | 'completed' | 'failed';
|
|
392
|
-
/** This is `manifest` where the earlier index is a segment manifest with
|
|
393
|
-
* its files, and `bundle` where it is a single snapshot bundle. */
|
|
394
|
-
layout: 'manifest' | 'bundle';
|
|
395
|
-
/** This is the error that stopped the rewrite, which only a `failed`
|
|
396
|
-
* status includes. */
|
|
397
|
-
error?: Error;
|
|
398
|
-
};
|
|
399
|
-
/** A write to the write-ahead log or a checkpoint failed, so the writes since
|
|
400
|
-
* the last checkpoint are at risk. */
|
|
401
|
-
durabilityError: {
|
|
402
|
-
/** This is the error that the durability layer threw. */
|
|
403
|
-
error: Error;
|
|
404
|
-
};
|
|
405
|
-
/** The invalidation channel failed, so this instance can serve partitions
|
|
406
|
-
* that another instance has since changed. */
|
|
407
|
-
invalidationError: {
|
|
408
|
-
/** This is the error that the adapter threw. */
|
|
409
|
-
error: Error;
|
|
410
|
-
};
|
|
411
|
-
};
|
|
361
|
+
mode?: 'min' | 'max' | 'avg' | 'median';
|
|
362
|
+
}
|
|
412
363
|
/**
|
|
413
|
-
*
|
|
414
|
-
*
|
|
364
|
+
* A sort, either as an object keyed by field or as a list of fields in the
|
|
365
|
+
* order they apply.
|
|
366
|
+
*
|
|
367
|
+
* Both forms order by the first field, break a tie on the second, and carry on
|
|
368
|
+
* that way. Prefer the list where the order of the fields matters, because
|
|
369
|
+
* JavaScript moves an all-digit key such as `2024` to the front of an object
|
|
370
|
+
* and the list keeps the order you wrote.
|
|
415
371
|
*
|
|
416
372
|
* @public
|
|
417
373
|
*/
|
|
418
|
-
type
|
|
419
|
-
[K in keyof NarsilEventMap]?: (payload: NarsilEventMap[K]) => void;
|
|
420
|
-
};
|
|
421
|
-
|
|
374
|
+
type SortSpec = Record<string, 'asc' | 'desc'> | readonly SortField[];
|
|
422
375
|
/**
|
|
423
|
-
*
|
|
424
|
-
* asked for alongside them.
|
|
376
|
+
* Everything {@link Narsil.query} accepts.
|
|
425
377
|
*
|
|
426
|
-
*
|
|
427
|
-
*
|
|
378
|
+
* Set `term` for keyword search, `vector` for similarity search, and `mode`
|
|
379
|
+
* when you want both. The engine matches nothing for a query carrying neither
|
|
380
|
+
* of them, so page through an index with {@link Narsil.listDocuments}
|
|
381
|
+
* instead.
|
|
428
382
|
*
|
|
429
383
|
* @public
|
|
430
384
|
*/
|
|
431
|
-
interface
|
|
432
|
-
/**
|
|
433
|
-
|
|
385
|
+
interface QueryParams {
|
|
386
|
+
/** The engine analyses this text with the index's language module and searches for the terms that result. */
|
|
387
|
+
term?: string;
|
|
388
|
+
/** The engine searches the term in these fields, and in every text field in the schema by default. */
|
|
389
|
+
fields?: string[];
|
|
434
390
|
/**
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
* sets neither of them. The engine also counts each pinned document that
|
|
440
|
-
* the query does not match, since it places that document among the hits.
|
|
391
|
+
* The engine scores only the documents that pass this filter. It throws
|
|
392
|
+
* `SEARCH_INVALID_FILTER` for an operand of the wrong shape, and for an
|
|
393
|
+
* operator on a field of another type, such as `startsWith` on a number
|
|
394
|
+
* field.
|
|
441
395
|
*/
|
|
442
|
-
|
|
396
|
+
filters?: FilterExpression;
|
|
443
397
|
/**
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
* `
|
|
447
|
-
*
|
|
448
|
-
* with only a fraction of that field's vectors. For a hybrid query the
|
|
449
|
-
* engine fuses two rankings, so the count is exact only where each of those
|
|
450
|
-
* rankings contains every matching document. Where you pin a document from
|
|
451
|
-
* outside the hits that the engine fetches, the engine reports true only
|
|
452
|
-
* where it holds every match of the query, because only then can it test
|
|
453
|
-
* whether the query matches that document.
|
|
398
|
+
* The engine multiplies the score from each named field by its weight. It
|
|
399
|
+
* throws `SEARCH_INVALID_FIELD` for any field other than a text field that
|
|
400
|
+
* the schema declares, and `CONFIG_INVALID` for a weight that is not a
|
|
401
|
+
* finite number.
|
|
454
402
|
*/
|
|
455
|
-
|
|
456
|
-
/** The engine
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
403
|
+
boost?: Record<string, number>;
|
|
404
|
+
/** The engine gathers term statistics this way, and follows the index's `defaultScoring` where the query sets none. */
|
|
405
|
+
scoring?: ScoringMode;
|
|
406
|
+
/**
|
|
407
|
+
* The engine drops any hit scoring below this value. It ranks with BM25,
|
|
408
|
+
* which has no fixed upper bound, so a floor that suits one index and one
|
|
409
|
+
* query can reject every hit in another.
|
|
410
|
+
*/
|
|
411
|
+
minScore?: number;
|
|
412
|
+
/**
|
|
413
|
+
* The engine keeps a document only where the document matches this many
|
|
414
|
+
* query terms, under the same `tolerance` and `prefixLength` that the search
|
|
415
|
+
* uses. One term is enough by default.
|
|
416
|
+
*/
|
|
417
|
+
termMatch?: TermMatchPolicy;
|
|
418
|
+
/**
|
|
419
|
+
* The engine matches an indexed term within this edit distance of a query
|
|
420
|
+
* term, so it finds a document for a query with a typo. It counts each
|
|
421
|
+
* Unicode code point as one character. Set an integer from 0 to 10.
|
|
422
|
+
*/
|
|
423
|
+
tolerance?: number;
|
|
424
|
+
/**
|
|
425
|
+
* The engine applies `tolerance` only to the indexed terms that share this
|
|
426
|
+
* many leading characters with the query term, or to the terms that start
|
|
427
|
+
* with the whole query term when the query term is shorter. Set an integer
|
|
428
|
+
* from 0 to 1,024; the default is 2.
|
|
429
|
+
*/
|
|
430
|
+
prefixLength?: number;
|
|
431
|
+
/**
|
|
432
|
+
* With this set, the engine treats the last query term as an unfinished
|
|
433
|
+
* word, so `secur` matches `security`. The engine matches that last term by
|
|
434
|
+
* its stem or by completing it, while `tolerance` applies only to the earlier
|
|
435
|
+
* terms, which have to match whole. The engine scores completions against a
|
|
436
|
+
* shared document frequency. It also ranks them below whole-word matches.
|
|
437
|
+
* The engine ignores this setting where `exact` is true, and the setting is
|
|
438
|
+
* false by default.
|
|
439
|
+
*/
|
|
440
|
+
prefix?: boolean;
|
|
441
|
+
/**
|
|
442
|
+
* With this set, the engine also matches each query word of three or more
|
|
443
|
+
* characters inside the longer words of every field whose type includes
|
|
444
|
+
* `partial`, so a search for `proof` matches a document with `waterproof`
|
|
445
|
+
* in such a field. The engine counts each Unicode code point as one
|
|
446
|
+
* character. It looks for the query word, before stemming, inside each word
|
|
447
|
+
* exactly as that word appears in a document.
|
|
448
|
+
*
|
|
449
|
+
* The engine adds at most 50 such words to a query, which it divides as
|
|
450
|
+
* evenly as it can among the query words. Within the share of each query
|
|
451
|
+
* word, it adds first the words that the most documents contain. It scores
|
|
452
|
+
* a match inside a longer word in proportion to the part of that word that
|
|
453
|
+
* the query word makes up, so it scores such a match below a whole-word
|
|
454
|
+
* match at the same frequency in a field of the same length. With
|
|
455
|
+
* `highlight`, it tags each whole word that contains a query word in a
|
|
456
|
+
* searched `partial` field.
|
|
457
|
+
*
|
|
458
|
+
* The engine applies no `tolerance` to these matches. It ignores this
|
|
459
|
+
* setting where `exact` is true or where the searched fields include no
|
|
460
|
+
* `partial` field. Where the setting is absent, the engine treats it as
|
|
461
|
+
* false, while it throws `CONFIG_INVALID` for any value other than `true`
|
|
462
|
+
* or `false`.
|
|
463
|
+
*/
|
|
464
|
+
partialWords?: boolean;
|
|
465
|
+
/**
|
|
466
|
+
* With this set, the engine matches each query term only against an equal
|
|
467
|
+
* indexed term, so it turns off fuzzy matching, prefix completion, and
|
|
468
|
+
* partial-word matching. The engine still stems the query, because the
|
|
469
|
+
* index stores stemmed terms, so a search for `running` matches a document
|
|
470
|
+
* that contains `runs` through the stem that both words share.
|
|
471
|
+
*/
|
|
472
|
+
exact?: boolean;
|
|
473
|
+
/**
|
|
474
|
+
* The engine counts the values of these fields across the matching
|
|
475
|
+
* documents, and each entry sets how it cuts and sorts that field's counts.
|
|
476
|
+
* For a field outside the schema, it counts the values that the documents
|
|
477
|
+
* store. It throws `SEARCH_INVALID_FIELD` for a `geopoint` or a vector
|
|
478
|
+
* field.
|
|
479
|
+
*/
|
|
480
|
+
facets?: FacetConfig;
|
|
481
|
+
/**
|
|
482
|
+
* The engine sorts the hits by the values of these fields, in place of the
|
|
483
|
+
* relevance ranking. Pass an object keyed by field, or a list of fields in
|
|
484
|
+
* the order that the engine compares them. The engine sorts by a `number`,
|
|
485
|
+
* `boolean`, or `enum` field, by a text field whose type includes
|
|
486
|
+
* `sortable`, or by a list of any of these, which it reduces to one value by
|
|
487
|
+
* the entry's `mode`. It throws `SEARCH_INVALID_FIELD` for a sort on a
|
|
488
|
+
* `geopoint` or a vector field, because neither type has an order. It throws
|
|
489
|
+
* the same code for a sort on any other text field, since the engine keeps
|
|
490
|
+
* up to the first 512 code points of every document's value in memory to
|
|
491
|
+
* sort by a text field. The engine orders hybrid results by fusion, so it
|
|
492
|
+
* throws `SEARCH_INVALID_MODE` for a sort on a hybrid query. It also throws
|
|
493
|
+
* that code for a direction other than `asc` and `desc`.
|
|
494
|
+
*/
|
|
495
|
+
sort?: SortSpec;
|
|
496
|
+
/** These settings collapse the hits into groups by field value. */
|
|
497
|
+
group?: GroupConfig;
|
|
498
|
+
/**
|
|
499
|
+
* The query returns this many hits, and 10 by default. Pass 0 to read the
|
|
500
|
+
* match count with no hits. The engine reads a value below 0 as 0. It falls
|
|
501
|
+
* back to the default for `NaN` and for an infinite value, so a page size
|
|
502
|
+
* that you compute from user input never fails the query.
|
|
503
|
+
*/
|
|
504
|
+
limit?: number;
|
|
505
|
+
/** The query skips this many hits before returning. A deep offset costs more than a cursor. */
|
|
506
|
+
offset?: number;
|
|
507
|
+
/** This cursor comes from a previous result's `cursor`, and pages without an offset's cost. */
|
|
508
|
+
searchAfter?: string;
|
|
509
|
+
/** These settings name the fields that come back with highlighted snippets. */
|
|
510
|
+
highlight?: HighlightConfig;
|
|
511
|
+
/** These documents take fixed positions, ahead of the ranking. */
|
|
512
|
+
pinned?: Array<{
|
|
513
|
+
docId: string;
|
|
514
|
+
position: number;
|
|
515
|
+
}>;
|
|
516
|
+
/** This picks which engine answers the query. Keyword search runs by default. */
|
|
517
|
+
mode?: SearchMode;
|
|
518
|
+
/** These vector-search inputs are required in `vector` and `hybrid` mode. */
|
|
519
|
+
vector?: VectorQueryConfig;
|
|
520
|
+
/** These settings control how the keyword and vector rankings merge in `hybrid` mode. */
|
|
521
|
+
hybrid?: HybridConfig;
|
|
522
|
+
/**
|
|
523
|
+
* Setting this returns relevance scores on a sorted query. A query that
|
|
524
|
+
* names a sort ranks by sort values alone and computes no scores, so its
|
|
525
|
+
* hits carry none until this restores them. A query without a sort ignores
|
|
526
|
+
* this and always carries scores.
|
|
527
|
+
*/
|
|
528
|
+
includeScores?: boolean;
|
|
529
|
+
/** Setting this returns the numbers behind each hit's score, which is what you read when a ranking surprises you. */
|
|
530
|
+
includeScoreComponents?: boolean;
|
|
531
|
+
/** This chooses how much of each stored document comes back, and the whole document by default. */
|
|
532
|
+
document?: DocumentProjection;
|
|
468
533
|
}
|
|
469
534
|
/**
|
|
470
|
-
* How much of
|
|
471
|
-
* trust a count or a ranking.
|
|
535
|
+
* How much of a stored document each hit carries back.
|
|
472
536
|
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
537
|
+
* Pass `false` when the ids and scores are all you need, and every hit's
|
|
538
|
+
* `document` is then an empty object. Pass `include` to keep named fields
|
|
539
|
+
* alone, or `exclude` to drop named fields and keep the rest; naming both
|
|
540
|
+
* keeps the included fields and then drops the excluded ones from those. Use
|
|
541
|
+
* dots to name a nested field, so `author.name` addresses the `name` inside
|
|
542
|
+
* `author`, and a name that matches no field changes nothing.
|
|
543
|
+
*
|
|
544
|
+
* Drop a vector field on a similarity search, because the engine otherwise
|
|
545
|
+
* reads every hit's vector back out of the index and writes it into the
|
|
546
|
+
* response.
|
|
477
547
|
*
|
|
478
548
|
* @public
|
|
479
549
|
*/
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
timedOutPartitions: number;
|
|
487
|
-
/** The search counts a partition here when the node holding it returned an error, and when no active replica served it. */
|
|
488
|
-
failedPartitions: number;
|
|
489
|
-
}
|
|
550
|
+
type DocumentProjection = boolean | {
|
|
551
|
+
/** Names the fields to keep, so every field left out of this list is dropped. */
|
|
552
|
+
include?: string[];
|
|
553
|
+
/** Names the fields to drop, so every other field is kept. */
|
|
554
|
+
exclude?: string[];
|
|
555
|
+
};
|
|
490
556
|
/**
|
|
491
|
-
*
|
|
557
|
+
* Vector-search inputs passed under `QueryParams.vector`.
|
|
492
558
|
*
|
|
493
|
-
*
|
|
559
|
+
* Supply either a raw `value` array or a `text` string for auto-embedding;
|
|
560
|
+
* passing both throws `EMBEDDING_CONFIG_INVALID`. Result count is governed
|
|
561
|
+
* by the outer query's `limit`, not by any field on this object.
|
|
494
562
|
*
|
|
495
563
|
* @public
|
|
496
564
|
*/
|
|
497
|
-
interface
|
|
498
|
-
/** The document is stored under this id. */
|
|
499
|
-
id: string;
|
|
565
|
+
interface VectorQueryConfig {
|
|
500
566
|
/**
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* no score unless it sets `includeScores`.
|
|
567
|
+
* Name of the schema field that holds the vector to compare against.
|
|
568
|
+
* Must reference a field declared as `vector[N]` in the index schema.
|
|
504
569
|
*/
|
|
505
|
-
|
|
506
|
-
/** This is the stored document. */
|
|
507
|
-
document: T;
|
|
508
|
-
/** These are the parts the score was built from, which arrive when the query asked for them. */
|
|
509
|
-
scoreComponents?: ScoreComponents;
|
|
510
|
-
/** These highlighted snippets are keyed by field, and arrive when the query asked for highlighting. */
|
|
511
|
-
highlights?: Record<string, HighlightMatch>;
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* The numbers BM25 combined into one hit's score, which is what you read when
|
|
515
|
-
* a ranking surprises you.
|
|
516
|
-
*
|
|
517
|
-
* @public
|
|
518
|
-
*/
|
|
519
|
-
interface ScoreComponents {
|
|
570
|
+
field: string;
|
|
520
571
|
/**
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
* the bare term.
|
|
572
|
+
* Raw query vector, given as a number array or a `Float32Array`. Length
|
|
573
|
+
* must match the indexed field's dimension or the search rejects the
|
|
574
|
+
* request with `VECTOR_DIMENSION_MISMATCH`.
|
|
525
575
|
*/
|
|
526
|
-
|
|
527
|
-
/** Each field the query searched holds this many tokens, keyed by field. */
|
|
528
|
-
fieldLengths: Record<string, number>;
|
|
529
|
-
/** Each query term carries this inverse document frequency, which is what makes a rare term count for more. */
|
|
530
|
-
idf: Record<string, number>;
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* A highlighted field, ready to render.
|
|
534
|
-
*
|
|
535
|
-
* @public
|
|
536
|
-
*/
|
|
537
|
-
interface HighlightMatch {
|
|
538
|
-
/** This is the field's text around the match, wrapped in the query's tags. */
|
|
539
|
-
snippet: string;
|
|
576
|
+
value?: number[] | Float32Array;
|
|
540
577
|
/**
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
* the field alone, the engine lists only the matches that the snippet
|
|
544
|
-
* displays. Every offset is a character count from the start of the original
|
|
545
|
-
* field, whatever the snippet contains.
|
|
578
|
+
* Text to embed at query time using the index or instance embedding
|
|
579
|
+
* adapter. Mutually exclusive with `value`; requires a configured adapter.
|
|
546
580
|
*/
|
|
547
|
-
|
|
548
|
-
start: number;
|
|
549
|
-
end: number;
|
|
550
|
-
}>;
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Counts for one faceted field.
|
|
554
|
-
*
|
|
555
|
-
* @public
|
|
556
|
-
*/
|
|
557
|
-
interface FacetResult {
|
|
558
|
-
/** This many documents match per value, keyed by value. */
|
|
559
|
-
values: Record<string, number>;
|
|
560
|
-
/** This is the number of entries in `values`, which is at most the facet's `limit`. */
|
|
561
|
-
count: number;
|
|
581
|
+
text?: string;
|
|
562
582
|
/**
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
* merged count of a value that is common overall but rare on one of them
|
|
570
|
-
* can lack the matches on that one. A bound of 0 means that `values` holds
|
|
571
|
-
* every matching value, each with its exact count.
|
|
583
|
+
* Score floor applied during ranking. Hits scoring below this value
|
|
584
|
+
* are dropped before `limit` is enforced, so the returned hit count
|
|
585
|
+
* can be smaller than `limit` even when more documents exist. The
|
|
586
|
+
* floor is interpreted in score space for every metric; for
|
|
587
|
+
* `euclidean`, distance is mapped to a similarity score of
|
|
588
|
+
* `1 / (1 + distance)` first. Defaults to no floor.
|
|
572
589
|
*/
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
|
|
590
|
+
similarity?: number;
|
|
591
|
+
/**
|
|
592
|
+
* Similarity metric used for ranking. Defaults to `cosine`. Choose
|
|
593
|
+
* `dotProduct` for raw inner-product scoring on already-normalised
|
|
594
|
+
* vectors and `euclidean` for distance-based ordering.
|
|
595
|
+
*/
|
|
596
|
+
metric?: 'cosine' | 'dotProduct' | 'euclidean';
|
|
597
|
+
/**
|
|
598
|
+
* HNSW exploration factor for approximate search. Higher values raise
|
|
599
|
+
* recall at the cost of latency. Ignored while the field is still
|
|
600
|
+
* served by the brute-force backend. Defaults to the engine's built-in
|
|
601
|
+
* value when omitted.
|
|
602
|
+
*/
|
|
603
|
+
efSearch?: number;
|
|
604
|
+
/**
|
|
605
|
+
* How many times `limit` a quantized field re-scores against its
|
|
606
|
+
* full-precision vectors before it returns the best `limit`. A value below
|
|
607
|
+
* 1 or one that is not a finite number fails with `CONFIG_INVALID`. The
|
|
608
|
+
* engine ignores this on a field whose quantization is `none`. When a query
|
|
609
|
+
* omits it, the engine takes 3 for `osq1` and `osq2`, 2 for `osq8`, and 2
|
|
610
|
+
* for `osq4` at 1,024 dimensions and above, but 5 for `osq4` below 1,024,
|
|
611
|
+
* where a four-bit code ranks the true neighbours less reliably.
|
|
612
|
+
*/
|
|
613
|
+
oversample?: number;
|
|
589
614
|
}
|
|
590
615
|
/**
|
|
591
|
-
*
|
|
592
|
-
* without building or ranking a single hit.
|
|
616
|
+
* How a hybrid query merges its keyword ranking with its vector ranking.
|
|
593
617
|
*
|
|
594
|
-
*
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
/** The query matches this many documents. */
|
|
598
|
-
count: number;
|
|
599
|
-
/** `count` holds the exact number of matches where this is true, and a number at or below the true total where it is false, under the rule in {@link QueryResult.countExact}. */
|
|
600
|
-
countExact: boolean;
|
|
601
|
-
/** The count took this many milliseconds. */
|
|
602
|
-
elapsed: number;
|
|
603
|
-
/** This turns true when the index's terms came from an older analysis than its language module produces now. */
|
|
604
|
-
analysisStale?: boolean;
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* What a batch write returns. One bad document never abandons the rest, so
|
|
608
|
-
* read both lists.
|
|
618
|
+
* `rrf` combines the two by rank alone, which needs no tuning and handles
|
|
619
|
+
* scores that live on different scales. `linear` blends the scores directly,
|
|
620
|
+
* which gives you control once you know what each side's scores look like.
|
|
609
621
|
*
|
|
610
622
|
* @public
|
|
611
623
|
*/
|
|
612
|
-
interface
|
|
613
|
-
/** The engine
|
|
614
|
-
|
|
615
|
-
/** The engine
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}>;
|
|
624
|
+
interface HybridConfig {
|
|
625
|
+
/** The engine merges the rankings this way, and by rank fusion by default. It throws `CONFIG_INVALID` for any other value. */
|
|
626
|
+
strategy?: 'rrf' | 'linear';
|
|
627
|
+
/** The engine uses this rank-fusion constant under `rrf` alone, where a larger value reduces the lead of the top ranks. Set a whole number of at least 1, or leave it out for 60. The engine throws `CONFIG_INVALID` for any other value. */
|
|
628
|
+
k?: number;
|
|
629
|
+
/** The engine uses this weight of the vector score, from 0 to 1, under `linear` alone, and 0.5 where you leave it out. It throws `CONFIG_INVALID` for a value outside that range. */
|
|
630
|
+
alpha?: number;
|
|
620
631
|
}
|
|
621
632
|
/**
|
|
622
|
-
*
|
|
623
|
-
* refused line, so read the refusals to learn which documents it skipped.
|
|
633
|
+
* Fields a query counts values for, keyed by field name.
|
|
624
634
|
*
|
|
625
635
|
* @public
|
|
626
636
|
*/
|
|
627
|
-
interface
|
|
628
|
-
/**
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
637
|
+
interface FacetConfig {
|
|
638
|
+
/** Each key names a field the query counts values for. */
|
|
639
|
+
[field: string]: {
|
|
640
|
+
/** The engine returns this many values for the field, in the order of `sort`. An engine returns every value where you leave this out, while a cluster returns 10, or every range of a field that sets `ranges`. */
|
|
641
|
+
limit?: number;
|
|
642
|
+
/** The engine orders the returned values by their count, putting the highest first under `'desc'`, which is the default, and the lowest first under `'asc'`. Under `'asc'`, each cluster node sends the count of up to 10,000 values of the field, so the lowest counts are exact wherever no node holds more values than that. */
|
|
643
|
+
sort?: 'asc' | 'desc';
|
|
644
|
+
/** The engine counts a numeric field's matches into these ranges, with one count for each range. A cluster search counts up to 1,000 ranges on a field and throws `CONFIG_INVALID` for more. */
|
|
645
|
+
ranges?: Array<{
|
|
646
|
+
from: number;
|
|
647
|
+
to: number;
|
|
648
|
+
}>;
|
|
649
|
+
};
|
|
638
650
|
}
|
|
639
651
|
/**
|
|
640
|
-
*
|
|
652
|
+
* How a query collapses its hits into groups.
|
|
641
653
|
*
|
|
642
654
|
* @public
|
|
643
655
|
*/
|
|
644
|
-
interface
|
|
645
|
-
/** The
|
|
646
|
-
|
|
647
|
-
/** The
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
* the real heap by a meaningful factor. Use {@link Narsil.getMemoryStats}
|
|
656
|
-
* when sizing host memory.
|
|
656
|
+
interface GroupConfig {
|
|
657
|
+
/** The values of these fields define a group, and several fields group by their combination. */
|
|
658
|
+
fields: string[];
|
|
659
|
+
/** The engine returns this many hits from each group, best first, and one hit where you leave this out. */
|
|
660
|
+
maxPerGroup?: number;
|
|
661
|
+
/** The engine returns this many groups, best first, and every group where you leave this out. */
|
|
662
|
+
limit?: number;
|
|
663
|
+
/**
|
|
664
|
+
* The engine folds every hit of each group into one value, such as a sum or
|
|
665
|
+
* an average, including the hits beyond `maxPerGroup`. In cluster mode the
|
|
666
|
+
* coordinator fetches up to 10,000 hits of each group to fold.
|
|
657
667
|
*/
|
|
658
|
-
|
|
659
|
-
/** The index analyses text with this language module. */
|
|
660
|
-
language: string;
|
|
661
|
-
/** The index was created with this field layout. */
|
|
662
|
-
schema: SchemaDefinition;
|
|
668
|
+
reduce?: GroupReducer;
|
|
663
669
|
}
|
|
664
670
|
/**
|
|
665
|
-
*
|
|
671
|
+
* Folds the hits of one group into a single value.
|
|
666
672
|
*
|
|
667
673
|
* @public
|
|
668
674
|
*/
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
/**
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
reopenCount: number;
|
|
684
|
-
}
|
|
675
|
+
type GroupReducer = {
|
|
676
|
+
/**
|
|
677
|
+
* Folds one hit into the running value.
|
|
678
|
+
*
|
|
679
|
+
* @param accumulator - What the previous call returned, or what
|
|
680
|
+
* `initialValue` produced for the first hit.
|
|
681
|
+
* @param doc - The hit's stored document.
|
|
682
|
+
* @param score - The hit's relevance score.
|
|
683
|
+
* @returns The new running value.
|
|
684
|
+
*/
|
|
685
|
+
reducer: (accumulator: unknown, doc: AnyDocument, score: number) => unknown;
|
|
686
|
+
/** Produces the starting value for each group. The engine calls it once per group. */
|
|
687
|
+
initialValue: () => unknown;
|
|
688
|
+
};
|
|
685
689
|
/**
|
|
686
|
-
*
|
|
687
|
-
*
|
|
690
|
+
* This configuration names the fields that receive highlighted snippets. It
|
|
691
|
+
* also sets how the engine marks those snippets up.
|
|
692
|
+
*
|
|
693
|
+
* The engine analyses the text of each returned field again to tag every word
|
|
694
|
+
* that it matched, so it tags the same words whatever the index's
|
|
695
|
+
* `trackPositions` setting is. It tags a word whose stem equals a query stem,
|
|
696
|
+
* and a word within the query's `tolerance` of a query stem. For a `prefix`
|
|
697
|
+
* query, it tags a word for the last query term only when that word completes
|
|
698
|
+
* the term or shares its stem.
|
|
688
699
|
*
|
|
689
700
|
* @public
|
|
690
701
|
*/
|
|
691
|
-
interface
|
|
692
|
-
/**
|
|
693
|
-
|
|
694
|
-
/** The
|
|
695
|
-
|
|
702
|
+
interface HighlightConfig {
|
|
703
|
+
/** The engine highlights these fields. */
|
|
704
|
+
fields: string[];
|
|
705
|
+
/** The engine writes this before each match, and writes `<mark>` by default. */
|
|
706
|
+
preTag?: string;
|
|
707
|
+
/** The engine writes this after each match, and writes `</mark>` by default. */
|
|
708
|
+
postTag?: string;
|
|
696
709
|
/**
|
|
697
|
-
*
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
*
|
|
710
|
+
* The engine takes this many characters of the field around the densest run
|
|
711
|
+
* of matches, 200 by default. It returns a snippet longer than that number,
|
|
712
|
+
* because it then adds the opening and closing tags, and an ellipsis at each
|
|
713
|
+
* end where it cuts the field.
|
|
701
714
|
*/
|
|
702
|
-
|
|
715
|
+
maxSnippetLength?: number;
|
|
703
716
|
}
|
|
717
|
+
|
|
704
718
|
/**
|
|
705
|
-
*
|
|
706
|
-
*
|
|
719
|
+
* Every code a {@link NarsilError} carries, grouped by the part of the engine
|
|
720
|
+
* that raises it.
|
|
721
|
+
*
|
|
722
|
+
* Match on the code rather than on the message, because a code is stable and a
|
|
723
|
+
* message is not. The HTTP server maps each code to a status, so a code also
|
|
724
|
+
* tells you whether the caller or the engine is at fault.
|
|
707
725
|
*
|
|
708
726
|
* @public
|
|
709
727
|
*/
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
728
|
+
declare const ErrorCodes: {
|
|
729
|
+
readonly SCHEMA_INVALID_TYPE: "SCHEMA_INVALID_TYPE";
|
|
730
|
+
readonly SCHEMA_DEPTH_EXCEEDED: "SCHEMA_DEPTH_EXCEEDED";
|
|
731
|
+
readonly SCHEMA_INVALID_VECTOR_DIMENSION: "SCHEMA_INVALID_VECTOR_DIMENSION";
|
|
732
|
+
readonly SCHEMA_INVALID_GEOPOINT: "SCHEMA_INVALID_GEOPOINT";
|
|
733
|
+
readonly DOC_NOT_FOUND: "DOC_NOT_FOUND";
|
|
734
|
+
readonly DOC_ALREADY_EXISTS: "DOC_ALREADY_EXISTS";
|
|
735
|
+
readonly DOC_VALIDATION_FAILED: "DOC_VALIDATION_FAILED";
|
|
736
|
+
readonly INDEX_NOT_FOUND: "INDEX_NOT_FOUND";
|
|
737
|
+
readonly INDEX_ALREADY_EXISTS: "INDEX_ALREADY_EXISTS";
|
|
738
|
+
readonly INDEX_ORPHANED: "INDEX_ORPHANED";
|
|
739
|
+
readonly INDEX_REOPEN_CAPACITY_EXHAUSTED: "INDEX_REOPEN_CAPACITY_EXHAUSTED";
|
|
740
|
+
readonly INSTANCE_SHUT_DOWN: "INSTANCE_SHUT_DOWN";
|
|
741
|
+
readonly PARTITION_CORRUPTED: "PARTITION_CORRUPTED";
|
|
742
|
+
readonly PARTITION_REBALANCING_BACKPRESSURE: "PARTITION_REBALANCING_BACKPRESSURE";
|
|
743
|
+
readonly WORKER_CRASHED: "WORKER_CRASHED";
|
|
744
|
+
readonly WORKER_BUSY: "WORKER_BUSY";
|
|
745
|
+
readonly WORKER_TIMEOUT: "WORKER_TIMEOUT";
|
|
746
|
+
readonly WORKER_ACTION_FAILED: "WORKER_ACTION_FAILED";
|
|
747
|
+
readonly PERSISTENCE_SAVE_FAILED: "PERSISTENCE_SAVE_FAILED";
|
|
748
|
+
readonly PERSISTENCE_LOAD_FAILED: "PERSISTENCE_LOAD_FAILED";
|
|
749
|
+
readonly PERSISTENCE_DELETE_FAILED: "PERSISTENCE_DELETE_FAILED";
|
|
750
|
+
readonly PERSISTENCE_CRC_MISMATCH: "PERSISTENCE_CRC_MISMATCH";
|
|
751
|
+
readonly PERSISTENCE_WAL_CORRUPT: "PERSISTENCE_WAL_CORRUPT";
|
|
752
|
+
readonly PERSISTENCE_FSYNC_FAILED: "PERSISTENCE_FSYNC_FAILED";
|
|
753
|
+
readonly SEARCH_INVALID_FIELD: "SEARCH_INVALID_FIELD";
|
|
754
|
+
readonly VECTOR_DIMENSION_MISMATCH: "VECTOR_DIMENSION_MISMATCH";
|
|
755
|
+
readonly SEARCH_INVALID_FILTER: "SEARCH_INVALID_FILTER";
|
|
756
|
+
readonly SEARCH_INVALID_MODE: "SEARCH_INVALID_MODE";
|
|
757
|
+
readonly SEARCH_INVALID_CURSOR: "SEARCH_INVALID_CURSOR";
|
|
758
|
+
readonly SEARCH_RESULT_WINDOW_EXCEEDED: "SEARCH_RESULT_WINDOW_EXCEEDED";
|
|
759
|
+
readonly SEARCH_WORK_CAP_EXCEEDED: "SEARCH_WORK_CAP_EXCEEDED";
|
|
760
|
+
readonly LANGUAGE_NOT_SUPPORTED: "LANGUAGE_NOT_SUPPORTED";
|
|
761
|
+
readonly ENVELOPE_VERSION_MISMATCH: "ENVELOPE_VERSION_MISMATCH";
|
|
762
|
+
readonly ENVELOPE_INVALID_MAGIC: "ENVELOPE_INVALID_MAGIC";
|
|
763
|
+
readonly PARTITION_CAPACITY_EXCEEDED: "PARTITION_CAPACITY_EXCEEDED";
|
|
764
|
+
readonly EMBEDDING_FAILED: "EMBEDDING_FAILED";
|
|
765
|
+
readonly EMBEDDING_DIMENSION_MISMATCH: "EMBEDDING_DIMENSION_MISMATCH";
|
|
766
|
+
readonly EMBEDDING_NO_SOURCE: "EMBEDDING_NO_SOURCE";
|
|
767
|
+
readonly EMBEDDING_CONFIG_INVALID: "EMBEDDING_CONFIG_INVALID";
|
|
768
|
+
readonly DOC_MISSING_REQUIRED_FIELD: "DOC_MISSING_REQUIRED_FIELD";
|
|
769
|
+
readonly CONFIG_INVALID: "CONFIG_INVALID";
|
|
770
|
+
readonly QUERY_ROUTING_FAILED: "QUERY_ROUTING_FAILED";
|
|
771
|
+
readonly QUERY_PARTIAL_FAILURE: "QUERY_PARTIAL_FAILURE";
|
|
772
|
+
readonly QUERY_NODE_TIMEOUT: "QUERY_NODE_TIMEOUT";
|
|
773
|
+
readonly QUERY_NO_ACTIVE_REPLICA: "QUERY_NO_ACTIVE_REPLICA";
|
|
774
|
+
readonly CLUSTER_OPERATION_UNSUPPORTED: "CLUSTER_OPERATION_UNSUPPORTED";
|
|
775
|
+
readonly ALLOCATION_NO_DATA_NODES: "ALLOCATION_NO_DATA_NODES";
|
|
776
|
+
readonly ALLOCATION_INVALID_CONFIG: "ALLOCATION_INVALID_CONFIG";
|
|
777
|
+
readonly ALLOCATION_FAILED: "ALLOCATION_FAILED";
|
|
778
|
+
readonly CONTROLLER_METADATA_INVALID: "CONTROLLER_METADATA_INVALID";
|
|
779
|
+
readonly NODE_BOOTSTRAP_FAILED: "NODE_BOOTSTRAP_FAILED";
|
|
780
|
+
readonly NODE_ALREADY_JOINED: "NODE_ALREADY_JOINED";
|
|
781
|
+
readonly NODE_NOT_JOINED: "NODE_NOT_JOINED";
|
|
782
|
+
readonly NODE_NOT_READY: "NODE_NOT_READY";
|
|
783
|
+
readonly NODE_NOT_CONTROLLER: "NODE_NOT_CONTROLLER";
|
|
784
|
+
readonly COORDINATOR_DEPENDENCY_MISSING: "COORDINATOR_DEPENDENCY_MISSING";
|
|
785
|
+
readonly TRANSPORT_DEPENDENCY_MISSING: "TRANSPORT_DEPENDENCY_MISSING";
|
|
786
|
+
readonly REPLICATION_ENTRY_INVALID: "REPLICATION_ENTRY_INVALID";
|
|
787
|
+
readonly REPLICATION_INSYNC_REMOVAL_FAILED: "REPLICATION_INSYNC_REMOVAL_FAILED";
|
|
788
|
+
readonly REPLICATION_ROLLBACK_FAILED: "REPLICATION_ROLLBACK_FAILED";
|
|
789
|
+
readonly REPLICATION_LOG_FULL: "REPLICATION_LOG_FULL";
|
|
790
|
+
readonly REPLICATION_ENTRY_CORRUPT: "REPLICATION_ENTRY_CORRUPT";
|
|
791
|
+
readonly REPLICATION_SNAPSHOT_CORRUPT: "REPLICATION_SNAPSHOT_CORRUPT";
|
|
792
|
+
readonly REPLICATION_TERM_MISMATCH: "REPLICATION_TERM_MISMATCH";
|
|
793
|
+
readonly REPLICATION_SYNC_FAILED: "REPLICATION_SYNC_FAILED";
|
|
794
|
+
readonly PARTITION_NOT_PRIMARY: "PARTITION_NOT_PRIMARY";
|
|
795
|
+
readonly PARTITION_UNASSIGNED: "PARTITION_UNASSIGNED";
|
|
796
|
+
readonly INSUFFICIENT_REPLICAS: "INSUFFICIENT_REPLICAS";
|
|
797
|
+
readonly SNAPSHOT_SYNC_UNAUTHORIZED: "SNAPSHOT_SYNC_UNAUTHORIZED";
|
|
798
|
+
readonly SNAPSHOT_SYNC_REQUEST_INVALID: "SNAPSHOT_SYNC_REQUEST_INVALID";
|
|
799
|
+
readonly SNAPSHOT_SYNC_INDEX_NOT_FOUND: "SNAPSHOT_SYNC_INDEX_NOT_FOUND";
|
|
800
|
+
readonly SNAPSHOT_SYNC_CAPACITY_EXHAUSTED: "SNAPSHOT_SYNC_CAPACITY_EXHAUSTED";
|
|
801
|
+
readonly SNAPSHOT_SYNC_SNAPSHOT_FAILED: "SNAPSHOT_SYNC_SNAPSHOT_FAILED";
|
|
802
|
+
readonly SNAPSHOT_SYNC_DECODE_FAILED: "SNAPSHOT_SYNC_DECODE_FAILED";
|
|
803
|
+
readonly SNAPSHOT_SYNC_FRAME_INVALID: "SNAPSHOT_SYNC_FRAME_INVALID";
|
|
804
|
+
readonly SNAPSHOT_SYNC_HEADER_INVALID: "SNAPSHOT_SYNC_HEADER_INVALID";
|
|
805
|
+
readonly SNAPSHOT_SYNC_HEADER_MISMATCH: "SNAPSHOT_SYNC_HEADER_MISMATCH";
|
|
806
|
+
readonly SNAPSHOT_SYNC_CHUNK_OUT_OF_ORDER: "SNAPSHOT_SYNC_CHUNK_OUT_OF_ORDER";
|
|
807
|
+
readonly SNAPSHOT_SYNC_CHUNK_OVERFLOW: "SNAPSHOT_SYNC_CHUNK_OVERFLOW";
|
|
808
|
+
readonly SNAPSHOT_SYNC_CHUNK_SIZE_EXCEEDED: "SNAPSHOT_SYNC_CHUNK_SIZE_EXCEEDED";
|
|
809
|
+
readonly SNAPSHOT_SYNC_CHUNK_MISSING: "SNAPSHOT_SYNC_CHUNK_MISSING";
|
|
810
|
+
readonly SNAPSHOT_SYNC_END_MISSING: "SNAPSHOT_SYNC_END_MISSING";
|
|
811
|
+
readonly SNAPSHOT_SYNC_CHECKSUM_MISMATCH: "SNAPSHOT_SYNC_CHECKSUM_MISMATCH";
|
|
812
|
+
readonly SNAPSHOT_SYNC_PRIMARY_ERROR: "SNAPSHOT_SYNC_PRIMARY_ERROR";
|
|
813
|
+
readonly SNAPSHOT_SYNC_NO_TARGETS: "SNAPSHOT_SYNC_NO_TARGETS";
|
|
814
|
+
readonly SNAPSHOT_SYNC_TRANSPORT_FAILED: "SNAPSHOT_SYNC_TRANSPORT_FAILED";
|
|
815
|
+
readonly SNAPSHOT_SYNC_SCHEMA_UNAVAILABLE: "SNAPSHOT_SYNC_SCHEMA_UNAVAILABLE";
|
|
816
|
+
readonly SNAPSHOT_SYNC_RESTORE_FAILED: "SNAPSHOT_SYNC_RESTORE_FAILED";
|
|
817
|
+
readonly SNAPSHOT_SYNC_RESTORE_CLEANUP_FAILED: "SNAPSHOT_SYNC_RESTORE_CLEANUP_FAILED";
|
|
818
|
+
readonly SNAPSHOT_SYNC_TIMEOUT: "SNAPSHOT_SYNC_TIMEOUT";
|
|
819
|
+
readonly SNAPSHOT_SYNC_ALLOCATION_UNAVAILABLE: "SNAPSHOT_SYNC_ALLOCATION_UNAVAILABLE";
|
|
820
|
+
readonly SNAPSHOT_SYNC_NOT_ASSIGNED: "SNAPSHOT_SYNC_NOT_ASSIGNED";
|
|
821
|
+
readonly SNAPSHOT_SYNC_ABORTED: "SNAPSHOT_SYNC_ABORTED";
|
|
822
|
+
};
|
|
723
823
|
/**
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
* Removing a vector leaves a tombstone in the graph, and enough of them slow a
|
|
728
|
-
* search down. Read this to decide when compaction earns its cost.
|
|
824
|
+
* Any one of the codes in {@link ErrorCodes}, which is the type to narrow on
|
|
825
|
+
* when you branch on a failure the engine raised.
|
|
729
826
|
*
|
|
730
827
|
* @public
|
|
731
828
|
*/
|
|
732
|
-
|
|
733
|
-
/** This describes the named vector field. */
|
|
734
|
-
fieldName: string;
|
|
735
|
-
/**
|
|
736
|
-
* Tombstones make up this share of the graph's nodes, from 0 to 1. Before
|
|
737
|
-
* the first build, where {@link VectorMaintenanceResult.graphCount} reads 0,
|
|
738
|
-
* the engine divides by the number of stored vectors, because no graph
|
|
739
|
-
* exists yet.
|
|
740
|
-
*/
|
|
741
|
-
tombstoneRatio: number;
|
|
742
|
-
/** The field holds this many HNSW graphs: 0 before the first build and 1 once a graph exists. */
|
|
743
|
-
graphCount: number;
|
|
744
|
-
/** This many vectors wait outside the graph, which a search scans one by one. */
|
|
745
|
-
bufferSize: number;
|
|
746
|
-
/** This stays true while a graph build runs. */
|
|
747
|
-
building: boolean;
|
|
748
|
-
/** {@link Narsil.compactVectors} would take about this many milliseconds. */
|
|
749
|
-
estimatedCompactMs: number;
|
|
750
|
-
/** {@link Narsil.optimizeVectors} would take about this many milliseconds. */
|
|
751
|
-
estimatedOptimizeMs: number;
|
|
752
|
-
}
|
|
829
|
+
type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
753
830
|
/**
|
|
754
|
-
*
|
|
831
|
+
* Every code the HTTP layer raises for a failure that arises before or around
|
|
832
|
+
* the engine call, such as parsing the body, enforcing a limit, or routing.
|
|
755
833
|
*
|
|
756
|
-
*
|
|
834
|
+
* The engine raises none of these, so a failure carrying one of them says the
|
|
835
|
+
* request never reached the engine.
|
|
757
836
|
*
|
|
758
837
|
* @public
|
|
759
838
|
*/
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
839
|
+
declare const ServerErrorCodes: {
|
|
840
|
+
readonly INVALID_REQUEST: "INVALID_REQUEST";
|
|
841
|
+
readonly INVALID_JSON: "INVALID_JSON";
|
|
842
|
+
readonly EMPTY_BODY: "EMPTY_BODY";
|
|
843
|
+
readonly PAYLOAD_TOO_LARGE: "PAYLOAD_TOO_LARGE";
|
|
844
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
845
|
+
readonly TASK_NOT_FOUND: "TASK_NOT_FOUND";
|
|
846
|
+
readonly TASK_NOT_CANCELLABLE: "TASK_NOT_CANCELLABLE";
|
|
847
|
+
readonly TASK_OWNED_BY_ANOTHER_INSTANCE: "TASK_OWNED_BY_ANOTHER_INSTANCE";
|
|
848
|
+
readonly TASK_INTERRUPTED: "TASK_INTERRUPTED";
|
|
849
|
+
readonly TOO_MANY_REQUESTS: "TOO_MANY_REQUESTS";
|
|
850
|
+
readonly HOOK_ERROR: "HOOK_ERROR";
|
|
851
|
+
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
852
|
+
};
|
|
766
853
|
/**
|
|
767
|
-
*
|
|
768
|
-
*
|
|
854
|
+
* Any one of the codes in {@link ServerErrorCodes}.
|
|
855
|
+
*
|
|
856
|
+
* @public
|
|
857
|
+
*/
|
|
858
|
+
type ServerErrorCode = (typeof ServerErrorCodes)[keyof typeof ServerErrorCodes];
|
|
859
|
+
/**
|
|
860
|
+
* Every code that the caller's own side raises, where a request never reaches
|
|
861
|
+
* a server, or where the caller cannot read the answer.
|
|
769
862
|
*
|
|
770
|
-
*
|
|
863
|
+
* The HTTP client raises the first five. The React bindings raise
|
|
864
|
+
* `CLIENT_UNEXPECTED_ERROR` alone, which reports a fault inside a hook. No
|
|
865
|
+
* server sends any of them, so a failure under one means the exchange broke
|
|
866
|
+
* before the operation ran. `STATUS_BY_CODE` in `src/server/errors.ts`
|
|
867
|
+
* therefore maps none of them, because no request can arrive under one and no
|
|
868
|
+
* HTTP status belongs to one.
|
|
771
869
|
*
|
|
772
870
|
* @public
|
|
773
871
|
*/
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
elapsed: number;
|
|
783
|
-
}
|
|
784
|
-
|
|
872
|
+
declare const ClientErrorCodes: {
|
|
873
|
+
readonly CLIENT_CONNECTION_FAILED: "CLIENT_CONNECTION_FAILED";
|
|
874
|
+
readonly CLIENT_REQUEST_TIMEOUT: "CLIENT_REQUEST_TIMEOUT";
|
|
875
|
+
readonly CLIENT_REQUEST_ABORTED: "CLIENT_REQUEST_ABORTED";
|
|
876
|
+
readonly CLIENT_INVALID_RESPONSE: "CLIENT_INVALID_RESPONSE";
|
|
877
|
+
readonly CLIENT_TASK_TIMEOUT: "CLIENT_TASK_TIMEOUT";
|
|
878
|
+
readonly CLIENT_UNEXPECTED_ERROR: "CLIENT_UNEXPECTED_ERROR";
|
|
879
|
+
};
|
|
785
880
|
/**
|
|
786
|
-
*
|
|
787
|
-
* because a document has to satisfy all of them.
|
|
881
|
+
* Any one of the codes in {@link ClientErrorCodes}.
|
|
788
882
|
*
|
|
789
883
|
* @public
|
|
790
884
|
*/
|
|
791
|
-
type
|
|
792
|
-
/** This matches a field equal to the value, or a list field where one element equals it. */
|
|
793
|
-
eq?: number | string | boolean;
|
|
794
|
-
/**
|
|
795
|
-
* This matches a document that holds the field with a value other than this
|
|
796
|
-
* one, or a list field where every element differs from it, which an empty
|
|
797
|
-
* list does.
|
|
798
|
-
*/
|
|
799
|
-
ne?: number | string | boolean;
|
|
800
|
-
/** This matches a field greater than the number. */
|
|
801
|
-
gt?: number;
|
|
802
|
-
/** This matches a field less than the number. */
|
|
803
|
-
lt?: number;
|
|
804
|
-
/** This matches a field greater than or equal to the number. */
|
|
805
|
-
gte?: number;
|
|
806
|
-
/** This matches a field less than or equal to the number. */
|
|
807
|
-
lte?: number;
|
|
808
|
-
/** This matches a field inside the inclusive range, given as `[low, high]`. */
|
|
809
|
-
between?: [number, number];
|
|
810
|
-
};
|
|
885
|
+
type ClientErrorCode = (typeof ClientErrorCodes)[keyof typeof ClientErrorCodes];
|
|
811
886
|
/**
|
|
812
|
-
*
|
|
813
|
-
*
|
|
887
|
+
* Every code a {@link NarsilError} can carry: one the engine raised, one the
|
|
888
|
+
* HTTP layer raised, one the client raised, or any other string.
|
|
814
889
|
*
|
|
815
|
-
* The
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
*
|
|
890
|
+
* The last arm exists for a server's `onRequest` hook, which rejects a request
|
|
891
|
+
* under a code of its own, such as `UNAUTHORIZED`, and the client then passes
|
|
892
|
+
* that code through unchanged. An editor still completes every code Narsil
|
|
893
|
+
* defines.
|
|
819
894
|
*
|
|
820
|
-
*
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
*
|
|
895
|
+
* @public
|
|
896
|
+
*/
|
|
897
|
+
type NarsilErrorCode = ErrorCode | ServerErrorCode | ClientErrorCode | (string & {});
|
|
898
|
+
/**
|
|
899
|
+
* The error every part of the engine throws.
|
|
825
900
|
*
|
|
826
|
-
*
|
|
827
|
-
*
|
|
828
|
-
*
|
|
829
|
-
*
|
|
830
|
-
* On an `enum` or `enum[]` field, the engine answers `eq`, `ne`, `in`, `nin`,
|
|
831
|
-
* `startsWith`, and `endsWith` from the field's index of values. It throws
|
|
832
|
-
* `SEARCH_INVALID_FILTER` for `eq`, `ne`, `in`, `nin`, `startsWith`, or
|
|
833
|
-
* `endsWith` on a `string` or `string[]` field whose type leaves out
|
|
834
|
-
* `pattern`, because such a field keeps no index of whole values.
|
|
835
|
-
* The engine compares the code points of each value as stored, with no
|
|
836
|
-
* Unicode normalisation. It throws `SEARCH_INVALID_FILTER` for `contains` or
|
|
837
|
-
* `caseFold` on any other field, for a test text longer than 1,024 code points
|
|
838
|
-
* on a pattern field, and for a `caseFold` test whose text has a case fold
|
|
839
|
-
* longer than 2,048 code points.
|
|
901
|
+
* Catch it, read {@link NarsilError.code} to decide what to do, and read
|
|
902
|
+
* {@link NarsilError.details} for the values that caused it. The engine lets
|
|
903
|
+
* this error propagate unchanged, so the code you catch is the code the
|
|
904
|
+
* failing operation raised.
|
|
840
905
|
*
|
|
841
906
|
* @public
|
|
842
907
|
*/
|
|
843
|
-
|
|
844
|
-
/** This
|
|
845
|
-
|
|
846
|
-
/** This
|
|
847
|
-
|
|
848
|
-
/** This matches a value equal to the text or after it in sort order. */
|
|
849
|
-
gte?: string;
|
|
850
|
-
/** This matches a value equal to the text or before it in sort order. */
|
|
851
|
-
lte?: string;
|
|
852
|
-
/** This matches a value inside the inclusive range in sort order, given as `[low, high]`. */
|
|
853
|
-
between?: [string, string];
|
|
854
|
-
/** This matches a field equal to any value in the list, which holds at most 65,536 values. */
|
|
855
|
-
in?: string[];
|
|
856
|
-
/** This matches a field that differs from every value in the list, which holds at most 65,536 values. */
|
|
857
|
-
nin?: string[];
|
|
858
|
-
/** This matches a field starting with the text. */
|
|
859
|
-
startsWith?: string;
|
|
860
|
-
/** This matches a field ending with the text. */
|
|
861
|
-
endsWith?: string;
|
|
862
|
-
/** This matches a pattern field whose value holds the text anywhere in it. */
|
|
863
|
-
contains?: string;
|
|
908
|
+
declare class NarsilError extends Error {
|
|
909
|
+
/** This says which failure it is. */
|
|
910
|
+
readonly code: NarsilErrorCode;
|
|
911
|
+
/** This carries the values behind the failure, such as the field, index, or limit involved. It is empty when the code says everything. */
|
|
912
|
+
readonly details: Record<string, unknown>;
|
|
864
913
|
/**
|
|
865
|
-
*
|
|
866
|
-
*
|
|
867
|
-
*
|
|
868
|
-
*
|
|
914
|
+
* Builds an error carrying a code the caller can branch on.
|
|
915
|
+
*
|
|
916
|
+
* @param code - The failure this error reports, from {@link ErrorCodes} for
|
|
917
|
+
* an engine failure, {@link ServerErrorCodes} for one the HTTP layer raised,
|
|
918
|
+
* or {@link ClientErrorCodes} for one that stopped a request from reaching a
|
|
919
|
+
* server.
|
|
920
|
+
* @param message - Plain description, for a log or a person.
|
|
921
|
+
* @param details - Values behind the failure, which reach
|
|
922
|
+
* {@link NarsilError.details}.
|
|
869
923
|
*/
|
|
870
|
-
|
|
871
|
-
}
|
|
924
|
+
constructor(code: NarsilErrorCode, message: string, details?: Record<string, unknown>);
|
|
925
|
+
}
|
|
872
926
|
/**
|
|
873
|
-
*
|
|
874
|
-
*
|
|
927
|
+
* Reports whether a caught value is a {@link NarsilError}, including one that
|
|
928
|
+
* another entry point of this package raises.
|
|
875
929
|
*
|
|
876
|
-
*
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
930
|
+
* Each browser bundle holds its own copy of the class, so an `instanceof` test
|
|
931
|
+
* inside the React bindings returns false for an error that the client raises,
|
|
932
|
+
* although that error still holds its code. This function tests for the marker
|
|
933
|
+
* that the constructor writes, so it returns true for an error from any entry
|
|
934
|
+
* point.
|
|
880
935
|
*
|
|
881
|
-
* @
|
|
882
|
-
|
|
883
|
-
type ArrayFilter = {
|
|
884
|
-
/** This matches a list holding every one of the values, at most 65,536 of them, so an empty set of values matches every list. */
|
|
885
|
-
containsAll?: (string | number | boolean)[];
|
|
886
|
-
/** This matches a list holding at least one of the values, at most 65,536 of them. */
|
|
887
|
-
matchesAny?: (string | number | boolean)[];
|
|
888
|
-
/** This compares the number of elements in the list. */
|
|
889
|
-
size?: ComparisonFilter;
|
|
890
|
-
};
|
|
891
|
-
/**
|
|
892
|
-
* Tests whether a field carries a value at all, without looking at what it
|
|
893
|
-
* holds.
|
|
936
|
+
* @param value - The value that a `catch` block receives.
|
|
937
|
+
* @returns True where the value holds a code in {@link NarsilError.code}.
|
|
894
938
|
*
|
|
895
939
|
* @public
|
|
896
940
|
*/
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
exists?: boolean;
|
|
900
|
-
/** This matches a document where the field is absent or null. */
|
|
901
|
-
notExists?: boolean;
|
|
902
|
-
/** This matches a document where the field is absent, null, an empty string, or an empty list. */
|
|
903
|
-
isEmpty?: boolean;
|
|
904
|
-
/** This matches a document where the field holds a value other than an empty string or an empty list. */
|
|
905
|
-
isNotEmpty?: boolean;
|
|
906
|
-
};
|
|
941
|
+
declare function isNarsilError(value: unknown): value is NarsilError;
|
|
942
|
+
|
|
907
943
|
/**
|
|
908
|
-
*
|
|
944
|
+
* This map lists every event that the engine emits, with the payload of each
|
|
945
|
+
* one.
|
|
946
|
+
*
|
|
947
|
+
* {@link Narsil.on} registers a listener under a key from this map, so that the
|
|
948
|
+
* engine can pass the matching payload to that listener. Most of these events
|
|
949
|
+
* report work that the engine does in the background, away from the call that
|
|
950
|
+
* started it, so a failure that such an event reports never rejects a promise
|
|
951
|
+
* that you are holding.
|
|
909
952
|
*
|
|
910
953
|
* @public
|
|
911
954
|
*/
|
|
912
|
-
type
|
|
913
|
-
/**
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
955
|
+
type NarsilEventMap = {
|
|
956
|
+
/**
|
|
957
|
+
* The engine emits this event after a call changes what a read returns from
|
|
958
|
+
* an index. The calls are the inserts, updates, and removals, singly or in a
|
|
959
|
+
* batch, together with `clear`, `restore`, `rebalance`, `rebuildAnalysis`,
|
|
960
|
+
* `compactVectors`, `optimizeVectors`, `createIndex`, and `dropIndex`. The
|
|
961
|
+
* engine emits the event after a call that throws as well, because a call can
|
|
962
|
+
* change the index before it throws. It also emits the event after it reloads
|
|
963
|
+
* an index, once a shared invalidation adapter reports that another instance
|
|
964
|
+
* saved that index. The engine emits one event per batch, however many
|
|
965
|
+
* documents the batch holds.
|
|
966
|
+
*
|
|
967
|
+
* The engine emits the event once a query can see the change, which means
|
|
968
|
+
* after every worker copy applies the change and after any rebalance in
|
|
969
|
+
* progress replays it. A query that a listener sends from its handler
|
|
970
|
+
* therefore returns results that include the change. The engine waits for the
|
|
971
|
+
* change to become visible only while a listener is registered for the event.
|
|
972
|
+
*/
|
|
973
|
+
write: {
|
|
974
|
+
/** This is the name of the index that changed. */
|
|
975
|
+
indexName: string;
|
|
976
|
+
};
|
|
977
|
+
/**
|
|
978
|
+
* A worker thread exited unexpectedly. The pool removes the thread and fails
|
|
979
|
+
* the requests that the thread was serving with `WORKER_CRASHED`. The engine
|
|
980
|
+
* then sends each of those queries again on the main thread, so the caller
|
|
981
|
+
* receives a result with no error. The remaining workers keep serving
|
|
982
|
+
* queries, because each of them holds a full worker copy of every promoted
|
|
983
|
+
* index.
|
|
984
|
+
*
|
|
985
|
+
* After a delay, the engine spawns a replacement and loads every copy onto
|
|
986
|
+
* it before it sends queries to the replacement. Once no worker is left, the
|
|
987
|
+
* main thread serves every query, because it holds every document. The first
|
|
988
|
+
* request after the delay then starts a new pool. The delay starts at one
|
|
989
|
+
* second and doubles up to a minute while replacements keep failing.
|
|
990
|
+
*/
|
|
991
|
+
workerCrash: {
|
|
992
|
+
/** This is the id of the worker that exited. */
|
|
993
|
+
workerId: number;
|
|
994
|
+
/** These are the indexes that the worker held. */
|
|
995
|
+
indexNames: string[];
|
|
996
|
+
/** This is the error that ended the worker. */
|
|
997
|
+
error: Error;
|
|
998
|
+
};
|
|
999
|
+
/** An index gained worker copies, either because it reached the copy
|
|
1000
|
+
* threshold or because a request loaded its copies again after an idle
|
|
1001
|
+
* spell. */
|
|
1002
|
+
workerPromote: {
|
|
1003
|
+
/** This is the number of workers in the pool. */
|
|
1004
|
+
workerCount: number;
|
|
1005
|
+
/** This is the reason that the index gained its copies, such as the copy
|
|
1006
|
+
* threshold that it reached. */
|
|
1007
|
+
reason: string;
|
|
1008
|
+
};
|
|
1009
|
+
/** An index could not gain worker copies, so the main thread keeps serving
|
|
1010
|
+
* its queries. */
|
|
1011
|
+
workerPromoteFailure: {
|
|
1012
|
+
/** This is the reason that the engine tried to load the copies. */
|
|
1013
|
+
reason: string;
|
|
1014
|
+
/** This is the error that stopped the load. */
|
|
1015
|
+
error: Error;
|
|
1016
|
+
/** This is true when the engine will try again at a later threshold. */
|
|
1017
|
+
retryable: boolean;
|
|
1018
|
+
};
|
|
1019
|
+
/** An index finished spreading its documents across a new number of
|
|
1020
|
+
* partitions. */
|
|
1021
|
+
partitionRebalance: {
|
|
1022
|
+
/** This is the name of the index that the engine rebalanced. */
|
|
1023
|
+
indexName: string;
|
|
1024
|
+
/** This is the number of partitions before the rebalance. */
|
|
1025
|
+
oldCount: number;
|
|
1026
|
+
/** This is the number of partitions after the rebalance. */
|
|
1027
|
+
newCount: number;
|
|
1028
|
+
};
|
|
1029
|
+
/**
|
|
1030
|
+
* An index passed its watermark, so its partitions are close to their
|
|
1031
|
+
* capacity. On a cluster node, the engine reports the document count and the
|
|
1032
|
+
* capacity of the one partition that `partitionId` identifies, which this
|
|
1033
|
+
* node leads.
|
|
1034
|
+
*/
|
|
1035
|
+
partitionWatermark: {
|
|
1036
|
+
/** This is the name of the index that crossed the mark. */
|
|
1037
|
+
indexName: string;
|
|
1038
|
+
/** This is the number of documents in the index, or in the partition on a
|
|
1039
|
+
* cluster node. */
|
|
1040
|
+
documentCount: number;
|
|
1041
|
+
/** This is the number of documents that the current partitions of the
|
|
1042
|
+
* index can hold, or that the partition can hold on a cluster node. */
|
|
1043
|
+
capacity: number;
|
|
1044
|
+
/** This is the number of partitions in the index. */
|
|
1045
|
+
partitionCount: number;
|
|
1046
|
+
/** On a cluster node, this is the partition that crossed the mark, while
|
|
1047
|
+
* outside a cluster the field is absent. */
|
|
1048
|
+
partitionId?: number;
|
|
1049
|
+
};
|
|
1050
|
+
/**
|
|
1051
|
+
* The process uses nine tenths of its heap, as measured during a write or a
|
|
1052
|
+
* load, so the next large index can end the process with an out-of-memory
|
|
1053
|
+
* error.
|
|
1054
|
+
*
|
|
1055
|
+
* Where `--max-old-space-size` or `--max-old-space-size-percentage` sets a
|
|
1056
|
+
* limit, on the command line or in `NODE_OPTIONS`, the engine measures the
|
|
1057
|
+
* used bytes against that limit, which `heapLimit` then reports. Where
|
|
1058
|
+
* neither flag sets a limit, the engine measures the share of the heap that
|
|
1059
|
+
* V8 reports as no longer available. V8 reports a limit about 192 MB above
|
|
1060
|
+
* the true ceiling, so a process on a default heap below about 2 GB can end before
|
|
1061
|
+
* this event fires.
|
|
1062
|
+
*
|
|
1063
|
+
* The engine emits the event once per crossing, then arms it again once the
|
|
1064
|
+
* free share of the heap recovers to two tenths. Raise the limit with
|
|
1065
|
+
* `--max-old-space-size-percentage` or `--max-old-space-size`, or close an
|
|
1066
|
+
* idle index; see {@link ProcessMemoryReport.heapLimit}.
|
|
1067
|
+
*/
|
|
1068
|
+
heapPressure: {
|
|
1069
|
+
/** This is the index that a write or a load was touching when the heap
|
|
1070
|
+
* reached that point. */
|
|
1071
|
+
indexName: string;
|
|
1072
|
+
/** This is the heap that the process uses, in bytes. */
|
|
1073
|
+
heapUsed: number;
|
|
1074
|
+
/** This is the size in bytes that the heap can grow to. */
|
|
1075
|
+
heapLimit: number;
|
|
1076
|
+
/** This is the estimate of the bytes that the index holds. */
|
|
1077
|
+
estimatedMemoryBytes: number;
|
|
1078
|
+
};
|
|
1079
|
+
/** The engine started, completed, or failed a rebuild that brings the terms
|
|
1080
|
+
* of an index up to the current analysis of its language module. */
|
|
1081
|
+
analysisRebuild: {
|
|
1082
|
+
/** This is the name of the index under rebuild. */
|
|
1083
|
+
indexName: string;
|
|
1084
|
+
/** This is the stage that the rebuild has reached. */
|
|
1085
|
+
status: 'started' | 'completed' | 'failed';
|
|
1086
|
+
/** This is the number of partitions that the rebuild has covered so far. */
|
|
1087
|
+
partitionsRebuilt: number;
|
|
1088
|
+
/** This is the number of partitions that the rebuild covers in total. */
|
|
1089
|
+
partitionCount: number;
|
|
1090
|
+
/** This is the error that stopped the rebuild, which only a `failed`
|
|
1091
|
+
* status includes. */
|
|
1092
|
+
error?: Error;
|
|
1093
|
+
};
|
|
1094
|
+
/** The engine started, completed, or failed the rewrite of an index that you
|
|
1095
|
+
* saved with an earlier release. The engine rewrites the index as it
|
|
1096
|
+
* recovers it, before it serves the index's first request. Because the
|
|
1097
|
+
* engine writes the new manifest last, the earlier files stay intact through
|
|
1098
|
+
* a failed rewrite. The engine then starts the rewrite again the next time
|
|
1099
|
+
* it recovers the index. Without index lifecycle settings, the engine
|
|
1100
|
+
* recovers every index before {@link createNarsil} returns, so pass the
|
|
1101
|
+
* listener in the `events` setting of {@link createNarsil}. */
|
|
1102
|
+
layoutUpgrade: {
|
|
1103
|
+
/** This is the name of the index under rewrite. */
|
|
1104
|
+
indexName: string;
|
|
1105
|
+
/** This is the stage that the rewrite has reached. */
|
|
1106
|
+
status: 'started' | 'completed' | 'failed';
|
|
1107
|
+
/** This is `manifest` where the earlier index is a segment manifest with
|
|
1108
|
+
* its files, and `bundle` where it is a single snapshot bundle. */
|
|
1109
|
+
layout: 'manifest' | 'bundle';
|
|
1110
|
+
/** This is the error that stopped the rewrite, which only a `failed`
|
|
1111
|
+
* status includes. */
|
|
1112
|
+
error?: Error;
|
|
1113
|
+
};
|
|
1114
|
+
/** A write to the write-ahead log or a checkpoint failed, so the writes since
|
|
1115
|
+
* the last checkpoint are at risk. */
|
|
1116
|
+
durabilityError: {
|
|
1117
|
+
/** This is the error that the durability layer threw. */
|
|
1118
|
+
error: Error;
|
|
1119
|
+
};
|
|
1120
|
+
/** The invalidation channel failed, so this instance can serve partitions
|
|
1121
|
+
* that another instance has since changed. */
|
|
1122
|
+
invalidationError: {
|
|
1123
|
+
/** This is the error that the adapter threw. */
|
|
1124
|
+
error: Error;
|
|
937
1125
|
};
|
|
938
1126
|
};
|
|
939
1127
|
/**
|
|
940
|
-
*
|
|
1128
|
+
* This map holds a listener for any event of {@link NarsilEventMap}, so that
|
|
1129
|
+
* the engine can register each listener before it starts.
|
|
941
1130
|
*
|
|
942
1131
|
* @public
|
|
943
1132
|
*/
|
|
944
|
-
type
|
|
945
|
-
|
|
946
|
-
polygon: {
|
|
947
|
-
/**
|
|
948
|
-
* The engine closes the ring through these corners in the order that you
|
|
949
|
-
* list them, so you can leave the first point off the end. It throws
|
|
950
|
-
* `SEARCH_INVALID_FILTER` for a ring of fewer than three corners, which
|
|
951
|
-
* encloses no area, and for a corner whose latitude is outside -90 to 90
|
|
952
|
-
* or whose longitude is outside -180 to 180. It also throws that error for
|
|
953
|
-
* a ring of more than 65,536 corners. List the corners counter-clockwise
|
|
954
|
-
* around the area, as in an exterior ring of GeoJSON. Where the corners
|
|
955
|
-
* span 180 degrees of longitude or more, the engine matches the area on
|
|
956
|
-
* the left of that path, so a ring listed that way can cross the
|
|
957
|
-
* antimeridian or span more than half the globe.
|
|
958
|
-
*/
|
|
959
|
-
points: Array<{
|
|
960
|
-
lat: number;
|
|
961
|
-
lon: number;
|
|
962
|
-
}>;
|
|
963
|
-
/** The engine matches the points inside the polygon while this is true, which is the default, and the points outside it while this is false. */
|
|
964
|
-
inside?: boolean;
|
|
965
|
-
};
|
|
1133
|
+
type NarsilEventHandlers = {
|
|
1134
|
+
[K in keyof NarsilEventMap]?: (payload: NarsilEventMap[K]) => void;
|
|
966
1135
|
};
|
|
1136
|
+
|
|
967
1137
|
/**
|
|
968
|
-
*
|
|
1138
|
+
* What {@link Narsil.query} returns: the ranked hits and everything the query
|
|
1139
|
+
* asked for alongside them.
|
|
969
1140
|
*
|
|
970
|
-
* @
|
|
971
|
-
|
|
972
|
-
type GeoFilter = GeoRadiusFilter | GeoPolygonFilter;
|
|
973
|
-
/**
|
|
974
|
-
* The filter one field accepts. Which of these forms applies follows from the
|
|
975
|
-
* field's declared type.
|
|
1141
|
+
* @typeParam T - Shape of the stored documents, which flows through to each
|
|
1142
|
+
* hit's `document`.
|
|
976
1143
|
*
|
|
977
1144
|
* @public
|
|
978
1145
|
*/
|
|
979
|
-
|
|
1146
|
+
interface QueryResult<T = AnyDocument> {
|
|
1147
|
+
/** These documents match, cut to the query's `limit`, best score first or in the query's sort order. */
|
|
1148
|
+
hits: Array<Hit<T>>;
|
|
1149
|
+
/**
|
|
1150
|
+
* This many documents match in total, before the engine applies `limit`
|
|
1151
|
+
* and `offset`. For a keyword search the engine counts every match. For a
|
|
1152
|
+
* vector search it counts every vector that passes the query's filter and
|
|
1153
|
+
* its `similarity` floor, which is every vector in the field where the query
|
|
1154
|
+
* sets neither of them. The engine also counts each pinned document that
|
|
1155
|
+
* the query does not match, since it places that document among the hits.
|
|
1156
|
+
*/
|
|
1157
|
+
count: number;
|
|
1158
|
+
/**
|
|
1159
|
+
* `count` holds the exact number of matches where this is true, and a
|
|
1160
|
+
* number at or below the true total where it is false. Where a query sets a
|
|
1161
|
+
* `similarity` floor on a vector field that holds a graph, the engine
|
|
1162
|
+
* counts only the vectors that it fetches, because it compares the query
|
|
1163
|
+
* with only a fraction of that field's vectors. For a hybrid query the
|
|
1164
|
+
* engine fuses two rankings, so the count is exact only where each of those
|
|
1165
|
+
* rankings contains every matching document. Where you pin a document from
|
|
1166
|
+
* outside the hits that the engine fetches, the engine reports true only
|
|
1167
|
+
* where it holds every match of the query, because only then can it test
|
|
1168
|
+
* whether the query matches that document.
|
|
1169
|
+
*/
|
|
1170
|
+
countExact: boolean;
|
|
1171
|
+
/** The engine spent this many milliseconds on the search. */
|
|
1172
|
+
elapsed: number;
|
|
1173
|
+
/** This opaque cursor reaches the next page. Pass it back as `searchAfter`. */
|
|
1174
|
+
cursor?: string;
|
|
1175
|
+
/** These facet counts are keyed by the field each facet was asked for. */
|
|
1176
|
+
facets?: Record<string, FacetResult>;
|
|
1177
|
+
/** These groups arrive when the query asked for grouping. */
|
|
1178
|
+
groups?: GroupResult[];
|
|
1179
|
+
/** This turns true when the index's terms came from an older analysis than its language module produces now. */
|
|
1180
|
+
analysisStale?: boolean;
|
|
1181
|
+
/** The search read this much of the index, which is how you spot a degraded answer. */
|
|
1182
|
+
coverage: QueryCoverage;
|
|
1183
|
+
}
|
|
980
1184
|
/**
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
* The engine answers every test from an index that it keeps for the field. It
|
|
985
|
-
* applies the filter before scoring, so a narrow filter makes a search
|
|
986
|
-
* cheaper. A filter nests at most 30 levels deep and holds at most 1,024
|
|
987
|
-
* tests, counted across every field and nested expression. Past either limit,
|
|
988
|
-
* the engine throws `SEARCH_INVALID_FILTER`, while it throws
|
|
989
|
-
* `SEARCH_INVALID_FIELD` for a test on a field that the schema leaves out.
|
|
1185
|
+
* How much of an index one search read, which is what you check before you
|
|
1186
|
+
* trust a count or a ranking.
|
|
990
1187
|
*
|
|
991
|
-
*
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
fields?: Record<string, FieldFilter>;
|
|
996
|
-
/** Every nested expression has to match. */
|
|
997
|
-
and?: FilterExpression[];
|
|
998
|
-
/** At least one nested expression has to match. */
|
|
999
|
-
or?: FilterExpression[];
|
|
1000
|
-
/** The nested expression has to fail. */
|
|
1001
|
-
not?: FilterExpression;
|
|
1002
|
-
};
|
|
1003
|
-
|
|
1004
|
-
/**
|
|
1005
|
-
* Everything {@link Narsil.suggest} accepts.
|
|
1188
|
+
* An embedded engine reads every partition it holds, so `queriedPartitions`
|
|
1189
|
+
* matches `totalPartitions` there and the other two stay zero. A search across
|
|
1190
|
+
* a cluster may find a node slow or unreachable, which it counts here while
|
|
1191
|
+
* still returning the hits the other nodes gave it.
|
|
1006
1192
|
*
|
|
1007
1193
|
* @public
|
|
1008
1194
|
*/
|
|
1009
|
-
interface
|
|
1010
|
-
/** The
|
|
1011
|
-
|
|
1012
|
-
/** The
|
|
1013
|
-
|
|
1195
|
+
interface QueryCoverage {
|
|
1196
|
+
/** The search should have read this many partitions. */
|
|
1197
|
+
totalPartitions: number;
|
|
1198
|
+
/** The search read this many of them. */
|
|
1199
|
+
queriedPartitions: number;
|
|
1200
|
+
/** The search counts a partition here when the node holding it took longer than the query allowed. */
|
|
1201
|
+
timedOutPartitions: number;
|
|
1202
|
+
/** The search counts a partition here when the node holding it returned an error, and when no active replica served it. */
|
|
1203
|
+
failedPartitions: number;
|
|
1014
1204
|
}
|
|
1015
1205
|
/**
|
|
1016
|
-
*
|
|
1017
|
-
*
|
|
1018
|
-
* {@link Narsil.listDocuments} reads the stored documents without ranking them,
|
|
1019
|
-
* which is how you page through a whole index. Leave `cursor` out to start at
|
|
1020
|
-
* the first document, then pass back the cursor each result carries until it
|
|
1021
|
-
* comes back null.
|
|
1206
|
+
* One matching document, with the score that ranked it.
|
|
1022
1207
|
*
|
|
1023
|
-
*
|
|
1024
|
-
* with it. Changing `sort` invalidates the cursor, and the engine then throws
|
|
1025
|
-
* `SEARCH_INVALID_CURSOR` rather than returning a page from the wrong order.
|
|
1208
|
+
* @typeParam T - Shape of the stored document.
|
|
1026
1209
|
*
|
|
1027
1210
|
* @public
|
|
1028
1211
|
*/
|
|
1029
|
-
interface
|
|
1030
|
-
/**
|
|
1031
|
-
|
|
1032
|
-
* The engine ties a cursor to the sort that produced it, and it throws
|
|
1033
|
-
* `SEARCH_INVALID_CURSOR` for a cursor sent back under a different sort.
|
|
1034
|
-
*/
|
|
1035
|
-
cursor?: string;
|
|
1036
|
-
/** The page carries this many documents, and 10 by default. The engine raises a value below one to one. */
|
|
1037
|
-
limit?: number;
|
|
1038
|
-
/** This narrows the listing to the documents the filter accepts. */
|
|
1039
|
-
filters?: FilterExpression;
|
|
1212
|
+
interface Hit<T = AnyDocument> {
|
|
1213
|
+
/** The document is stored under this id. */
|
|
1214
|
+
id: string;
|
|
1040
1215
|
/**
|
|
1041
|
-
* This
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
* tie on document id, and it sorts by at most eight fields. The engine uses
|
|
1045
|
-
* document-id order when you leave this out.
|
|
1046
|
-
*
|
|
1047
|
-
* The engine reads every document the listing covers to build a sorted page,
|
|
1048
|
-
* so a sorted listing costs more than the default order on a large index.
|
|
1216
|
+
* This score ranked the hit. Scores compare within one result set, never
|
|
1217
|
+
* across searches. A sorted query ranks by sort values instead and carries
|
|
1218
|
+
* no score unless it sets `includeScores`.
|
|
1049
1219
|
*/
|
|
1050
|
-
|
|
1051
|
-
/** This
|
|
1052
|
-
document
|
|
1220
|
+
score?: number;
|
|
1221
|
+
/** This is the stored document. */
|
|
1222
|
+
document: T;
|
|
1223
|
+
/** These are the parts the score was built from, which arrive when the query asked for them. */
|
|
1224
|
+
scoreComponents?: ScoreComponents;
|
|
1225
|
+
/** These highlighted snippets are keyed by field, and arrive when the query asked for highlighting. */
|
|
1226
|
+
highlights?: Record<string, HighlightMatch>;
|
|
1053
1227
|
}
|
|
1054
|
-
|
|
1055
1228
|
/**
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1229
|
+
* The numbers BM25 combined into one hit's score, which is what you read when
|
|
1230
|
+
* a ranking surprises you.
|
|
1058
1231
|
*
|
|
1059
1232
|
* @public
|
|
1060
1233
|
*/
|
|
1061
|
-
|
|
1234
|
+
interface ScoreComponents {
|
|
1235
|
+
/**
|
|
1236
|
+
* Each query term appears in one field of this document this many times,
|
|
1237
|
+
* under a key of `field:term`. A term that appears in two fields therefore
|
|
1238
|
+
* has two entries here, while the keys of {@link ScoreComponents.idf} hold
|
|
1239
|
+
* the bare term.
|
|
1240
|
+
*/
|
|
1241
|
+
termFrequencies: Record<string, number>;
|
|
1242
|
+
/** Each field the query searched holds this many tokens, keyed by field. */
|
|
1243
|
+
fieldLengths: Record<string, number>;
|
|
1244
|
+
/** Each query term carries this inverse document frequency, which is what makes a rare term count for more. */
|
|
1245
|
+
idf: Record<string, number>;
|
|
1246
|
+
}
|
|
1062
1247
|
/**
|
|
1063
|
-
*
|
|
1064
|
-
* term, `any` accepts one, and a number demands that many.
|
|
1248
|
+
* A highlighted field, ready to render.
|
|
1065
1249
|
*
|
|
1066
1250
|
* @public
|
|
1067
1251
|
*/
|
|
1068
|
-
|
|
1252
|
+
interface HighlightMatch {
|
|
1253
|
+
/** This is the field's text around the match, wrapped in the query's tags. */
|
|
1254
|
+
snippet: string;
|
|
1255
|
+
/**
|
|
1256
|
+
* Each range gives the start and the end of one match in the original field,
|
|
1257
|
+
* so you can render the highlight yourself. Where the snippet covers part of
|
|
1258
|
+
* the field alone, the engine lists only the matches that the snippet
|
|
1259
|
+
* displays. Every offset is a character count from the start of the original
|
|
1260
|
+
* field, whatever the snippet contains.
|
|
1261
|
+
*/
|
|
1262
|
+
positions: Array<{
|
|
1263
|
+
start: number;
|
|
1264
|
+
end: number;
|
|
1265
|
+
}>;
|
|
1266
|
+
}
|
|
1069
1267
|
/**
|
|
1070
|
-
*
|
|
1268
|
+
* Counts for one faceted field.
|
|
1071
1269
|
*
|
|
1072
1270
|
* @public
|
|
1073
1271
|
*/
|
|
1074
|
-
interface
|
|
1075
|
-
/**
|
|
1076
|
-
|
|
1077
|
-
/**
|
|
1078
|
-
|
|
1272
|
+
interface FacetResult {
|
|
1273
|
+
/** This many documents match per value, keyed by value. */
|
|
1274
|
+
values: Record<string, number>;
|
|
1275
|
+
/** This is the number of entries in `values`, which is at most the facet's `limit`. */
|
|
1276
|
+
count: number;
|
|
1079
1277
|
/**
|
|
1080
|
-
*
|
|
1081
|
-
*
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1278
|
+
* Every count in `values` is at most this far below its true count. A value
|
|
1279
|
+
* that the engine leaves out of `values` because of `limit` has a true
|
|
1280
|
+
* count of at most this figure too. Where the engine counts a field on one
|
|
1281
|
+
* thread, it counts every value exactly, so this figure is the largest
|
|
1282
|
+
* count that it leaves out. Where it splits the count across worker copies
|
|
1283
|
+
* or cluster nodes, each of them returns only its own top values, so the
|
|
1284
|
+
* merged count of a value that is common overall but rare on one of them
|
|
1285
|
+
* can lack the matches on that one. A bound of 0 means that `values` holds
|
|
1286
|
+
* every matching value, each with its exact count.
|
|
1088
1287
|
*/
|
|
1089
|
-
|
|
1288
|
+
errorBound: number;
|
|
1090
1289
|
}
|
|
1091
1290
|
/**
|
|
1092
|
-
*
|
|
1093
|
-
* order they apply.
|
|
1094
|
-
*
|
|
1095
|
-
* Both forms order by the first field, break a tie on the second, and carry on
|
|
1096
|
-
* that way. Prefer the list where the order of the fields matters, because
|
|
1097
|
-
* JavaScript moves an all-digit key such as `2024` to the front of an object
|
|
1098
|
-
* and the list keeps the order you wrote.
|
|
1291
|
+
* One group of hits, produced by a query that grouped its results.
|
|
1099
1292
|
*
|
|
1100
1293
|
* @public
|
|
1101
1294
|
*/
|
|
1102
|
-
|
|
1295
|
+
interface GroupResult {
|
|
1296
|
+
/** Each grouping field holds this value for the group, keyed by field. */
|
|
1297
|
+
values: Record<string, unknown>;
|
|
1298
|
+
/** These hits fall in the group, cut to the query's `maxPerGroup`. */
|
|
1299
|
+
hits: Array<Hit>;
|
|
1300
|
+
/** The query's reducer produced this value for the group, and only a query that set `group.reduce` carries it. */
|
|
1301
|
+
reduced?: unknown;
|
|
1302
|
+
/** The reducer threw, and this holds its message, so the group carries its hits and no `reduced` value. */
|
|
1303
|
+
reducerError?: string;
|
|
1304
|
+
}
|
|
1103
1305
|
/**
|
|
1104
|
-
*
|
|
1306
|
+
* What {@link Narsil.preflight} returns: how many documents a query matches,
|
|
1307
|
+
* without building or ranking a single hit.
|
|
1105
1308
|
*
|
|
1106
|
-
*
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1309
|
+
* @public
|
|
1310
|
+
*/
|
|
1311
|
+
interface PreflightResult {
|
|
1312
|
+
/** The query matches this many documents. */
|
|
1313
|
+
count: number;
|
|
1314
|
+
/** `count` holds the exact number of matches where this is true, and a number at or below the true total where it is false, under the rule in {@link QueryResult.countExact}. */
|
|
1315
|
+
countExact: boolean;
|
|
1316
|
+
/** The count took this many milliseconds. */
|
|
1317
|
+
elapsed: number;
|
|
1318
|
+
/** This turns true when the index's terms came from an older analysis than its language module produces now. */
|
|
1319
|
+
analysisStale?: boolean;
|
|
1320
|
+
}
|
|
1321
|
+
/**
|
|
1322
|
+
* What a batch write returns. One bad document never abandons the rest, so
|
|
1323
|
+
* read both lists.
|
|
1110
1324
|
*
|
|
1111
1325
|
* @public
|
|
1112
1326
|
*/
|
|
1113
|
-
interface
|
|
1114
|
-
/** The engine
|
|
1115
|
-
|
|
1116
|
-
/** The engine
|
|
1117
|
-
|
|
1118
|
-
/**
|
|
1119
|
-
* The engine scores only the documents that pass this filter. It throws
|
|
1120
|
-
* `SEARCH_INVALID_FILTER` for an operand of the wrong shape, and for an
|
|
1121
|
-
* operator on a field of another type, such as `startsWith` on a number
|
|
1122
|
-
* field.
|
|
1123
|
-
*/
|
|
1124
|
-
filters?: FilterExpression;
|
|
1125
|
-
/**
|
|
1126
|
-
* The engine multiplies the score from each named field by its weight. It
|
|
1127
|
-
* throws `SEARCH_INVALID_FIELD` for any field other than a text field that
|
|
1128
|
-
* the schema declares, and `CONFIG_INVALID` for a weight that is not a
|
|
1129
|
-
* finite number.
|
|
1130
|
-
*/
|
|
1131
|
-
boost?: Record<string, number>;
|
|
1132
|
-
/** The engine gathers term statistics this way, and follows the index's `defaultScoring` where the query sets none. */
|
|
1133
|
-
scoring?: ScoringMode;
|
|
1134
|
-
/**
|
|
1135
|
-
* The engine drops any hit scoring below this value. It ranks with BM25,
|
|
1136
|
-
* which has no fixed upper bound, so a floor that suits one index and one
|
|
1137
|
-
* query can reject every hit in another.
|
|
1138
|
-
*/
|
|
1139
|
-
minScore?: number;
|
|
1140
|
-
/**
|
|
1141
|
-
* The engine keeps a document only where the document matches this many
|
|
1142
|
-
* query terms, under the same `tolerance` and `prefixLength` that the search
|
|
1143
|
-
* uses. One term is enough by default.
|
|
1144
|
-
*/
|
|
1145
|
-
termMatch?: TermMatchPolicy;
|
|
1146
|
-
/**
|
|
1147
|
-
* The engine matches an indexed term within this edit distance of a query
|
|
1148
|
-
* term, so it finds a document for a query with a typo. It counts each
|
|
1149
|
-
* Unicode code point as one character. Set an integer from 0 to 10.
|
|
1150
|
-
*/
|
|
1151
|
-
tolerance?: number;
|
|
1152
|
-
/**
|
|
1153
|
-
* The engine applies `tolerance` only to the indexed terms that share this
|
|
1154
|
-
* many leading characters with the query term, or to the terms that start
|
|
1155
|
-
* with the whole query term when the query term is shorter. Set an integer
|
|
1156
|
-
* from 0 to 1,024; the default is 2.
|
|
1157
|
-
*/
|
|
1158
|
-
prefixLength?: number;
|
|
1159
|
-
/**
|
|
1160
|
-
* With this set, the engine treats the last query term as an unfinished
|
|
1161
|
-
* word, so `secur` matches `security`. The engine matches that last term by
|
|
1162
|
-
* its stem or by completing it, while `tolerance` applies only to the earlier
|
|
1163
|
-
* terms, which have to match whole. The engine scores completions against a
|
|
1164
|
-
* shared document frequency. It also ranks them below whole-word matches.
|
|
1165
|
-
* The engine ignores this setting where `exact` is true, and the setting is
|
|
1166
|
-
* false by default.
|
|
1167
|
-
*/
|
|
1168
|
-
prefix?: boolean;
|
|
1169
|
-
/**
|
|
1170
|
-
* Setting this makes the engine match each query term only against an equal
|
|
1171
|
-
* indexed term, which turns off fuzzy matching and prefix completion. The
|
|
1172
|
-
* engine still stems the query, because the index stores stemmed terms, so
|
|
1173
|
-
* `running` matches a document that holds `runs` through their shared stem.
|
|
1174
|
-
*/
|
|
1175
|
-
exact?: boolean;
|
|
1176
|
-
/**
|
|
1177
|
-
* The engine counts the values of these fields across the matching
|
|
1178
|
-
* documents, and each entry sets how it cuts and sorts that field's counts.
|
|
1179
|
-
* For a field outside the schema, it counts the values that the documents
|
|
1180
|
-
* store. It throws `SEARCH_INVALID_FIELD` for a `geopoint` or a vector
|
|
1181
|
-
* field.
|
|
1182
|
-
*/
|
|
1183
|
-
facets?: FacetConfig;
|
|
1184
|
-
/**
|
|
1185
|
-
* The engine sorts the hits by the values of these fields, in place of the
|
|
1186
|
-
* relevance ranking. Pass an object keyed by field, or a list of fields in
|
|
1187
|
-
* the order that the engine compares them. The engine sorts by a `number`,
|
|
1188
|
-
* `boolean`, or `enum` field, by a text field whose type includes
|
|
1189
|
-
* `sortable`, or by a list of any of these, which it reduces to one value by
|
|
1190
|
-
* the entry's `mode`. It throws `SEARCH_INVALID_FIELD` for a sort on a
|
|
1191
|
-
* `geopoint` or a vector field, because neither type has an order. It throws
|
|
1192
|
-
* the same code for a sort on any other text field, since the engine keeps
|
|
1193
|
-
* up to the first 512 code points of every document's value in memory to
|
|
1194
|
-
* sort by a text field. The engine orders hybrid results by fusion, so it
|
|
1195
|
-
* throws `SEARCH_INVALID_MODE` for a sort on a hybrid query. It also throws
|
|
1196
|
-
* that code for a direction other than `asc` and `desc`.
|
|
1197
|
-
*/
|
|
1198
|
-
sort?: SortSpec;
|
|
1199
|
-
/** These settings collapse the hits into groups by field value. */
|
|
1200
|
-
group?: GroupConfig;
|
|
1201
|
-
/**
|
|
1202
|
-
* The query returns this many hits, and 10 by default. Pass 0 to read the
|
|
1203
|
-
* match count with no hits. The engine reads a value below 0 as 0. It falls
|
|
1204
|
-
* back to the default for `NaN` and for an infinite value, so a page size
|
|
1205
|
-
* that you compute from user input never fails the query.
|
|
1206
|
-
*/
|
|
1207
|
-
limit?: number;
|
|
1208
|
-
/** The query skips this many hits before returning. A deep offset costs more than a cursor. */
|
|
1209
|
-
offset?: number;
|
|
1210
|
-
/** This cursor comes from a previous result's `cursor`, and pages without an offset's cost. */
|
|
1211
|
-
searchAfter?: string;
|
|
1212
|
-
/** These settings name the fields that come back with highlighted snippets. */
|
|
1213
|
-
highlight?: HighlightConfig;
|
|
1214
|
-
/** These documents take fixed positions, ahead of the ranking. */
|
|
1215
|
-
pinned?: Array<{
|
|
1327
|
+
interface BatchResult {
|
|
1328
|
+
/** The engine wrote the documents under these ids. */
|
|
1329
|
+
succeeded: string[];
|
|
1330
|
+
/** The engine rejected each of these documents, and each entry carries the error that rejected it. */
|
|
1331
|
+
failed: Array<{
|
|
1216
1332
|
docId: string;
|
|
1217
|
-
|
|
1333
|
+
error: NarsilError;
|
|
1218
1334
|
}>;
|
|
1219
|
-
/** This picks which engine answers the query. Keyword search runs by default. */
|
|
1220
|
-
mode?: SearchMode;
|
|
1221
|
-
/** These vector-search inputs are required in `vector` and `hybrid` mode. */
|
|
1222
|
-
vector?: VectorQueryConfig;
|
|
1223
|
-
/** These settings control how the keyword and vector rankings merge in `hybrid` mode. */
|
|
1224
|
-
hybrid?: HybridConfig;
|
|
1225
|
-
/**
|
|
1226
|
-
* Setting this returns relevance scores on a sorted query. A query that
|
|
1227
|
-
* names a sort ranks by sort values alone and computes no scores, so its
|
|
1228
|
-
* hits carry none until this restores them. A query without a sort ignores
|
|
1229
|
-
* this and always carries scores.
|
|
1230
|
-
*/
|
|
1231
|
-
includeScores?: boolean;
|
|
1232
|
-
/** Setting this returns the numbers behind each hit's score, which is what you read when a ranking surprises you. */
|
|
1233
|
-
includeScoreComponents?: boolean;
|
|
1234
|
-
/** This chooses how much of each stored document comes back, and the whole document by default. */
|
|
1235
|
-
document?: DocumentProjection;
|
|
1236
1335
|
}
|
|
1237
1336
|
/**
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
* Pass `false` when the ids and scores are all you need, and every hit's
|
|
1241
|
-
* `document` is then an empty object. Pass `include` to keep named fields
|
|
1242
|
-
* alone, or `exclude` to drop named fields and keep the rest; naming both
|
|
1243
|
-
* keeps the included fields and then drops the excluded ones from those. Use
|
|
1244
|
-
* dots to name a nested field, so `author.name` addresses the `name` inside
|
|
1245
|
-
* `author`, and a name that matches no field changes nothing.
|
|
1246
|
-
*
|
|
1247
|
-
* Drop a vector field on a similarity search, because the engine otherwise
|
|
1248
|
-
* reads every hit's vector back out of the index and writes it into the
|
|
1249
|
-
* response.
|
|
1337
|
+
* What {@link Narsil.importDocumentExport} returns. The engine continues past each
|
|
1338
|
+
* refused line, so read the refusals to learn which documents it skipped.
|
|
1250
1339
|
*
|
|
1251
1340
|
* @public
|
|
1252
1341
|
*/
|
|
1253
|
-
|
|
1254
|
-
/**
|
|
1255
|
-
|
|
1256
|
-
/**
|
|
1257
|
-
|
|
1258
|
-
|
|
1342
|
+
interface DocumentImportResult {
|
|
1343
|
+
/** The engine wrote this many documents, counting each one that it replaced. */
|
|
1344
|
+
imported: number;
|
|
1345
|
+
/** The engine refused this many lines in total. */
|
|
1346
|
+
refusedCount: number;
|
|
1347
|
+
/** These are the 1,000 refusals with the lowest line numbers. Each entry contains the line number, where the header is line 1, along with the error code and a message. */
|
|
1348
|
+
refused: Array<{
|
|
1349
|
+
line: number;
|
|
1350
|
+
code: NarsilErrorCode;
|
|
1351
|
+
message: string;
|
|
1352
|
+
}>;
|
|
1353
|
+
}
|
|
1259
1354
|
/**
|
|
1260
|
-
*
|
|
1261
|
-
*
|
|
1262
|
-
* Supply either a raw `value` array or a `text` string for auto-embedding;
|
|
1263
|
-
* passing both throws `EMBEDDING_CONFIG_INVALID`. Result count is governed
|
|
1264
|
-
* by the outer query's `limit`, not by any field on this object.
|
|
1355
|
+
* What {@link Narsil.getStats} returns about one index.
|
|
1265
1356
|
*
|
|
1266
1357
|
* @public
|
|
1267
1358
|
*/
|
|
1268
|
-
interface
|
|
1269
|
-
/**
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
field: string;
|
|
1274
|
-
/**
|
|
1275
|
-
* Raw query vector, given as a number array or a `Float32Array`. Length
|
|
1276
|
-
* must match the indexed field's dimension or the search rejects the
|
|
1277
|
-
* request with `VECTOR_DIMENSION_MISMATCH`.
|
|
1278
|
-
*/
|
|
1279
|
-
value?: number[] | Float32Array;
|
|
1280
|
-
/**
|
|
1281
|
-
* Text to embed at query time using the index or instance embedding
|
|
1282
|
-
* adapter. Mutually exclusive with `value`; requires a configured adapter.
|
|
1283
|
-
*/
|
|
1284
|
-
text?: string;
|
|
1285
|
-
/**
|
|
1286
|
-
* Score floor applied during ranking. Hits scoring below this value
|
|
1287
|
-
* are dropped before `limit` is enforced, so the returned hit count
|
|
1288
|
-
* can be smaller than `limit` even when more documents exist. The
|
|
1289
|
-
* floor is interpreted in score space for every metric; for
|
|
1290
|
-
* `euclidean`, distance is mapped to a similarity score of
|
|
1291
|
-
* `1 / (1 + distance)` first. Defaults to no floor.
|
|
1292
|
-
*/
|
|
1293
|
-
similarity?: number;
|
|
1294
|
-
/**
|
|
1295
|
-
* Similarity metric used for ranking. Defaults to `cosine`. Choose
|
|
1296
|
-
* `dotProduct` for raw inner-product scoring on already-normalised
|
|
1297
|
-
* vectors and `euclidean` for distance-based ordering.
|
|
1298
|
-
*/
|
|
1299
|
-
metric?: 'cosine' | 'dotProduct' | 'euclidean';
|
|
1300
|
-
/**
|
|
1301
|
-
* HNSW exploration factor for approximate search. Higher values raise
|
|
1302
|
-
* recall at the cost of latency. Ignored while the field is still
|
|
1303
|
-
* served by the brute-force backend. Defaults to the engine's built-in
|
|
1304
|
-
* value when omitted.
|
|
1305
|
-
*/
|
|
1306
|
-
efSearch?: number;
|
|
1359
|
+
interface IndexStats {
|
|
1360
|
+
/** The index holds this many documents. A closed index reports its count as of the last checkpoint. */
|
|
1361
|
+
documentCount: number;
|
|
1362
|
+
/** The index is spread across this many partitions. */
|
|
1363
|
+
partitionCount: number;
|
|
1307
1364
|
/**
|
|
1308
|
-
*
|
|
1309
|
-
*
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1313
|
-
*
|
|
1314
|
-
*
|
|
1365
|
+
* Formula-based estimate of the index's main-thread memory footprint, summed
|
|
1366
|
+
* across every partition and vector index for this index. Computed from
|
|
1367
|
+
* structural counters (document count, posting counts, field-index sizes),
|
|
1368
|
+
* not measured. Per-object V8 overhead (hidden classes, map transitions,
|
|
1369
|
+
* GC headers) is not captured here, so this number routinely undershoots
|
|
1370
|
+
* the real heap by a meaningful factor. Use {@link Narsil.getMemoryStats}
|
|
1371
|
+
* when sizing host memory.
|
|
1315
1372
|
*/
|
|
1316
|
-
|
|
1373
|
+
estimatedMemoryBytes: number;
|
|
1374
|
+
/** The index analyses text with this language module. */
|
|
1375
|
+
language: string;
|
|
1376
|
+
/** The index was created with this field layout. */
|
|
1377
|
+
schema: SchemaDefinition;
|
|
1317
1378
|
}
|
|
1318
1379
|
/**
|
|
1319
|
-
*
|
|
1380
|
+
* A summary of one index, as {@link Narsil.listIndexes} reports it.
|
|
1320
1381
|
*
|
|
1321
|
-
*
|
|
1322
|
-
|
|
1323
|
-
|
|
1382
|
+
* @public
|
|
1383
|
+
*/
|
|
1384
|
+
interface IndexInfo {
|
|
1385
|
+
/** The index was created under this name. */
|
|
1386
|
+
name: string;
|
|
1387
|
+
/** The index holds this many documents. A closed index reports its count as of the last checkpoint. */
|
|
1388
|
+
documentCount: number;
|
|
1389
|
+
/** The index is spread across this many partitions. */
|
|
1390
|
+
partitionCount: number;
|
|
1391
|
+
/** The index analyses text with this language module. */
|
|
1392
|
+
language: string;
|
|
1393
|
+
/** This turns true when the index's terms came from an older analysis than its language module produces now. */
|
|
1394
|
+
analysisStale?: boolean;
|
|
1395
|
+
/** This is `open` in memory, `closed` after release, and `reopen-failed` after five recovery failures. */
|
|
1396
|
+
state: 'open' | 'closed' | 'reopen-failed';
|
|
1397
|
+
/** This counts successful loads since this engine started. */
|
|
1398
|
+
reopenCount: number;
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* What {@link Narsil.getPartitionStats} reports for one partition, which is
|
|
1402
|
+
* where you look when an index grows unevenly.
|
|
1324
1403
|
*
|
|
1325
1404
|
* @public
|
|
1326
1405
|
*/
|
|
1327
|
-
interface
|
|
1328
|
-
/**
|
|
1329
|
-
|
|
1330
|
-
/** The
|
|
1331
|
-
|
|
1332
|
-
/**
|
|
1333
|
-
|
|
1406
|
+
interface PartitionStatsResult {
|
|
1407
|
+
/** This identifies the partition within its index. */
|
|
1408
|
+
partitionId: number;
|
|
1409
|
+
/** The partition holds this many documents. */
|
|
1410
|
+
documentCount: number;
|
|
1411
|
+
/**
|
|
1412
|
+
* Formula-based estimate of this partition's memory footprint. V8 has no
|
|
1413
|
+
* per-object heap accounting API, so this number is derived from structural
|
|
1414
|
+
* counters (document count, posting counts, field-index sizes) and does not
|
|
1415
|
+
* include per-object overhead. Treat as an estimate, not a measurement.
|
|
1416
|
+
*/
|
|
1417
|
+
estimatedMemoryBytes: number;
|
|
1334
1418
|
}
|
|
1335
1419
|
/**
|
|
1336
|
-
*
|
|
1420
|
+
* What {@link Narsil.suggest} returns: the indexed terms that complete a
|
|
1421
|
+
* prefix, ready to offer as you-type suggestions.
|
|
1337
1422
|
*
|
|
1338
1423
|
* @public
|
|
1339
1424
|
*/
|
|
1340
|
-
interface
|
|
1341
|
-
/**
|
|
1342
|
-
|
|
1343
|
-
/**
|
|
1344
|
-
|
|
1345
|
-
/** The
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
};
|
|
1425
|
+
interface SuggestResult {
|
|
1426
|
+
/** These completions run most widely used first. */
|
|
1427
|
+
terms: Array<{
|
|
1428
|
+
/** This is the completed term, as the index holds it. */
|
|
1429
|
+
term: string;
|
|
1430
|
+
/** The term appears in this many documents, which is what ordered the list. */
|
|
1431
|
+
documentFrequency: number;
|
|
1432
|
+
}>;
|
|
1433
|
+
/** The lookup took this many milliseconds. */
|
|
1434
|
+
elapsed: number;
|
|
1435
|
+
/** This turns true when the index's terms came from an older analysis than its language module produces now. */
|
|
1436
|
+
analysisStale?: boolean;
|
|
1353
1437
|
}
|
|
1354
1438
|
/**
|
|
1355
|
-
*
|
|
1439
|
+
* The state of one vector field, and what maintenance would cost, as
|
|
1440
|
+
* {@link Narsil.vectorMaintenanceStatus} reports it.
|
|
1441
|
+
*
|
|
1442
|
+
* Removing a vector leaves a tombstone in the graph, and enough of them slow a
|
|
1443
|
+
* search down. Read this to decide when compaction earns its cost.
|
|
1356
1444
|
*
|
|
1357
1445
|
* @public
|
|
1358
1446
|
*/
|
|
1359
|
-
interface
|
|
1360
|
-
/**
|
|
1361
|
-
|
|
1362
|
-
/** The engine returns this many hits from each group, best first, and one hit where you leave this out. */
|
|
1363
|
-
maxPerGroup?: number;
|
|
1364
|
-
/** The engine returns this many groups, best first, and every group where you leave this out. */
|
|
1365
|
-
limit?: number;
|
|
1447
|
+
interface VectorMaintenanceResult {
|
|
1448
|
+
/** This describes the named vector field. */
|
|
1449
|
+
fieldName: string;
|
|
1366
1450
|
/**
|
|
1367
|
-
*
|
|
1368
|
-
*
|
|
1369
|
-
*
|
|
1451
|
+
* Tombstones make up this share of the graph's nodes, from 0 to 1. Before
|
|
1452
|
+
* the first build, where {@link VectorMaintenanceResult.graphCount} reads 0,
|
|
1453
|
+
* the engine divides by the number of stored vectors, because no graph
|
|
1454
|
+
* exists yet.
|
|
1370
1455
|
*/
|
|
1371
|
-
|
|
1456
|
+
tombstoneRatio: number;
|
|
1457
|
+
/** The field holds this many HNSW graphs: 0 before the first build and 1 once a graph exists. */
|
|
1458
|
+
graphCount: number;
|
|
1459
|
+
/** This many vectors wait outside the graph, which a search scans one by one. */
|
|
1460
|
+
bufferSize: number;
|
|
1461
|
+
/** This stays true while a graph build runs. */
|
|
1462
|
+
building: boolean;
|
|
1463
|
+
/** {@link Narsil.compactVectors} would take about this many milliseconds. */
|
|
1464
|
+
estimatedCompactMs: number;
|
|
1465
|
+
/** {@link Narsil.optimizeVectors} would take about this many milliseconds. */
|
|
1466
|
+
estimatedOptimizeMs: number;
|
|
1372
1467
|
}
|
|
1373
1468
|
/**
|
|
1374
|
-
*
|
|
1469
|
+
* One stored document, as {@link Narsil.listDocuments} returns it.
|
|
1470
|
+
*
|
|
1471
|
+
* @typeParam T - Shape of the stored document.
|
|
1375
1472
|
*
|
|
1376
1473
|
* @public
|
|
1377
1474
|
*/
|
|
1378
|
-
|
|
1379
|
-
/**
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
* @param doc - The hit's stored document.
|
|
1385
|
-
* @param score - The hit's relevance score.
|
|
1386
|
-
* @returns The new running value.
|
|
1387
|
-
*/
|
|
1388
|
-
reducer: (accumulator: unknown, doc: AnyDocument, score: number) => unknown;
|
|
1389
|
-
/** Produces the starting value for each group. The engine calls it once per group. */
|
|
1390
|
-
initialValue: () => unknown;
|
|
1391
|
-
};
|
|
1475
|
+
interface ListedDocument<T = AnyDocument> {
|
|
1476
|
+
/** The document is stored under this id. */
|
|
1477
|
+
id: string;
|
|
1478
|
+
/** This holds the stored document, cut down to what the projection kept. */
|
|
1479
|
+
document: T;
|
|
1480
|
+
}
|
|
1392
1481
|
/**
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
1482
|
+
* What {@link Narsil.listDocuments} returns: one page of stored documents and
|
|
1483
|
+
* the cursor that reaches the next one.
|
|
1395
1484
|
*
|
|
1396
|
-
*
|
|
1397
|
-
* that it matched, so it tags the same words whatever the index's
|
|
1398
|
-
* `trackPositions` setting is. It tags a word whose stem equals a query stem,
|
|
1399
|
-
* and a word within the query's `tolerance` of a query stem. For a `prefix`
|
|
1400
|
-
* query, it tags a word for the last query term only when that word completes
|
|
1401
|
-
* the term or shares its stem.
|
|
1485
|
+
* @typeParam T - Shape of the stored documents.
|
|
1402
1486
|
*
|
|
1403
1487
|
* @public
|
|
1404
1488
|
*/
|
|
1405
|
-
interface
|
|
1406
|
-
/**
|
|
1407
|
-
|
|
1408
|
-
/**
|
|
1409
|
-
|
|
1410
|
-
/** The
|
|
1411
|
-
|
|
1412
|
-
/**
|
|
1413
|
-
|
|
1414
|
-
* of matches, 200 by default. It returns a snippet longer than that number,
|
|
1415
|
-
* because it then adds the opening and closing tags, and an ellipsis at each
|
|
1416
|
-
* end where it cuts the field.
|
|
1417
|
-
*/
|
|
1418
|
-
maxSnippetLength?: number;
|
|
1489
|
+
interface ListResult<T = AnyDocument> {
|
|
1490
|
+
/** These documents make up the page, in ascending document-id order. */
|
|
1491
|
+
documents: Array<ListedDocument<T>>;
|
|
1492
|
+
/** This opaque cursor reaches the next page, and is null once the listing is finished. */
|
|
1493
|
+
cursor: string | null;
|
|
1494
|
+
/** The listing covers this many documents in total, and any filter narrows that count. */
|
|
1495
|
+
total: number;
|
|
1496
|
+
/** The engine spent this many milliseconds building the page. */
|
|
1497
|
+
elapsed: number;
|
|
1419
1498
|
}
|
|
1420
1499
|
|
|
1421
1500
|
/**
|