vectlite 0.1.12 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -10
- package/index.d.ts +111 -0
- package/index.js +295 -12
- package/native/Cargo.toml +1 -1
- package/native/src/lib.rs +661 -43
- package/native/vectlite-core/Cargo.toml +2 -1
- package/native/vectlite-core/src/lib.rs +6208 -2160
- package/native/vectlite-core/src/quantization.rs +715 -30
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/vectlite.node +0 -0
- package/prebuilds/darwin-x64/vectlite.node +0 -0
- package/prebuilds/linux-x64-gnu/vectlite.node +0 -0
- package/prebuilds/win32-x64-msvc/vectlite.node +0 -0
package/index.js
CHANGED
|
@@ -63,6 +63,7 @@ function loadNative() {
|
|
|
63
63
|
const native = loadNative()
|
|
64
64
|
|
|
65
65
|
const TOKEN_RE = /[a-z0-9]+/g
|
|
66
|
+
let otelTracer = null
|
|
66
67
|
|
|
67
68
|
class VectLiteError extends Error {
|
|
68
69
|
constructor(message, cause) {
|
|
@@ -102,10 +103,140 @@ function decode(value) {
|
|
|
102
103
|
return value == null ? null : JSON.parse(value)
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
function configureOpenTelemetry(options = {}) {
|
|
107
|
+
if (options === false || options?.enabled === false) {
|
|
108
|
+
otelTracer = null
|
|
109
|
+
return null
|
|
110
|
+
}
|
|
111
|
+
if (options?.tracer != null) {
|
|
112
|
+
otelTracer = options.tracer
|
|
113
|
+
return otelTracer
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const { trace } = require('@opentelemetry/api')
|
|
117
|
+
otelTracer = trace.getTracer(options?.tracerName ?? 'vectlite')
|
|
118
|
+
return otelTracer
|
|
119
|
+
} catch {
|
|
120
|
+
otelTracer = null
|
|
121
|
+
return null
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function searchAttributes(query, options, stats = null) {
|
|
126
|
+
const attrs = {
|
|
127
|
+
'db.system': 'vectlite',
|
|
128
|
+
'db.operation.name': 'search',
|
|
129
|
+
'vectlite.search.k': options?.k ?? 10,
|
|
130
|
+
'vectlite.search.namespace': options?.namespace ?? '',
|
|
131
|
+
'vectlite.search.all_namespaces': Boolean(options?.allNamespaces),
|
|
132
|
+
'vectlite.search.has_dense': query != null,
|
|
133
|
+
'vectlite.search.has_sparse': options?.sparse != null,
|
|
134
|
+
'vectlite.search.fusion': options?.fusion ?? 'linear',
|
|
135
|
+
}
|
|
136
|
+
if (options?.vectorName != null) attrs['vectlite.search.vector_name'] = options.vectorName
|
|
137
|
+
if (options?.truncateDim != null) attrs['vectlite.search.truncate_dim'] = options.truncateDim
|
|
138
|
+
if (stats != null) {
|
|
139
|
+
attrs['vectlite.search.used_ann'] = Boolean(stats.used_ann)
|
|
140
|
+
attrs['vectlite.search.exact_fallback'] = Boolean(stats.exact_fallback)
|
|
141
|
+
attrs['vectlite.search.considered_count'] = stats.considered_count ?? 0
|
|
142
|
+
attrs['vectlite.search.result_count'] = stats.result_count ?? 0
|
|
143
|
+
attrs['vectlite.search.effective_dimension'] = stats.effective_dimension ?? 0
|
|
144
|
+
attrs['vectlite.search.matryoshka_truncated'] = Boolean(stats.matryoshka_truncated)
|
|
145
|
+
attrs['vectlite.search.total_us'] = stats.timings?.total_us ?? 0
|
|
146
|
+
}
|
|
147
|
+
return attrs
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function withSearchSpan(query, options, fn) {
|
|
151
|
+
if (otelTracer == null) {
|
|
152
|
+
return fn()
|
|
153
|
+
}
|
|
154
|
+
return otelTracer.startActiveSpan('vectlite.search', { attributes: searchAttributes(query, options) }, (span) => {
|
|
155
|
+
try {
|
|
156
|
+
const value = fn()
|
|
157
|
+
if (isPromiseLike(value)) {
|
|
158
|
+
return value.then(
|
|
159
|
+
(resolved) => {
|
|
160
|
+
span.setAttributes(searchAttributes(query, options, resolved?.stats ?? null))
|
|
161
|
+
span.end()
|
|
162
|
+
return resolved
|
|
163
|
+
},
|
|
164
|
+
(error) => {
|
|
165
|
+
span.recordException?.(error)
|
|
166
|
+
span.setStatus?.({ code: 2, message: error?.message ?? String(error) })
|
|
167
|
+
span.end()
|
|
168
|
+
throw error
|
|
169
|
+
},
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
span.setAttributes(searchAttributes(query, options, value?.stats ?? null))
|
|
173
|
+
span.end()
|
|
174
|
+
return value
|
|
175
|
+
} catch (error) {
|
|
176
|
+
span.recordException?.(error)
|
|
177
|
+
span.setStatus?.({ code: 2, message: error?.message ?? String(error) })
|
|
178
|
+
span.end()
|
|
179
|
+
throw error
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
105
184
|
function asArray(values) {
|
|
185
|
+
if (
|
|
186
|
+
values != null &&
|
|
187
|
+
typeof values === 'object' &&
|
|
188
|
+
!Array.isArray(values) &&
|
|
189
|
+
!ArrayBuffer.isView(values) &&
|
|
190
|
+
typeof values[Symbol.iterator] !== 'function' &&
|
|
191
|
+
typeof values.length !== 'number'
|
|
192
|
+
) {
|
|
193
|
+
throw new TypeError('vector must be an array-like or iterable of numbers')
|
|
194
|
+
}
|
|
106
195
|
return Array.from(values)
|
|
107
196
|
}
|
|
108
197
|
|
|
198
|
+
function encodeNativeOptions(value) {
|
|
199
|
+
return typeof value === 'string' ? value : encode(value)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const SEARCH_OPTION_KEYS = new Set([
|
|
203
|
+
'query',
|
|
204
|
+
'k',
|
|
205
|
+
'filter',
|
|
206
|
+
'namespace',
|
|
207
|
+
'allNamespaces',
|
|
208
|
+
'sparse',
|
|
209
|
+
'denseWeight',
|
|
210
|
+
'sparseWeight',
|
|
211
|
+
'fetchK',
|
|
212
|
+
'mmrLambda',
|
|
213
|
+
'vectorName',
|
|
214
|
+
'fusion',
|
|
215
|
+
'rrfK',
|
|
216
|
+
'truncateDim',
|
|
217
|
+
'explain',
|
|
218
|
+
'queryVectors',
|
|
219
|
+
'vectorWeights',
|
|
220
|
+
])
|
|
221
|
+
|
|
222
|
+
function isSearchRequestObject(value) {
|
|
223
|
+
return (
|
|
224
|
+
value != null &&
|
|
225
|
+
typeof value === 'object' &&
|
|
226
|
+
!Array.isArray(value) &&
|
|
227
|
+
!ArrayBuffer.isView(value) &&
|
|
228
|
+
[...SEARCH_OPTION_KEYS].some((key) => Object.prototype.hasOwnProperty.call(value, key))
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function normalizeSearchArgs(query, options) {
|
|
233
|
+
if (isSearchRequestObject(query) && (options == null || Object.keys(options).length === 0)) {
|
|
234
|
+
const { query: normalizedQuery = null, ...normalizedOptions } = query
|
|
235
|
+
return { query: normalizedQuery, options: normalizedOptions }
|
|
236
|
+
}
|
|
237
|
+
return { query, options: options ?? {} }
|
|
238
|
+
}
|
|
239
|
+
|
|
109
240
|
function isPromiseLike(value) {
|
|
110
241
|
return value != null && typeof value.then === 'function'
|
|
111
242
|
}
|
|
@@ -123,6 +254,7 @@ function normalizeWriteOptions(options = {}) {
|
|
|
123
254
|
namespace: options.namespace ?? null,
|
|
124
255
|
sparse: options.sparse ?? null,
|
|
125
256
|
vectors: options.vectors ?? null,
|
|
257
|
+
ttl: options.ttl ?? null,
|
|
126
258
|
}
|
|
127
259
|
}
|
|
128
260
|
|
|
@@ -150,16 +282,16 @@ class Transaction {
|
|
|
150
282
|
}
|
|
151
283
|
|
|
152
284
|
insert(id, vector, metadata = null, options = {}) {
|
|
153
|
-
const { namespace, sparse, vectors } = normalizeWriteOptions(options)
|
|
285
|
+
const { namespace, sparse, vectors, ttl } = normalizeWriteOptions(options)
|
|
154
286
|
return wrapError(() =>
|
|
155
|
-
this._native.insert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors)),
|
|
287
|
+
this._native.insert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors), ttl),
|
|
156
288
|
)
|
|
157
289
|
}
|
|
158
290
|
|
|
159
291
|
upsert(id, vector, metadata = null, options = {}) {
|
|
160
|
-
const { namespace, sparse, vectors } = normalizeWriteOptions(options)
|
|
292
|
+
const { namespace, sparse, vectors, ttl } = normalizeWriteOptions(options)
|
|
161
293
|
return wrapError(() =>
|
|
162
|
-
this._native.upsert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors)),
|
|
294
|
+
this._native.upsert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors), ttl),
|
|
163
295
|
)
|
|
164
296
|
}
|
|
165
297
|
|
|
@@ -205,6 +337,10 @@ class Database {
|
|
|
205
337
|
return wrapError(() => this._native.dimension)
|
|
206
338
|
}
|
|
207
339
|
|
|
340
|
+
get metric() {
|
|
341
|
+
return wrapError(() => this._native.metric)
|
|
342
|
+
}
|
|
343
|
+
|
|
208
344
|
get readOnly() {
|
|
209
345
|
return wrapError(() => this._native.readOnly)
|
|
210
346
|
}
|
|
@@ -234,21 +370,35 @@ class Database {
|
|
|
234
370
|
)
|
|
235
371
|
}
|
|
236
372
|
|
|
373
|
+
listCursor(options = {}) {
|
|
374
|
+
return wrapError(() => {
|
|
375
|
+
const raw = decode(
|
|
376
|
+
this._native.listCursor(
|
|
377
|
+
options.namespace ?? null,
|
|
378
|
+
encode(options.filter),
|
|
379
|
+
options.limit ?? null,
|
|
380
|
+
options.cursor ?? null,
|
|
381
|
+
),
|
|
382
|
+
)
|
|
383
|
+
return { records: raw.records, cursor: raw.cursor ?? null }
|
|
384
|
+
})
|
|
385
|
+
}
|
|
386
|
+
|
|
237
387
|
transaction() {
|
|
238
388
|
return wrapError(() => new Transaction(this._native.transaction()))
|
|
239
389
|
}
|
|
240
390
|
|
|
241
391
|
insert(id, vector, metadata = null, options = {}) {
|
|
242
|
-
const { namespace, sparse, vectors } = normalizeWriteOptions(options)
|
|
392
|
+
const { namespace, sparse, vectors, ttl } = normalizeWriteOptions(options)
|
|
243
393
|
return wrapError(() =>
|
|
244
|
-
this._native.insert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors)),
|
|
394
|
+
this._native.insert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors), ttl),
|
|
245
395
|
)
|
|
246
396
|
}
|
|
247
397
|
|
|
248
398
|
upsert(id, vector, metadata = null, options = {}) {
|
|
249
|
-
const { namespace, sparse, vectors } = normalizeWriteOptions(options)
|
|
399
|
+
const { namespace, sparse, vectors, ttl } = normalizeWriteOptions(options)
|
|
250
400
|
return wrapError(() =>
|
|
251
|
-
this._native.upsert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors)),
|
|
401
|
+
this._native.upsert(id, asArray(vector), encode(metadata), namespace, encode(sparse), encode(vectors), ttl),
|
|
252
402
|
)
|
|
253
403
|
}
|
|
254
404
|
|
|
@@ -282,6 +432,78 @@ class Database {
|
|
|
282
432
|
return wrapError(() => this._native.deleteByFilter(encode(filter), options.namespace ?? null))
|
|
283
433
|
}
|
|
284
434
|
|
|
435
|
+
updateMetadata(id, metadata, options = {}) {
|
|
436
|
+
return wrapError(() =>
|
|
437
|
+
this._native.updateMetadata(id, encode(metadata), options.namespace ?? null),
|
|
438
|
+
)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
setTtl(id, ttl, options = {}) {
|
|
442
|
+
return wrapError(() => this._native.setTtl(id, ttl, options.namespace ?? null))
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
clearTtl(id, options = {}) {
|
|
446
|
+
return wrapError(() => this._native.clearTtl(id, options.namespace ?? null))
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
createIndex(field, indexType) {
|
|
450
|
+
return wrapError(() => this._native.createIndex(field, indexType))
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
dropIndex(field) {
|
|
454
|
+
return wrapError(() => this._native.dropIndex(field))
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
listIndexes() {
|
|
458
|
+
return wrapError(() => decode(this._native.listIndexes()))
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
enableQuantization(method = 'scalar', options = {}) {
|
|
462
|
+
return wrapError(() => this._native.enableQuantization(method, encodeNativeOptions(options)))
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
disableQuantization() {
|
|
466
|
+
return wrapError(() => this._native.disableQuantization())
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
get isQuantized() {
|
|
470
|
+
return wrapError(() => this._native.isQuantized)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
get quantizationMethod() {
|
|
474
|
+
return wrapError(() => this._native.quantizationMethod)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
validNumSubVectors() {
|
|
478
|
+
return wrapError(() => this._native.validNumSubVectors())
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
upsertMultiVectors(id, vector, multiVectors, options = {}) {
|
|
482
|
+
return wrapError(() =>
|
|
483
|
+
this._native.upsertMultiVectors(id, asArray(vector), encode(multiVectors), encode(options)),
|
|
484
|
+
)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
searchMultiVector(space, queryTokens, options = {}) {
|
|
488
|
+
return wrapError(() =>
|
|
489
|
+
decode(this._native.searchMultiVector(space, encode(queryTokens), encode(options))),
|
|
490
|
+
)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
enableMultiVectorQuantization(space, options = {}) {
|
|
494
|
+
return wrapError(() =>
|
|
495
|
+
this._native.enableMultiVectorQuantization(space, encodeNativeOptions(options)),
|
|
496
|
+
)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
disableMultiVectorQuantization(space) {
|
|
500
|
+
return wrapError(() => this._native.disableMultiVectorQuantization(space))
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
isMultiVectorQuantized(space) {
|
|
504
|
+
return wrapError(() => this._native.isMultiVectorQuantized(space))
|
|
505
|
+
}
|
|
506
|
+
|
|
285
507
|
flush() {
|
|
286
508
|
return wrapError(() => this._native.flush())
|
|
287
509
|
}
|
|
@@ -299,12 +521,68 @@ class Database {
|
|
|
299
521
|
}
|
|
300
522
|
|
|
301
523
|
search(query = null, options = {}) {
|
|
302
|
-
|
|
524
|
+
const normalized = normalizeSearchArgs(query, options)
|
|
525
|
+
return withSearchSpan(normalized.query, normalized.options, () =>
|
|
526
|
+
wrapError(() =>
|
|
527
|
+
decode(
|
|
528
|
+
this._native.search(
|
|
529
|
+
normalized.query == null ? null : asArray(normalized.query),
|
|
530
|
+
encode(normalized.options),
|
|
531
|
+
),
|
|
532
|
+
),
|
|
533
|
+
),
|
|
534
|
+
)
|
|
303
535
|
}
|
|
304
536
|
|
|
305
537
|
searchWithStats(query = null, options = {}) {
|
|
306
|
-
|
|
307
|
-
|
|
538
|
+
const normalized = normalizeSearchArgs(query, options)
|
|
539
|
+
return withSearchSpan(normalized.query, normalized.options, () =>
|
|
540
|
+
wrapError(() =>
|
|
541
|
+
decode(
|
|
542
|
+
this._native.searchWithStats(
|
|
543
|
+
normalized.query == null ? null : asArray(normalized.query),
|
|
544
|
+
encode(normalized.options),
|
|
545
|
+
),
|
|
546
|
+
),
|
|
547
|
+
),
|
|
548
|
+
)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
searchAsync(query = null, options = {}) {
|
|
552
|
+
const normalized = normalizeSearchArgs(query, options)
|
|
553
|
+
return withSearchSpan(normalized.query, normalized.options, () =>
|
|
554
|
+
wrapAsync(
|
|
555
|
+
this._native.searchAsync(
|
|
556
|
+
normalized.query == null ? null : asArray(normalized.query),
|
|
557
|
+
encode(normalized.options),
|
|
558
|
+
),
|
|
559
|
+
).then(decode),
|
|
560
|
+
)
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
searchWithStatsAsync(query = null, options = {}) {
|
|
564
|
+
const normalized = normalizeSearchArgs(query, options)
|
|
565
|
+
return withSearchSpan(normalized.query, normalized.options, () =>
|
|
566
|
+
wrapAsync(
|
|
567
|
+
this._native.searchWithStatsAsync(
|
|
568
|
+
normalized.query == null ? null : asArray(normalized.query),
|
|
569
|
+
encode(normalized.options),
|
|
570
|
+
),
|
|
571
|
+
).then(decode),
|
|
572
|
+
)
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
flushAsync() {
|
|
576
|
+
return wrapAsync(this._native.flushAsync())
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
compactAsync() {
|
|
580
|
+
return wrapAsync(this._native.compactAsync())
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
bulkIngestAsync(records, options = {}) {
|
|
584
|
+
return wrapAsync(
|
|
585
|
+
this._native.bulkIngestAsync(encode(records), options.namespace ?? null, options.batchSize ?? 10_000),
|
|
308
586
|
)
|
|
309
587
|
}
|
|
310
588
|
}
|
|
@@ -341,11 +619,15 @@ class Store {
|
|
|
341
619
|
collections() {
|
|
342
620
|
return wrapError(() => this._native.collections())
|
|
343
621
|
}
|
|
622
|
+
|
|
623
|
+
close() {
|
|
624
|
+
return wrapError(() => this._native.close())
|
|
625
|
+
}
|
|
344
626
|
}
|
|
345
627
|
|
|
346
628
|
function open(path, options = {}) {
|
|
347
629
|
return wrapError(() =>
|
|
348
|
-
new Database(native.open(path, options.dimension ?? null, options.readOnly ?? false, options.lockTimeout ?? null)),
|
|
630
|
+
new Database(native.open(path, options.dimension ?? null, options.readOnly ?? false, options.lockTimeout ?? null, options.metric ?? null)),
|
|
349
631
|
)
|
|
350
632
|
}
|
|
351
633
|
|
|
@@ -393,6 +675,7 @@ module.exports = {
|
|
|
393
675
|
Store,
|
|
394
676
|
Transaction,
|
|
395
677
|
VectLiteError,
|
|
678
|
+
configureOpenTelemetry,
|
|
396
679
|
open,
|
|
397
680
|
openStore,
|
|
398
681
|
restore,
|