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/README.md
CHANGED
|
@@ -43,10 +43,12 @@ db.close()
|
|
|
43
43
|
### Core
|
|
44
44
|
|
|
45
45
|
- **Single-file storage** -- one `.vdb` file per database, portable and easy to back up
|
|
46
|
-
- **
|
|
46
|
+
- **Distance metrics** -- cosine (default), euclidean (L2), dot product, manhattan (L1) with SIMD acceleration
|
|
47
|
+
- **Dense vectors** -- automatic HNSW indexing with metric-aware distance functions
|
|
47
48
|
- **Sparse vectors** -- BM25-scored inverted index for keyword retrieval
|
|
48
49
|
- **Hybrid search** -- dense + sparse fusion with linear or RRF strategies
|
|
49
50
|
- **Vector quantization** -- scalar (int8, 4x), binary (32x), and product quantization (PQ) with 2-stage rescoring
|
|
51
|
+
- **Multi-vector / ColBERT** -- late interaction search with per-token MaxSim scoring and 2-bit quantization (~16x compression)
|
|
50
52
|
- **Rich metadata** -- string, number, boolean, null, array, and nested object values
|
|
51
53
|
- **Crash-safe WAL** -- writes land in a write-ahead log first, then checkpoint with `compact()`
|
|
52
54
|
- **Transactions** -- atomic batched writes with `db.transaction()`
|
|
@@ -61,6 +63,7 @@ db.close()
|
|
|
61
63
|
- **MMR diversification** -- `mmrLambda` controls relevance vs. diversity trade-off
|
|
62
64
|
- **Namespaces** -- logical isolation with per-namespace or cross-namespace search
|
|
63
65
|
- **Observability** -- `searchWithStats()` returns timings, BM25 term scores, ANN stats, and per-result explain payloads
|
|
66
|
+
- **Payload indexes** -- keyword and numeric indexes on metadata fields accelerate filtered queries on large collections
|
|
64
67
|
|
|
65
68
|
### Data Management
|
|
66
69
|
|
|
@@ -68,14 +71,35 @@ db.close()
|
|
|
68
71
|
- **Bulk ingestion** -- `bulkIngest()` with deferred index rebuilds for fast imports
|
|
69
72
|
- **Listing & filtered counts** -- `list()` and `count({ namespace, filter })` without a vector query
|
|
70
73
|
- **Delete by filter** -- `deleteByFilter()` for bulk deletion by metadata filter
|
|
74
|
+
- **Partial metadata updates** -- `updateMetadata()` merges a patch without re-writing the vector or rebuilding indexes
|
|
71
75
|
- **Snapshots** -- `db.snapshot(path)` creates a self-contained copy
|
|
72
76
|
- **Backup / Restore** -- `db.backup(dir)` and `vectlite.restore(dir, path)` for full roundtrips
|
|
73
77
|
- **Read-only mode** -- `vectlite.open(path, { readOnly: true })` for safe concurrent readers
|
|
74
78
|
- **Explicit close** -- `db.close()` to release locks deterministically
|
|
75
79
|
- **Lock timeouts** -- `lockTimeout` for bounded lock acquisition waits
|
|
80
|
+
- **TTL / Expiry** -- `setTtl()` / `clearTtl()` or `ttl` option on insert/upsert; expired records auto-filtered from reads and GC'd on compact
|
|
81
|
+
- **Cursor-based pagination** -- `listCursor()` for efficient iteration over large collections
|
|
82
|
+
- **Async API** -- `searchAsync()`, `compactAsync()`, `flushAsync()`, `bulkIngestAsync()` run on the libuv threadpool
|
|
76
83
|
|
|
77
84
|
## Usage
|
|
78
85
|
|
|
86
|
+
### Distance Metrics
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
// Default is cosine similarity
|
|
90
|
+
const db = vectlite.open('knowledge.vdb', { dimension: 384 })
|
|
91
|
+
|
|
92
|
+
// Choose a different metric at creation time
|
|
93
|
+
const db2 = vectlite.open('knowledge.vdb', { dimension: 384, metric: 'euclidean' })
|
|
94
|
+
const db3 = vectlite.open('knowledge.vdb', { dimension: 384, metric: 'dotproduct' })
|
|
95
|
+
const db4 = vectlite.open('knowledge.vdb', { dimension: 384, metric: 'manhattan' })
|
|
96
|
+
|
|
97
|
+
// Aliases: 'l2', 'dot', 'ip', 'l1'
|
|
98
|
+
console.log(db2.metric) // "euclidean"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The metric is persisted in the database file. Scores are always oriented so that **higher is better**.
|
|
102
|
+
|
|
79
103
|
### Hybrid Search
|
|
80
104
|
|
|
81
105
|
```js
|
|
@@ -114,6 +138,10 @@ products.upsert('p1', embedding, { name: 'Widget', price: 9.99 })
|
|
|
114
138
|
|
|
115
139
|
const logs = store.openOrCreateCollection('logs', 128)
|
|
116
140
|
console.log(store.collections()) // ["logs", "products"]
|
|
141
|
+
|
|
142
|
+
products.close()
|
|
143
|
+
logs.close()
|
|
144
|
+
store.close()
|
|
117
145
|
```
|
|
118
146
|
|
|
119
147
|
### Transactions
|
|
@@ -167,6 +195,9 @@ const records = db.list({ namespace: 'docs', filter: { stale: false }, limit: 20
|
|
|
167
195
|
const count = db.count({ namespace: 'docs', filter: { source: 'blog' } })
|
|
168
196
|
const deleted = db.deleteByFilter({ stale: true }, { namespace: 'docs' })
|
|
169
197
|
|
|
198
|
+
// Partial metadata update (merge patch -- only touches specified keys)
|
|
199
|
+
db.updateMetadata('doc1', { status: 'reviewed', score: 0.95 })
|
|
200
|
+
|
|
170
201
|
db.close()
|
|
171
202
|
```
|
|
172
203
|
|
|
@@ -184,22 +215,42 @@ console.log(outcome.stats.used_ann) // true
|
|
|
184
215
|
console.log(outcome.results[0].explain) // Detailed scoring breakdown
|
|
185
216
|
```
|
|
186
217
|
|
|
218
|
+
### Payload Indexes
|
|
219
|
+
|
|
220
|
+
Create keyword or numeric indexes on metadata fields to accelerate filtered queries on large collections. Indexes are automatically used by `search()`, `count()`, and `list()`.
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
// Create indexes on frequently-filtered fields
|
|
224
|
+
db.createIndex('source', 'keyword') // string equality, $in
|
|
225
|
+
db.createIndex('score', 'numeric') // range queries: $gt, $gte, $lt, $lte
|
|
226
|
+
|
|
227
|
+
// Filtered queries now use indexes automatically
|
|
228
|
+
const count = db.count({ filter: { source: 'blog' } })
|
|
229
|
+
const results = db.search(query, { k: 10, filter: { score: { $gte: 0.8 } } })
|
|
230
|
+
|
|
231
|
+
// Inspect and manage indexes
|
|
232
|
+
console.log(db.listIndexes()) // [{ field: 'source', type: 'keyword' }, ...]
|
|
233
|
+
db.dropIndex('score')
|
|
234
|
+
```
|
|
235
|
+
|
|
187
236
|
### Vector Quantization
|
|
188
237
|
|
|
189
|
-
Reduce memory usage and accelerate search with quantized vectors. All methods use a 2-stage pipeline: fast quantized candidate selection followed by exact float32 rescoring.
|
|
238
|
+
Reduce in-memory candidate-index usage and accelerate search with quantized vectors. All methods use a 2-stage pipeline: fast quantized candidate selection followed by exact float32 rescoring.
|
|
190
239
|
|
|
191
240
|
```js
|
|
192
|
-
// Scalar quantization (int8) --
|
|
241
|
+
// Scalar quantization (int8) -- smaller in-memory candidate index, minimal recall loss
|
|
193
242
|
db.enableQuantization('scalar')
|
|
194
243
|
|
|
195
|
-
// Binary quantization --
|
|
196
|
-
db.enableQuantization('binary',
|
|
244
|
+
// Binary quantization -- smallest in-memory candidate index, best for normalized embeddings
|
|
245
|
+
db.enableQuantization('binary', { rescoreMultiplier: 10 })
|
|
197
246
|
|
|
198
|
-
// Product quantization --
|
|
199
|
-
|
|
247
|
+
// Product quantization -- "pq" and "product" are accepted case-insensitively
|
|
248
|
+
console.log(db.validNumSubVectors()) // valid PQ partitions for this dimension
|
|
249
|
+
db.enableQuantization('pq', { numSubVectors: 16, numCentroids: 256 })
|
|
200
250
|
|
|
201
251
|
// Search works exactly the same -- quantization accelerates it transparently
|
|
202
252
|
const results = db.search(queryEmbedding, { k: 10 })
|
|
253
|
+
const sameResults = db.search({ query: queryEmbedding, k: 10 })
|
|
203
254
|
|
|
204
255
|
// Check quantization status
|
|
205
256
|
console.log(db.isQuantized) // true
|
|
@@ -209,7 +260,133 @@ console.log(db.quantizationMethod) // "scalar", "binary", or "product"
|
|
|
209
260
|
db.disableQuantization()
|
|
210
261
|
```
|
|
211
262
|
|
|
212
|
-
|
|
263
|
+
`rescoreMultiplier` controls the number of quantized candidates rescored with exact float32 scoring: `k * rescoreMultiplier`, capped at the collection size. Increase it to trade latency for recall.
|
|
264
|
+
|
|
265
|
+
For PQ, `numSubVectors` must divide the database dimension. If omitted, Vectlite chooses a compatible default; use `db.validNumSubVectors()` to inspect all valid values.
|
|
266
|
+
|
|
267
|
+
Quantization does not shrink the `.vdb` file on disk. Vectlite keeps the original float32 vectors for exact rescoring and stores quantization parameters in a `.vdb.quant` sidecar file, so total disk footprint can increase slightly. The quantized index auto-rebuilds on inserts and upserts.
|
|
268
|
+
|
|
269
|
+
### Multi-Vector / ColBERT Search
|
|
270
|
+
|
|
271
|
+
Store token-level embeddings (ColBERT, ColPali) and search with MaxSim late interaction scoring.
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
// Upsert with per-token ColBERT embeddings
|
|
275
|
+
db.upsertMultiVectors('doc1', denseVector,
|
|
276
|
+
{ colbert: [tokenVec1, tokenVec2] },
|
|
277
|
+
{ metadata: { source: 'paper' } }
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
// MaxSim search
|
|
281
|
+
const results = db.searchMultiVector('colbert', queryTokenVectors)
|
|
282
|
+
|
|
283
|
+
// Enable 2-bit quantization (~16x compression)
|
|
284
|
+
db.enableMultiVectorQuantization('colbert')
|
|
285
|
+
|
|
286
|
+
// Check and disable
|
|
287
|
+
console.log(db.isMultiVectorQuantized('colbert')) // true
|
|
288
|
+
db.disableMultiVectorQuantization('colbert')
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### TTL / Expiry
|
|
292
|
+
|
|
293
|
+
Records can automatically expire after a time-to-live. Expired records are transparently filtered from all reads and permanently removed on `compact()`.
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
// Set TTL on insert/upsert (seconds)
|
|
297
|
+
db.upsert('session1', embedding, { user: 'alice' }, { ttl: 3600 }) // expires in 1 hour
|
|
298
|
+
|
|
299
|
+
// Set/clear TTL on existing records
|
|
300
|
+
db.setTtl('doc1', 86400) // expire in 24 hours
|
|
301
|
+
db.clearTtl('doc1') // remove expiry
|
|
302
|
+
|
|
303
|
+
// Expired records are invisible to get/list/count/search
|
|
304
|
+
const record = db.get('session1') // null after TTL elapses
|
|
305
|
+
|
|
306
|
+
// compact() garbage-collects expired records from disk
|
|
307
|
+
db.compact()
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Cursor-Based Pagination
|
|
311
|
+
|
|
312
|
+
Efficiently iterate over large collections without offset overhead.
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
// Paginate 100 records at a time
|
|
316
|
+
let cursor = null
|
|
317
|
+
do {
|
|
318
|
+
const page = db.listCursor({ limit: 100, cursor })
|
|
319
|
+
for (const record of page.records) {
|
|
320
|
+
process(record)
|
|
321
|
+
}
|
|
322
|
+
cursor = page.cursor
|
|
323
|
+
} while (cursor !== null)
|
|
324
|
+
|
|
325
|
+
// Works with namespace and filter
|
|
326
|
+
const page = db.listCursor({ namespace: 'docs', filter: { source: 'blog' }, limit: 50 })
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Async API
|
|
330
|
+
|
|
331
|
+
Non-blocking versions of heavy operations that run on the libuv threadpool.
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
// Async search (returns a Promise)
|
|
335
|
+
const results = await db.searchAsync(queryEmbedding, { k: 10, filter: { source: 'blog' } })
|
|
336
|
+
|
|
337
|
+
// Async search with stats
|
|
338
|
+
const outcome = await db.searchWithStatsAsync(queryEmbedding, { k: 10 })
|
|
339
|
+
|
|
340
|
+
// Async maintenance
|
|
341
|
+
await db.flushAsync()
|
|
342
|
+
await db.compactAsync()
|
|
343
|
+
|
|
344
|
+
// Async bulk ingestion
|
|
345
|
+
const count = await db.bulkIngestAsync(records, { batchSize: 5000 })
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### OpenTelemetry Integration
|
|
349
|
+
|
|
350
|
+
vectlite ships with optional OpenTelemetry tracing. When enabled, every search
|
|
351
|
+
call is wrapped in a span carrying semantic DB attributes and search-specific
|
|
352
|
+
metrics. `@opentelemetry/api` is loaded lazily -- it is **not** a runtime
|
|
353
|
+
dependency.
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
const vectlite = require('vectlite')
|
|
357
|
+
|
|
358
|
+
// Auto-detect: resolves a tracer from @opentelemetry/api if installed
|
|
359
|
+
const tracer = vectlite.configureOpenTelemetry()
|
|
360
|
+
|
|
361
|
+
// Or supply your own tracer
|
|
362
|
+
vectlite.configureOpenTelemetry({ tracer: myTracer })
|
|
363
|
+
|
|
364
|
+
// Custom tracer name (default: 'vectlite')
|
|
365
|
+
vectlite.configureOpenTelemetry({ tracerName: 'my-app' })
|
|
366
|
+
|
|
367
|
+
// Disable
|
|
368
|
+
vectlite.configureOpenTelemetry(false)
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
When a tracer is active, each `search` / `searchWithStats` / `searchAsync` /
|
|
372
|
+
`searchWithStatsAsync` call creates a `vectlite.search` span with these
|
|
373
|
+
attributes:
|
|
374
|
+
|
|
375
|
+
| Attribute | Description |
|
|
376
|
+
|---|---|
|
|
377
|
+
| `db.system` | Always `"vectlite"` |
|
|
378
|
+
| `db.operation.name` | Always `"search"` |
|
|
379
|
+
| `vectlite.search.k` | Requested result count |
|
|
380
|
+
| `vectlite.search.namespace` | Target namespace |
|
|
381
|
+
| `vectlite.search.has_dense` | Whether a dense query vector was provided |
|
|
382
|
+
| `vectlite.search.has_sparse` | Whether sparse terms were provided |
|
|
383
|
+
| `vectlite.search.fusion` | Fusion strategy (`"linear"` or `"rrf"`) |
|
|
384
|
+
| `vectlite.search.used_ann` | Whether HNSW was used (set after completion) |
|
|
385
|
+
| `vectlite.search.result_count` | Number of results returned (set after completion) |
|
|
386
|
+
| `vectlite.search.total_us` | Total search time in microseconds (set after completion) |
|
|
387
|
+
|
|
388
|
+
If a search throws, the span records the exception and sets an error status
|
|
389
|
+
before re-throwing.
|
|
213
390
|
|
|
214
391
|
## Database Methods Reference
|
|
215
392
|
|
|
@@ -225,29 +402,46 @@ Quantization parameters persist across reopens in a `.vdb.quant` sidecar file. T
|
|
|
225
402
|
| `db.delete(id, { namespace })` | Delete a single record |
|
|
226
403
|
| `db.deleteMany(ids, { namespace })` | Delete multiple records by id |
|
|
227
404
|
| `db.deleteByFilter(filter, { namespace })` | Delete all records matching a filter |
|
|
405
|
+
| `db.updateMetadata(id, metadata, { namespace })` | Merge a metadata patch into an existing record (no vector rewrite) |
|
|
406
|
+
| `db.setTtl(id, seconds, { namespace })` | Set time-to-live on a record (seconds from now) |
|
|
407
|
+
| `db.clearTtl(id, { namespace })` | Remove TTL from a record |
|
|
228
408
|
|
|
229
409
|
### Read Methods
|
|
230
410
|
|
|
231
411
|
| Method | Description |
|
|
232
412
|
|---|---|
|
|
233
413
|
| `db.get(id, { namespace })` | Get a single record by id |
|
|
234
|
-
| `db.search(query, options)` | Search and return a list of results |
|
|
414
|
+
| `db.search(query, options)` or `db.search({ query, ...options })` | Search and return a list of results |
|
|
235
415
|
| `db.searchWithStats(query, options)` | Search with detailed performance stats |
|
|
236
416
|
| `db.count({ namespace, filter })` | Count records, optionally scoped by namespace/filter |
|
|
237
417
|
| `db.list({ namespace, filter, limit, offset })` | List records without issuing a vector query |
|
|
418
|
+
| `db.listCursor({ namespace, filter, limit, cursor })` | Cursor-based pagination for large collections |
|
|
238
419
|
| `db.namespaces()` | List all namespaces |
|
|
239
420
|
| `db.dimension` | Vector dimension (property) |
|
|
240
421
|
| `db.path` | Database file path (property) |
|
|
422
|
+
| `db.metric` | Distance metric name: `"cosine"`, `"euclidean"`, `"dotproduct"`, or `"manhattan"` (property) |
|
|
241
423
|
| `db.readOnly` | Whether the database is read-only (property) |
|
|
242
424
|
|
|
425
|
+
### Index Methods
|
|
426
|
+
|
|
427
|
+
| Method | Description |
|
|
428
|
+
|---|---|
|
|
429
|
+
| `db.createIndex(field, indexType)` | Create a payload index (`'keyword'` or `'numeric'`) on a metadata field |
|
|
430
|
+
| `db.dropIndex(field)` | Remove an index |
|
|
431
|
+
| `db.listIndexes()` | List all active indexes as `[{ field, type }, ...]` |
|
|
432
|
+
|
|
243
433
|
### Quantization Methods
|
|
244
434
|
|
|
245
435
|
| Method | Description |
|
|
246
436
|
|---|---|
|
|
247
|
-
| `db.enableQuantization(method,
|
|
437
|
+
| `db.enableQuantization(method, options)` | Enable quantization (`'scalar'`, `'binary'`, or `'pq'` / `'product'`) |
|
|
248
438
|
| `db.disableQuantization()` | Disable quantization and remove persisted parameters |
|
|
249
439
|
| `db.isQuantized` | Whether quantization is enabled (property) |
|
|
250
440
|
| `db.quantizationMethod` | Active method name or `null` (property) |
|
|
441
|
+
| `db.validNumSubVectors()` | Valid PQ `numSubVectors` values for this database dimension |
|
|
442
|
+
| `db.enableMultiVectorQuantization(space, options)` | Enable 2-bit quantization for a multi-vector space |
|
|
443
|
+
| `db.disableMultiVectorQuantization(space)` | Disable multi-vector quantization for a space |
|
|
444
|
+
| `db.isMultiVectorQuantized(space)` | Whether multi-vector quantization is enabled for a space |
|
|
251
445
|
|
|
252
446
|
### Maintenance Methods
|
|
253
447
|
|
|
@@ -260,6 +454,16 @@ Quantization parameters persist across reopens in a `.vdb.quant` sidecar file. T
|
|
|
260
454
|
| `db.transaction()` | Begin an atomic transaction |
|
|
261
455
|
| `db.close()` | Flush pending state, release the file lock, and invalidate the handle |
|
|
262
456
|
|
|
457
|
+
### Async Methods
|
|
458
|
+
|
|
459
|
+
| Method | Description |
|
|
460
|
+
|---|---|
|
|
461
|
+
| `db.searchAsync(query, options)` | Non-blocking search (returns Promise) |
|
|
462
|
+
| `db.searchWithStatsAsync(query, options)` | Non-blocking search with stats (returns Promise) |
|
|
463
|
+
| `db.flushAsync()` | Non-blocking flush/compact (returns Promise) |
|
|
464
|
+
| `db.compactAsync()` | Non-blocking compact (returns Promise) |
|
|
465
|
+
| `db.bulkIngestAsync(records, options)` | Non-blocking bulk import (returns Promise) |
|
|
466
|
+
|
|
263
467
|
## Filter Operators
|
|
264
468
|
|
|
265
469
|
| Operator | Example | Description |
|
package/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type MetadataValue =
|
|
|
9
9
|
export type Metadata = { [key: string]: MetadataValue }
|
|
10
10
|
export type SparseVector = { [term: string]: number }
|
|
11
11
|
export type NamedVectors = { [name: string]: number[] }
|
|
12
|
+
export type MultiVectors = { [space: string]: number[][] }
|
|
12
13
|
export type Filter = { [key: string]: unknown }
|
|
13
14
|
export type TextEmbedding = ArrayLike<number>
|
|
14
15
|
export type TextEmbeddingResult = TextEmbedding | Promise<TextEmbedding>
|
|
@@ -21,6 +22,7 @@ export interface Record {
|
|
|
21
22
|
vectors: NamedVectors
|
|
22
23
|
sparse: SparseVector
|
|
23
24
|
metadata: Metadata
|
|
25
|
+
expires_at: number | null
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface SearchTimings {
|
|
@@ -41,6 +43,8 @@ export interface SearchStats {
|
|
|
41
43
|
ann_loaded_from_disk: boolean
|
|
42
44
|
wal_entries_replayed: number
|
|
43
45
|
fusion: string
|
|
46
|
+
effective_dimension: number
|
|
47
|
+
matryoshka_truncated: boolean
|
|
44
48
|
rerank_applied: boolean
|
|
45
49
|
rerank_count: number
|
|
46
50
|
timings: SearchTimings
|
|
@@ -80,6 +84,7 @@ export interface WriteOptions {
|
|
|
80
84
|
namespace?: string | null
|
|
81
85
|
sparse?: SparseVector | null
|
|
82
86
|
vectors?: NamedVectors | null
|
|
87
|
+
ttl?: number | null
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
export interface CountOptions {
|
|
@@ -92,6 +97,16 @@ export interface ListOptions extends CountOptions {
|
|
|
92
97
|
offset?: number | null
|
|
93
98
|
}
|
|
94
99
|
|
|
100
|
+
export interface ListCursorOptions extends CountOptions {
|
|
101
|
+
limit?: number | null
|
|
102
|
+
cursor?: string | null
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface ListCursorResult {
|
|
106
|
+
records: Record[]
|
|
107
|
+
cursor: string | null
|
|
108
|
+
}
|
|
109
|
+
|
|
95
110
|
export interface BulkIngestOptions {
|
|
96
111
|
namespace?: string | null
|
|
97
112
|
batchSize?: number
|
|
@@ -110,15 +125,59 @@ export interface SearchOptions {
|
|
|
110
125
|
vectorName?: string | null
|
|
111
126
|
fusion?: 'linear' | 'rrf'
|
|
112
127
|
rrfK?: number
|
|
128
|
+
truncateDim?: number | null
|
|
113
129
|
explain?: boolean
|
|
114
130
|
queryVectors?: { [name: string]: number[] } | null
|
|
115
131
|
vectorWeights?: { [name: string]: number } | null
|
|
116
132
|
}
|
|
117
133
|
|
|
134
|
+
export interface SearchRequest extends SearchOptions {
|
|
135
|
+
query?: number[] | null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export type QuantizationMethod = 'scalar' | 'int8' | 'binary' | 'product' | 'pq'
|
|
139
|
+
export interface QuantizationOptions {
|
|
140
|
+
rescoreMultiplier?: number
|
|
141
|
+
rescore_multiplier?: number
|
|
142
|
+
numSubVectors?: number
|
|
143
|
+
num_sub_vectors?: number
|
|
144
|
+
numCentroids?: number
|
|
145
|
+
num_centroids?: number
|
|
146
|
+
trainingIterations?: number
|
|
147
|
+
training_iterations?: number
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface MultiVectorWriteOptions {
|
|
151
|
+
namespace?: string | null
|
|
152
|
+
metadata?: Metadata | null
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface MultiVectorSearchOptions {
|
|
156
|
+
k?: number
|
|
157
|
+
filter?: Filter | null
|
|
158
|
+
namespace?: string | null
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface MultiVectorSearchResult {
|
|
162
|
+
namespace: string
|
|
163
|
+
id: string
|
|
164
|
+
score: number
|
|
165
|
+
metadata: Metadata
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface MultiVectorQuantizationOptions {
|
|
169
|
+
method?: 'two_bit'
|
|
170
|
+
rescoreMultiplier?: number
|
|
171
|
+
rescore_multiplier?: number
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export type DistanceMetric = 'cosine' | 'euclidean' | 'dotproduct' | 'manhattan' | 'l2' | 'dot' | 'ip' | 'l1'
|
|
175
|
+
|
|
118
176
|
export interface OpenOptions {
|
|
119
177
|
dimension?: number | null
|
|
120
178
|
readOnly?: boolean
|
|
121
179
|
lockTimeout?: number | null
|
|
180
|
+
metric?: DistanceMetric | null
|
|
122
181
|
}
|
|
123
182
|
|
|
124
183
|
export class VectLiteError extends Error {}
|
|
@@ -139,12 +198,14 @@ export class Database {
|
|
|
139
198
|
readonly path: string
|
|
140
199
|
readonly walPath: string
|
|
141
200
|
readonly dimension: number
|
|
201
|
+
readonly metric: string
|
|
142
202
|
readonly readOnly: boolean
|
|
143
203
|
|
|
144
204
|
count(options?: CountOptions): number
|
|
145
205
|
namespaces(): string[]
|
|
146
206
|
close(): void
|
|
147
207
|
list(options?: ListOptions): Record[]
|
|
208
|
+
listCursor(options?: ListCursorOptions): ListCursorResult
|
|
148
209
|
transaction(): Transaction
|
|
149
210
|
insert(id: string, vector: number[], metadata?: Metadata | null, options?: WriteOptions): void
|
|
150
211
|
upsert(id: string, vector: number[], metadata?: Metadata | null, options?: WriteOptions): void
|
|
@@ -155,12 +216,37 @@ export class Database {
|
|
|
155
216
|
delete(id: string, options?: { namespace?: string | null }): boolean
|
|
156
217
|
deleteMany(ids: string[], options?: { namespace?: string | null }): number
|
|
157
218
|
deleteByFilter(filter: Filter, options?: { namespace?: string | null }): number
|
|
219
|
+
updateMetadata(id: string, metadata: Metadata, options?: { namespace?: string | null }): boolean
|
|
220
|
+
setTtl(id: string, ttl: number, options?: { namespace?: string | null }): boolean
|
|
221
|
+
clearTtl(id: string, options?: { namespace?: string | null }): boolean
|
|
222
|
+
createIndex(field: string, indexType: 'keyword' | 'numeric'): boolean
|
|
223
|
+
dropIndex(field: string): boolean
|
|
224
|
+
listIndexes(): Array<{ field: string; type: 'keyword' | 'numeric' }>
|
|
225
|
+
readonly isQuantized: boolean
|
|
226
|
+
readonly quantizationMethod: 'scalar' | 'binary' | 'product' | null
|
|
227
|
+
enableQuantization(method?: QuantizationMethod, options?: QuantizationOptions | string): void
|
|
228
|
+
disableQuantization(): void
|
|
229
|
+
validNumSubVectors(): number[]
|
|
230
|
+
upsertMultiVectors(id: string, vector: number[], multiVectors: MultiVectors, options?: MultiVectorWriteOptions): void
|
|
231
|
+
searchMultiVector(space: string, queryTokens: number[][], options?: MultiVectorSearchOptions): MultiVectorSearchResult[]
|
|
232
|
+
enableMultiVectorQuantization(space: string, options?: MultiVectorQuantizationOptions | string): void
|
|
233
|
+
disableMultiVectorQuantization(space: string): void
|
|
234
|
+
isMultiVectorQuantized(space: string): boolean
|
|
158
235
|
flush(): void
|
|
159
236
|
compact(): void
|
|
160
237
|
snapshot(dest: string): void
|
|
161
238
|
backup(dest: string): void
|
|
239
|
+
search(request: SearchRequest): SearchResult[]
|
|
162
240
|
search(query?: number[] | null, options?: SearchOptions): SearchResult[]
|
|
241
|
+
searchWithStats(request: SearchRequest): SearchResponse
|
|
163
242
|
searchWithStats(query?: number[] | null, options?: SearchOptions): SearchResponse
|
|
243
|
+
searchAsync(request: SearchRequest): Promise<SearchResult[]>
|
|
244
|
+
searchAsync(query?: number[] | null, options?: SearchOptions): Promise<SearchResult[]>
|
|
245
|
+
searchWithStatsAsync(request: SearchRequest): Promise<SearchResponse>
|
|
246
|
+
searchWithStatsAsync(query?: number[] | null, options?: SearchOptions): Promise<SearchResponse>
|
|
247
|
+
flushAsync(): Promise<void>
|
|
248
|
+
compactAsync(): Promise<void>
|
|
249
|
+
bulkIngestAsync(records: Record[], options?: BulkIngestOptions): Promise<number>
|
|
164
250
|
}
|
|
165
251
|
|
|
166
252
|
export class Store {
|
|
@@ -171,11 +257,36 @@ export class Store {
|
|
|
171
257
|
openCollectionReadOnly(name: string): Database
|
|
172
258
|
dropCollection(name: string): boolean
|
|
173
259
|
collections(): string[]
|
|
260
|
+
close(): void
|
|
174
261
|
}
|
|
175
262
|
|
|
176
263
|
export function open(path: string, options?: OpenOptions): Database
|
|
177
264
|
export function openStore(root: string): Store
|
|
178
265
|
export function restore(source: string, dest: string): Database
|
|
266
|
+
export interface OpenTelemetryOptions {
|
|
267
|
+
/** Pass `false` or `{ enabled: false }` to disable tracing. */
|
|
268
|
+
enabled?: boolean
|
|
269
|
+
/** Supply your own OTel `Tracer` instance. */
|
|
270
|
+
tracer?: unknown
|
|
271
|
+
/** Tracer name used when auto-resolving via `@opentelemetry/api`. Defaults to `'vectlite'`. */
|
|
272
|
+
tracerName?: string
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Configure optional OpenTelemetry tracing for search operations.
|
|
277
|
+
*
|
|
278
|
+
* When a tracer is active, every `search`, `searchWithStats`, `searchAsync`,
|
|
279
|
+
* and `searchWithStatsAsync` call is wrapped in a span with semantic
|
|
280
|
+
* `db.system` / `db.operation.name` attributes and search-specific metrics.
|
|
281
|
+
*
|
|
282
|
+
* `@opentelemetry/api` is loaded lazily via `require()` -- it is **not** a
|
|
283
|
+
* runtime dependency. If the package is not installed the function returns
|
|
284
|
+
* `null` and search calls remain un-instrumented.
|
|
285
|
+
*
|
|
286
|
+
* @returns The resolved tracer, or `null` if tracing could not be configured.
|
|
287
|
+
*/
|
|
288
|
+
export function configureOpenTelemetry(options?: OpenTelemetryOptions | false): unknown | null
|
|
289
|
+
|
|
179
290
|
export function sparseTerms(text: string): SparseVector
|
|
180
291
|
export function upsertText(
|
|
181
292
|
db: Database,
|