@wiscale/velesdb-sdk 1.5.1 → 1.7.0
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 +479 -194
- package/dist/index.d.mts +261 -62
- package/dist/index.d.ts +261 -62
- package/dist/index.js +1042 -699
- package/dist/index.mjs +1041 -699
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
# @wiscale/velesdb-sdk
|
|
2
2
|
|
|
3
|
-
Official TypeScript SDK for VelesDB -
|
|
3
|
+
Official TypeScript SDK for [VelesDB](https://github.com/cyberlife-coder/VelesDB) -- the local-first vector database for AI and RAG. Sub-millisecond semantic search in Browser and Node.js.
|
|
4
|
+
|
|
5
|
+
**v1.7.0** | Node.js >= 18 | Browser (WASM) | MIT License
|
|
6
|
+
|
|
7
|
+
## What's New in v1.7.0
|
|
8
|
+
|
|
9
|
+
- **Agent Memory API** -- semantic, episodic, and procedural memory for AI agents (REST only)
|
|
10
|
+
- **Graph collections** -- dedicated `createGraphCollection()` for knowledge graphs (REST only)
|
|
11
|
+
- **Metadata-only collections** -- reference tables with no vectors, joinable via VelesQL
|
|
12
|
+
- **Sparse vector support** -- hybrid sparse+dense search on insert and query (REST + WASM)
|
|
13
|
+
- **Stream insert with backpressure** -- `streamInsert()` for high-throughput ingestion (REST only)
|
|
14
|
+
- **Product Quantization training** -- `trainPq()` for further memory compression (REST only)
|
|
15
|
+
- **Collection analytics** -- `analyzeCollection()`, `getCollectionStats()`, `getCollectionConfig()` (REST only)
|
|
16
|
+
- **Property indexes** -- `createIndex()` / `listIndexes()` / `dropIndex()` for O(1) lookups (REST only)
|
|
17
|
+
- **Query introspection** -- `queryExplain()` and `collectionSanity()` diagnostics (REST only)
|
|
18
|
+
- **Batch search** -- `searchBatch()` for parallel multi-query execution
|
|
19
|
+
- **Lightweight search** -- `searchIds()` returns only IDs and scores (REST only)
|
|
4
20
|
|
|
5
21
|
## Installation
|
|
6
22
|
|
|
@@ -10,65 +26,73 @@ npm install @wiscale/velesdb-sdk
|
|
|
10
26
|
|
|
11
27
|
## Quick Start
|
|
12
28
|
|
|
13
|
-
### WASM Backend (Browser/Node.js)
|
|
29
|
+
### WASM Backend (Browser / Node.js)
|
|
30
|
+
|
|
31
|
+
The WASM backend runs entirely in-process -- no server required. Ideal for browser apps, prototyping, and edge deployments.
|
|
14
32
|
|
|
15
33
|
```typescript
|
|
16
34
|
import { VelesDB } from '@wiscale/velesdb-sdk';
|
|
17
35
|
|
|
18
|
-
//
|
|
36
|
+
// 1. Create a client with WASM backend
|
|
19
37
|
const db = new VelesDB({ backend: 'wasm' });
|
|
20
38
|
await db.init();
|
|
21
39
|
|
|
22
|
-
// Create a collection
|
|
40
|
+
// 2. Create a collection (768 dimensions for BERT, 1536 for OpenAI, etc.)
|
|
23
41
|
await db.createCollection('documents', {
|
|
24
|
-
dimension: 768,
|
|
42
|
+
dimension: 768,
|
|
25
43
|
metric: 'cosine'
|
|
26
44
|
});
|
|
27
45
|
|
|
28
|
-
// Insert vectors
|
|
46
|
+
// 3. Insert vectors with metadata
|
|
29
47
|
await db.insert('documents', {
|
|
30
48
|
id: 'doc-1',
|
|
31
49
|
vector: new Float32Array(768).fill(0.1),
|
|
32
50
|
payload: { title: 'Hello World', category: 'greeting' }
|
|
33
51
|
});
|
|
34
52
|
|
|
35
|
-
// Batch insert
|
|
53
|
+
// 4. Batch insert for better throughput
|
|
36
54
|
await db.insertBatch('documents', [
|
|
37
|
-
{ id: 'doc-2', vector:
|
|
38
|
-
{ id: 'doc-3', vector:
|
|
55
|
+
{ id: 'doc-2', vector: new Float32Array(768).fill(0.2), payload: { title: 'Second doc' } },
|
|
56
|
+
{ id: 'doc-3', vector: new Float32Array(768).fill(0.3), payload: { title: 'Third doc' } },
|
|
39
57
|
]);
|
|
40
58
|
|
|
41
|
-
// Search
|
|
59
|
+
// 5. Search for similar vectors
|
|
42
60
|
const results = await db.search('documents', queryVector, { k: 5 });
|
|
43
61
|
console.log(results);
|
|
44
|
-
// [{ id: 'doc-1', score: 0.95, payload: { title: '
|
|
62
|
+
// [{ id: 'doc-1', score: 0.95, payload: { title: 'Hello World', ... } }, ...]
|
|
45
63
|
|
|
46
|
-
// Cleanup
|
|
64
|
+
// 6. Cleanup
|
|
47
65
|
await db.close();
|
|
48
66
|
```
|
|
49
67
|
|
|
50
68
|
### REST Backend (Server)
|
|
51
69
|
|
|
70
|
+
The REST backend connects to a running VelesDB server. Use this for production deployments, multi-client access, and persistent storage.
|
|
71
|
+
|
|
52
72
|
```typescript
|
|
53
73
|
import { VelesDB } from '@wiscale/velesdb-sdk';
|
|
54
74
|
|
|
55
75
|
const db = new VelesDB({
|
|
56
76
|
backend: 'rest',
|
|
57
77
|
url: 'http://localhost:8080',
|
|
58
|
-
apiKey: 'your-api-key'
|
|
78
|
+
apiKey: 'your-api-key' // optional
|
|
59
79
|
});
|
|
60
80
|
|
|
61
81
|
await db.init();
|
|
62
82
|
|
|
63
83
|
// Same API as WASM backend
|
|
64
84
|
await db.createCollection('products', { dimension: 1536 });
|
|
65
|
-
await db.insert('products', { id: 1, vector:
|
|
66
|
-
const results = await db.search('products',
|
|
85
|
+
await db.insert('products', { id: 1, vector: embedding });
|
|
86
|
+
const results = await db.search('products', queryVector, { k: 10 });
|
|
67
87
|
```
|
|
68
88
|
|
|
89
|
+
> **REST backend note:** Document IDs must be numeric integers in the range `0..Number.MAX_SAFE_INTEGER`. String IDs are only supported with the WASM backend.
|
|
90
|
+
|
|
69
91
|
## API Reference
|
|
70
92
|
|
|
71
|
-
###
|
|
93
|
+
### Client
|
|
94
|
+
|
|
95
|
+
#### `new VelesDB(config)`
|
|
72
96
|
|
|
73
97
|
Create a new VelesDB client.
|
|
74
98
|
|
|
@@ -77,356 +101,617 @@ Create a new VelesDB client.
|
|
|
77
101
|
| `backend` | `'wasm' \| 'rest'` | Yes | Backend type |
|
|
78
102
|
| `url` | `string` | REST only | Server URL |
|
|
79
103
|
| `apiKey` | `string` | No | API key for authentication |
|
|
80
|
-
| `timeout` | `number` | No | Request timeout
|
|
104
|
+
| `timeout` | `number` | No | Request timeout in ms (default: 30000) |
|
|
105
|
+
|
|
106
|
+
#### `db.init()`
|
|
107
|
+
|
|
108
|
+
Initialize the client. **Must be called before any operations.** For the REST backend, this verifies connectivity to the server.
|
|
109
|
+
|
|
110
|
+
#### `db.close()`
|
|
111
|
+
|
|
112
|
+
Close the client and release resources.
|
|
81
113
|
|
|
82
|
-
|
|
114
|
+
---
|
|
83
115
|
|
|
84
|
-
|
|
116
|
+
### Collection Management
|
|
85
117
|
|
|
86
|
-
|
|
118
|
+
#### `db.createCollection(name, config)`
|
|
87
119
|
|
|
88
|
-
Create a
|
|
120
|
+
Create a vector collection.
|
|
89
121
|
|
|
90
122
|
| Option | Type | Default | Description |
|
|
91
123
|
|--------|------|---------|-------------|
|
|
92
124
|
| `dimension` | `number` | Required | Vector dimension |
|
|
93
125
|
| `metric` | `'cosine' \| 'euclidean' \| 'dot' \| 'hamming' \| 'jaccard'` | `'cosine'` | Distance metric |
|
|
94
|
-
| `storageMode` | `'full' \| 'sq8' \| 'binary'` | `'full'` |
|
|
126
|
+
| `storageMode` | `'full' \| 'sq8' \| 'binary'` | `'full'` | Quantization mode |
|
|
127
|
+
| `hnsw` | `{ m?: number, efConstruction?: number }` | - | HNSW index tuning |
|
|
128
|
+
| `description` | `string` | - | Optional description |
|
|
95
129
|
|
|
96
|
-
|
|
130
|
+
##### Storage Modes
|
|
97
131
|
|
|
98
132
|
| Mode | Memory (768D) | Compression | Use Case |
|
|
99
133
|
|------|---------------|-------------|----------|
|
|
100
134
|
| `full` | 3 KB/vector | 1x | Default, max precision |
|
|
101
|
-
| `sq8` | 776 B/vector | **4x** |
|
|
102
|
-
| `binary` | 96 B/vector | **32x** | Edge, IoT |
|
|
135
|
+
| `sq8` | 776 B/vector | **4x** | Production scale, RAM-constrained |
|
|
136
|
+
| `binary` | 96 B/vector | **32x** | Edge devices, IoT |
|
|
103
137
|
|
|
104
138
|
```typescript
|
|
105
|
-
// Memory-optimized collection
|
|
106
139
|
await db.createCollection('embeddings', {
|
|
107
140
|
dimension: 768,
|
|
108
141
|
metric: 'cosine',
|
|
109
|
-
storageMode: 'sq8'
|
|
142
|
+
storageMode: 'sq8',
|
|
143
|
+
hnsw: { m: 16, efConstruction: 200 }
|
|
110
144
|
});
|
|
111
145
|
```
|
|
112
146
|
|
|
113
|
-
|
|
147
|
+
#### `db.createGraphCollection(name, config?)`
|
|
114
148
|
|
|
115
|
-
|
|
149
|
+
Create a dedicated graph collection for knowledge graph workloads.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
await db.createGraphCollection('social', {
|
|
153
|
+
dimension: 384, // optional: embed nodes for vector+graph queries
|
|
154
|
+
metric: 'cosine',
|
|
155
|
+
schemaMode: 'schemaless' // or 'strict'
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### `db.createMetadataCollection(name)`
|
|
160
|
+
|
|
161
|
+
Create a metadata-only collection (no vectors). Useful for reference tables that can be JOINed with vector collections via VelesQL.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
await db.createMetadataCollection('products');
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### `db.deleteCollection(name)`
|
|
168
|
+
|
|
169
|
+
Delete a collection and all its data.
|
|
170
|
+
|
|
171
|
+
#### `db.getCollection(name)`
|
|
172
|
+
|
|
173
|
+
Get collection info. Returns `null` if not found.
|
|
174
|
+
|
|
175
|
+
#### `db.listCollections()`
|
|
176
|
+
|
|
177
|
+
List all collections. Returns an array of `Collection` objects.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### Insert and Retrieve
|
|
182
|
+
|
|
183
|
+
#### `db.insert(collection, document)`
|
|
184
|
+
|
|
185
|
+
Insert a single vector document.
|
|
116
186
|
|
|
117
187
|
```typescript
|
|
118
188
|
await db.insert('docs', {
|
|
119
189
|
id: 'unique-id',
|
|
120
|
-
vector: [0.1, 0.2,
|
|
121
|
-
payload: { key: 'value' }
|
|
190
|
+
vector: [0.1, 0.2, 0.3], // number[] or Float32Array
|
|
191
|
+
payload: { key: 'value' }, // optional metadata
|
|
192
|
+
sparseVector: { 42: 0.8, 99: 0.3 } // optional sparse vector for hybrid search
|
|
122
193
|
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### `db.insertBatch(collection, documents)`
|
|
197
|
+
|
|
198
|
+
Insert multiple vectors in a single call. More efficient than repeated `insert()`.
|
|
123
199
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
200
|
+
```typescript
|
|
201
|
+
await db.insertBatch('docs', [
|
|
202
|
+
{ id: 'a', vector: vecA, payload: { title: 'First' } },
|
|
203
|
+
{ id: 'b', vector: vecB, payload: { title: 'Second' } },
|
|
204
|
+
]);
|
|
127
205
|
```
|
|
128
206
|
|
|
129
|
-
|
|
207
|
+
#### `db.streamInsert(collection, documents)`
|
|
130
208
|
|
|
131
|
-
Insert
|
|
209
|
+
Insert documents with server backpressure support. Sends documents sequentially, respecting 429 rate limits. Throws `BackpressureError` if the server pushes back.
|
|
132
210
|
|
|
133
|
-
|
|
211
|
+
```typescript
|
|
212
|
+
await db.streamInsert('docs', largeDocumentArray);
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### `db.get(collection, id)`
|
|
216
|
+
|
|
217
|
+
Get a document by ID. Returns `null` if not found.
|
|
218
|
+
|
|
219
|
+
#### `db.delete(collection, id)`
|
|
220
|
+
|
|
221
|
+
Delete a document by ID. Returns `true` if deleted, `false` if not found.
|
|
222
|
+
|
|
223
|
+
---
|
|
134
224
|
|
|
135
|
-
Search
|
|
225
|
+
### Search
|
|
226
|
+
|
|
227
|
+
#### `db.search(collection, query, options?)`
|
|
228
|
+
|
|
229
|
+
Vector similarity search.
|
|
136
230
|
|
|
137
231
|
| Option | Type | Default | Description |
|
|
138
232
|
|--------|------|---------|-------------|
|
|
139
233
|
| `k` | `number` | `10` | Number of results |
|
|
140
|
-
| `filter` | `object` | - |
|
|
234
|
+
| `filter` | `object` | - | Payload filter expression |
|
|
141
235
|
| `includeVectors` | `boolean` | `false` | Include vectors in results |
|
|
236
|
+
| `sparseVector` | `Record<number, number>` | - | Sparse vector for hybrid sparse+dense search |
|
|
142
237
|
|
|
143
|
-
|
|
238
|
+
```typescript
|
|
239
|
+
const results = await db.search('docs', queryVector, {
|
|
240
|
+
k: 10,
|
|
241
|
+
filter: { category: 'tech' },
|
|
242
|
+
includeVectors: true
|
|
243
|
+
});
|
|
244
|
+
// Returns: SearchResult[] = [{ id, score, payload?, vector? }, ...]
|
|
245
|
+
```
|
|
144
246
|
|
|
145
|
-
|
|
247
|
+
#### `db.searchBatch(collection, searches)`
|
|
146
248
|
|
|
147
|
-
|
|
249
|
+
Execute multiple search queries in parallel.
|
|
148
250
|
|
|
149
|
-
|
|
251
|
+
```typescript
|
|
252
|
+
const batchResults = await db.searchBatch('docs', [
|
|
253
|
+
{ vector: queryA, k: 5 },
|
|
254
|
+
{ vector: queryB, k: 10, filter: { type: 'article' } },
|
|
255
|
+
]);
|
|
256
|
+
// Returns: SearchResult[][] (one result array per query)
|
|
257
|
+
```
|
|
150
258
|
|
|
151
|
-
|
|
259
|
+
#### `db.searchIds(collection, query, options?)`
|
|
152
260
|
|
|
153
|
-
|
|
261
|
+
Lightweight search returning only IDs and scores (no payloads).
|
|
154
262
|
|
|
155
263
|
```typescript
|
|
156
|
-
const
|
|
264
|
+
const hits = await db.searchIds('docs', queryVector, { k: 100 });
|
|
265
|
+
// Returns: Array<{ id: number, score: number }>
|
|
157
266
|
```
|
|
158
267
|
|
|
159
|
-
|
|
268
|
+
#### `db.textSearch(collection, query, options?)`
|
|
160
269
|
|
|
161
|
-
|
|
270
|
+
Full-text search using BM25 scoring.
|
|
162
271
|
|
|
163
272
|
```typescript
|
|
164
|
-
const results = await db.
|
|
165
|
-
'docs',
|
|
166
|
-
queryVector,
|
|
167
|
-
'machine learning',
|
|
168
|
-
{ k: 10, vectorWeight: 0.7 } // 0.7 = 70% vector, 30% text
|
|
169
|
-
);
|
|
273
|
+
const results = await db.textSearch('docs', 'machine learning', { k: 10 });
|
|
170
274
|
```
|
|
171
275
|
|
|
172
|
-
|
|
276
|
+
#### `db.hybridSearch(collection, vector, textQuery, options?)`
|
|
173
277
|
|
|
174
|
-
|
|
278
|
+
Combined vector similarity + BM25 text search with RRF fusion.
|
|
175
279
|
|
|
176
280
|
```typescript
|
|
177
|
-
|
|
178
|
-
const results = await db.query(
|
|
179
|
-
'documents',
|
|
180
|
-
"SELECT * FROM documents WHERE category = 'tech' LIMIT 10"
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
// With vector parameter
|
|
184
|
-
const results = await db.query(
|
|
185
|
-
'documents',
|
|
186
|
-
"SELECT * FROM documents WHERE VECTOR NEAR $query LIMIT 5",
|
|
187
|
-
{ query: [0.1, 0.2, ...] }
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
// Hybrid query
|
|
191
|
-
const results = await db.query(
|
|
281
|
+
const results = await db.hybridSearch(
|
|
192
282
|
'docs',
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
// Aggregation query (returns { result, stats })
|
|
198
|
-
const agg = await db.query(
|
|
199
|
-
'documents',
|
|
200
|
-
"SELECT COUNT(*) AS total FROM documents"
|
|
283
|
+
queryVector,
|
|
284
|
+
'machine learning',
|
|
285
|
+
{ k: 10, vectorWeight: 0.7 } // 70% vector, 30% text
|
|
201
286
|
);
|
|
202
287
|
```
|
|
203
288
|
|
|
204
|
-
|
|
289
|
+
#### `db.multiQuerySearch(collection, vectors, options?)`
|
|
205
290
|
|
|
206
|
-
Multi-query fusion search for RAG pipelines using Multiple Query Generation (MQG).
|
|
291
|
+
Multi-query fusion search for RAG pipelines using Multiple Query Generation (MQG). Combines results from several query vectors into a single ranked list.
|
|
207
292
|
|
|
208
293
|
| Option | Type | Default | Description |
|
|
209
294
|
|--------|------|---------|-------------|
|
|
210
295
|
| `k` | `number` | `10` | Number of results |
|
|
211
296
|
| `fusion` | `'rrf' \| 'average' \| 'maximum' \| 'weighted'` | `'rrf'` | Fusion strategy |
|
|
212
297
|
| `fusionParams` | `object` | `{ k: 60 }` | Strategy-specific parameters |
|
|
213
|
-
| `filter` | `object` | - |
|
|
298
|
+
| `filter` | `object` | - | Payload filter expression |
|
|
214
299
|
|
|
215
300
|
```typescript
|
|
216
|
-
// RRF fusion (default)
|
|
301
|
+
// RRF fusion (default) -- best for most RAG use cases
|
|
217
302
|
const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
|
|
218
303
|
k: 10,
|
|
219
304
|
fusion: 'rrf',
|
|
220
305
|
fusionParams: { k: 60 }
|
|
221
306
|
});
|
|
222
307
|
|
|
223
|
-
// Weighted fusion
|
|
308
|
+
// Weighted fusion
|
|
224
309
|
const results = await db.multiQuerySearch('docs', [emb1, emb2], {
|
|
225
310
|
k: 10,
|
|
226
311
|
fusion: 'weighted',
|
|
227
312
|
fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
|
|
228
313
|
});
|
|
314
|
+
```
|
|
229
315
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
316
|
+
> **Note:** WASM supports `rrf`, `average`, `maximum`. The `weighted` strategy is REST-only.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
### Collection Utilities
|
|
321
|
+
|
|
322
|
+
#### `db.isEmpty(collection)`
|
|
323
|
+
|
|
324
|
+
Returns `true` if the collection contains no vectors.
|
|
325
|
+
|
|
326
|
+
#### `db.flush(collection)`
|
|
327
|
+
|
|
328
|
+
Flush pending changes to disk. **REST backend only** -- the WASM backend runs in-memory and this is a no-op.
|
|
329
|
+
|
|
330
|
+
#### `db.analyzeCollection(collection)`
|
|
331
|
+
|
|
332
|
+
Compute and return collection statistics.
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
const stats = await db.analyzeCollection('docs');
|
|
336
|
+
console.log(stats.totalPoints, stats.totalSizeBytes);
|
|
235
337
|
```
|
|
236
338
|
|
|
237
|
-
|
|
339
|
+
#### `db.getCollectionStats(collection)`
|
|
238
340
|
|
|
239
|
-
|
|
341
|
+
Get previously computed statistics. Returns `null` if the collection has not been analyzed yet.
|
|
240
342
|
|
|
241
|
-
|
|
343
|
+
#### `db.getCollectionConfig(collection)`
|
|
344
|
+
|
|
345
|
+
Get detailed collection configuration (dimension, metric, storage mode, point count, schema).
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
### VelesQL Queries
|
|
350
|
+
|
|
351
|
+
#### `db.query(collection, queryString, params?, options?)`
|
|
352
|
+
|
|
353
|
+
Execute a VelesQL query. Supports SELECT, WHERE, vector NEAR, GROUP BY, HAVING, ORDER BY, JOIN, UNION/INTERSECT/EXCEPT, and USING FUSION.
|
|
242
354
|
|
|
243
355
|
```typescript
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
356
|
+
// Vector similarity search
|
|
357
|
+
const result = await db.query(
|
|
358
|
+
'documents',
|
|
359
|
+
'SELECT * FROM documents WHERE VECTOR NEAR $query LIMIT 5',
|
|
360
|
+
{ query: [0.1, 0.2, 0.3] }
|
|
361
|
+
);
|
|
362
|
+
|
|
363
|
+
// Aggregation
|
|
364
|
+
const agg = await db.query(
|
|
365
|
+
'products',
|
|
366
|
+
`SELECT category, COUNT(*), AVG(price)
|
|
367
|
+
FROM products
|
|
368
|
+
GROUP BY category
|
|
369
|
+
HAVING COUNT(*) > 5`
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// Hybrid vector + text
|
|
373
|
+
const hybrid = await db.query(
|
|
374
|
+
'docs',
|
|
375
|
+
"SELECT * FROM docs WHERE VECTOR NEAR $v AND content MATCH 'rust' LIMIT 10",
|
|
376
|
+
{ v: queryVector }
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
// Cross-collection JOIN
|
|
380
|
+
const joined = await db.query(
|
|
381
|
+
'orders',
|
|
382
|
+
`SELECT * FROM orders
|
|
383
|
+
JOIN customers AS c ON orders.customer_id = c.id
|
|
384
|
+
WHERE status = $status`,
|
|
385
|
+
{ status: 'active' }
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
// Set operations
|
|
389
|
+
const combined = await db.query('users',
|
|
390
|
+
'SELECT * FROM active_users UNION SELECT * FROM archived_users'
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
// Fusion strategy
|
|
394
|
+
const fused = await db.query('docs',
|
|
395
|
+
"SELECT * FROM docs USING FUSION(strategy = 'rrf', k = 60) LIMIT 20"
|
|
396
|
+
);
|
|
248
397
|
```
|
|
249
398
|
|
|
250
|
-
|
|
399
|
+
Query options:
|
|
400
|
+
|
|
401
|
+
| Option | Type | Default | Description |
|
|
402
|
+
|--------|------|---------|-------------|
|
|
403
|
+
| `timeoutMs` | `number` | `30000` | Query timeout in milliseconds |
|
|
404
|
+
| `stream` | `boolean` | `false` | Enable streaming response |
|
|
405
|
+
|
|
406
|
+
#### `db.queryExplain(queryString, params?)`
|
|
251
407
|
|
|
252
|
-
|
|
408
|
+
Get the execution plan for a VelesQL query without running it. Returns plan steps, estimated cost, index usage, and detected features.
|
|
253
409
|
|
|
254
410
|
```typescript
|
|
255
|
-
await db.
|
|
411
|
+
const plan = await db.queryExplain(
|
|
412
|
+
'SELECT * FROM docs WHERE VECTOR NEAR $v LIMIT 10',
|
|
413
|
+
{ v: queryVector }
|
|
414
|
+
);
|
|
415
|
+
console.log(plan.plan); // step-by-step execution plan
|
|
416
|
+
console.log(plan.estimatedCost); // { usesIndex, selectivity, complexity }
|
|
417
|
+
console.log(plan.features); // { hasVectorSearch, hasFilter, hasJoin, ... }
|
|
256
418
|
```
|
|
257
419
|
|
|
258
|
-
|
|
420
|
+
#### `db.collectionSanity(collection)`
|
|
259
421
|
|
|
260
|
-
|
|
422
|
+
Run diagnostic checks on a collection (dimensions, search readiness, error counts, hints).
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
const report = await db.collectionSanity('docs');
|
|
426
|
+
console.log(report.checks); // { hasVectors, searchReady, dimensionConfigured }
|
|
427
|
+
console.log(report.diagnostics); // { searchRequestsTotal, dimensionMismatchTotal, ... }
|
|
428
|
+
console.log(report.hints); // actionable suggestions
|
|
429
|
+
```
|
|
261
430
|
|
|
262
|
-
|
|
431
|
+
---
|
|
263
432
|
|
|
264
|
-
|
|
433
|
+
### VelesQL Query Builder
|
|
265
434
|
|
|
266
|
-
|
|
435
|
+
Build type-safe VelesQL queries with a fluent API instead of raw strings.
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
import { velesql } from '@wiscale/velesdb-sdk';
|
|
439
|
+
|
|
440
|
+
// Vector similarity with filters
|
|
441
|
+
const builder = velesql()
|
|
442
|
+
.match('d', 'Document')
|
|
443
|
+
.nearVector('$queryVector', queryVector)
|
|
444
|
+
.andWhere('d.category = $cat', { cat: 'tech' })
|
|
445
|
+
.orderBy('similarity()', 'DESC')
|
|
446
|
+
.limit(10);
|
|
447
|
+
|
|
448
|
+
const queryString = builder.toVelesQL();
|
|
449
|
+
const params = builder.getParams();
|
|
450
|
+
const results = await db.query('documents', queryString, params);
|
|
451
|
+
|
|
452
|
+
// Graph traversal with relationships
|
|
453
|
+
const graphQuery = velesql()
|
|
454
|
+
.match('p', 'Person')
|
|
455
|
+
.rel('KNOWS')
|
|
456
|
+
.to('f', 'Person')
|
|
457
|
+
.where('p.age > 25')
|
|
458
|
+
.return(['p.name', 'f.name'])
|
|
459
|
+
.toVelesQL();
|
|
460
|
+
// => "MATCH (p:Person)-[:KNOWS]->(f:Person) WHERE p.age > 25 RETURN p.name, f.name"
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Builder methods: `match()`, `rel()`, `to()`, `where()`, `andWhere()`, `orWhere()`, `nearVector()`, `limit()`, `offset()`, `orderBy()`, `return()`, `returnAll()`, `fusion()`.
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
### Knowledge Graph API
|
|
468
|
+
|
|
469
|
+
#### `db.addEdge(collection, edge)`
|
|
470
|
+
|
|
471
|
+
Add a directed edge between two nodes.
|
|
267
472
|
|
|
268
473
|
```typescript
|
|
269
474
|
await db.addEdge('social', {
|
|
270
|
-
id: 1,
|
|
475
|
+
id: 1,
|
|
476
|
+
source: 100,
|
|
477
|
+
target: 200,
|
|
271
478
|
label: 'FOLLOWS',
|
|
272
479
|
properties: { since: '2024-01-01' }
|
|
273
480
|
});
|
|
274
481
|
```
|
|
275
482
|
|
|
276
|
-
|
|
483
|
+
#### `db.getEdges(collection, options?)`
|
|
484
|
+
|
|
485
|
+
Query edges, optionally filtered by label.
|
|
277
486
|
|
|
278
487
|
```typescript
|
|
279
488
|
const edges = await db.getEdges('social', { label: 'FOLLOWS' });
|
|
280
489
|
```
|
|
281
490
|
|
|
282
|
-
|
|
491
|
+
#### `db.traverseGraph(collection, request)`
|
|
492
|
+
|
|
493
|
+
Traverse the graph using BFS or DFS from a source node.
|
|
283
494
|
|
|
284
495
|
```typescript
|
|
285
496
|
const result = await db.traverseGraph('social', {
|
|
286
|
-
source: 100,
|
|
497
|
+
source: 100,
|
|
498
|
+
strategy: 'bfs',
|
|
499
|
+
maxDepth: 3,
|
|
500
|
+
limit: 100,
|
|
501
|
+
relTypes: ['FOLLOWS', 'KNOWS']
|
|
287
502
|
});
|
|
503
|
+
|
|
504
|
+
for (const node of result.results) {
|
|
505
|
+
console.log(`Node ${node.targetId} at depth ${node.depth}`);
|
|
506
|
+
}
|
|
288
507
|
```
|
|
289
508
|
|
|
290
|
-
|
|
509
|
+
#### `db.getNodeDegree(collection, nodeId)`
|
|
510
|
+
|
|
511
|
+
Get the in-degree and out-degree of a node.
|
|
291
512
|
|
|
292
513
|
```typescript
|
|
293
514
|
const degree = await db.getNodeDegree('social', 100);
|
|
515
|
+
console.log(`In: ${degree.inDegree}, Out: ${degree.outDegree}`);
|
|
294
516
|
```
|
|
295
517
|
|
|
296
|
-
|
|
518
|
+
---
|
|
297
519
|
|
|
298
|
-
|
|
520
|
+
### Property Indexes
|
|
299
521
|
|
|
300
|
-
|
|
522
|
+
Create secondary indexes for fast lookups on payload fields.
|
|
301
523
|
|
|
302
|
-
|
|
303
|
-
// Group by with aggregates
|
|
304
|
-
const result = await db.query('products', `
|
|
305
|
-
SELECT category, COUNT(*), AVG(price)
|
|
306
|
-
FROM products
|
|
307
|
-
GROUP BY category
|
|
308
|
-
HAVING COUNT(*) > 5 AND AVG(price) > 50
|
|
309
|
-
`);
|
|
524
|
+
#### `db.createIndex(collection, options)`
|
|
310
525
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
526
|
+
```typescript
|
|
527
|
+
// Hash index for O(1) equality lookups
|
|
528
|
+
await db.createIndex('users', { label: 'Person', property: 'email' });
|
|
529
|
+
|
|
530
|
+
// Range index for O(log n) range queries
|
|
531
|
+
await db.createIndex('events', {
|
|
532
|
+
label: 'Event',
|
|
533
|
+
property: 'timestamp',
|
|
534
|
+
indexType: 'range'
|
|
535
|
+
});
|
|
315
536
|
```
|
|
316
537
|
|
|
317
|
-
|
|
538
|
+
#### `db.listIndexes(collection)`
|
|
318
539
|
|
|
319
540
|
```typescript
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
SELECT * FROM docs
|
|
323
|
-
ORDER BY similarity(vector, $v) DESC
|
|
324
|
-
LIMIT 10
|
|
325
|
-
`, { v: queryVector });
|
|
541
|
+
const indexes = await db.listIndexes('users');
|
|
542
|
+
// [{ label, property, indexType, cardinality, memoryBytes }, ...]
|
|
326
543
|
```
|
|
327
544
|
|
|
328
|
-
|
|
545
|
+
#### `db.hasIndex(collection, label, property)`
|
|
546
|
+
|
|
547
|
+
Returns `true` if the specified index exists.
|
|
548
|
+
|
|
549
|
+
#### `db.dropIndex(collection, label, property)`
|
|
550
|
+
|
|
551
|
+
Drop an index. Returns `true` if the index existed and was removed.
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
### Product Quantization
|
|
556
|
+
|
|
557
|
+
#### `db.trainPq(collection, options?)`
|
|
558
|
+
|
|
559
|
+
Train Product Quantization on a collection for further memory compression beyond SQ8. **REST backend only** -- delegates to velesdb-server; not available in the WASM backend.
|
|
329
560
|
|
|
330
561
|
```typescript
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
`, { status: 'active' });
|
|
562
|
+
const result = await db.trainPq('embeddings', {
|
|
563
|
+
m: 8, // number of subquantizers
|
|
564
|
+
k: 256, // centroids per subquantizer
|
|
565
|
+
opq: true // enable Optimized PQ
|
|
566
|
+
});
|
|
337
567
|
```
|
|
338
568
|
|
|
339
|
-
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
### Agent Memory API
|
|
572
|
+
|
|
573
|
+
The Agent Memory API provides three memory types for AI agents, built on top of VelesDB's vector and graph storage.
|
|
340
574
|
|
|
341
575
|
```typescript
|
|
342
|
-
|
|
343
|
-
const result = await db.query('users', `
|
|
344
|
-
SELECT * FROM active_users
|
|
345
|
-
UNION
|
|
346
|
-
SELECT * FROM archived_users
|
|
347
|
-
`);
|
|
576
|
+
import { VelesDB } from '@wiscale/velesdb-sdk';
|
|
348
577
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
SELECT id FROM active_users
|
|
354
|
-
`);
|
|
578
|
+
const db = new VelesDB({ backend: 'rest', url: 'http://localhost:8080' });
|
|
579
|
+
await db.init();
|
|
580
|
+
|
|
581
|
+
const memory = db.agentMemory({ dimension: 384 });
|
|
355
582
|
```
|
|
356
583
|
|
|
357
|
-
|
|
584
|
+
#### Semantic Memory (facts and knowledge)
|
|
358
585
|
|
|
359
586
|
```typescript
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
587
|
+
// Store a fact
|
|
588
|
+
await memory.storeFact('knowledge', {
|
|
589
|
+
id: 1,
|
|
590
|
+
text: 'VelesDB uses HNSW for vector indexing',
|
|
591
|
+
embedding: factEmbedding,
|
|
592
|
+
metadata: { source: 'docs', confidence: 0.95 }
|
|
593
|
+
});
|
|
366
594
|
|
|
367
|
-
//
|
|
368
|
-
const
|
|
369
|
-
SELECT * FROM docs
|
|
370
|
-
USING FUSION(strategy = 'weighted', vector_weight = 0.7, graph_weight = 0.3)
|
|
371
|
-
LIMIT 20
|
|
372
|
-
`);
|
|
595
|
+
// Recall similar facts
|
|
596
|
+
const facts = await memory.searchFacts('knowledge', queryEmbedding, 5);
|
|
373
597
|
```
|
|
374
598
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
Build type-safe VelesQL queries with the fluent builder API.
|
|
599
|
+
#### Episodic Memory (events and experiences)
|
|
378
600
|
|
|
379
601
|
```typescript
|
|
380
|
-
|
|
602
|
+
// Record an event
|
|
603
|
+
await memory.recordEvent('events', {
|
|
604
|
+
eventType: 'user_query',
|
|
605
|
+
data: { query: 'How does HNSW work?', response: '...' },
|
|
606
|
+
embedding: eventEmbedding,
|
|
607
|
+
metadata: { timestamp: Date.now() }
|
|
608
|
+
});
|
|
381
609
|
|
|
382
|
-
//
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
.nearVector('$queryVector', queryVector)
|
|
386
|
-
.andWhere('d.category = $cat', { cat: 'tech' })
|
|
387
|
-
.limit(10);
|
|
610
|
+
// Recall similar events
|
|
611
|
+
const events = await memory.recallEvents('events', queryEmbedding, 5);
|
|
612
|
+
```
|
|
388
613
|
|
|
389
|
-
|
|
390
|
-
const params = builder.getParams();
|
|
391
|
-
const results = await db.query('documents', queryString, params);
|
|
614
|
+
#### Procedural Memory (learned patterns)
|
|
392
615
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
.
|
|
399
|
-
|
|
400
|
-
|
|
616
|
+
```typescript
|
|
617
|
+
// Store a procedure
|
|
618
|
+
await memory.learnProcedure('procedures', {
|
|
619
|
+
name: 'deploy-to-prod',
|
|
620
|
+
steps: ['Run tests', 'Build artifacts', 'Push to registry', 'Deploy'],
|
|
621
|
+
metadata: { lastUsed: Date.now() }
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
// Find matching procedures
|
|
625
|
+
const procs = await memory.recallProcedures('procedures', queryEmbedding, 3);
|
|
401
626
|
```
|
|
402
627
|
|
|
628
|
+
---
|
|
629
|
+
|
|
403
630
|
## Error Handling
|
|
404
631
|
|
|
632
|
+
All error classes extend `VelesDBError` and include a `code` property for programmatic handling.
|
|
633
|
+
|
|
405
634
|
```typescript
|
|
406
|
-
import {
|
|
635
|
+
import {
|
|
636
|
+
VelesDBError,
|
|
637
|
+
ValidationError,
|
|
638
|
+
ConnectionError,
|
|
639
|
+
NotFoundError,
|
|
640
|
+
BackpressureError
|
|
641
|
+
} from '@wiscale/velesdb-sdk';
|
|
407
642
|
|
|
408
643
|
try {
|
|
409
|
-
await db.search('nonexistent',
|
|
644
|
+
await db.search('nonexistent', queryVector);
|
|
410
645
|
} catch (error) {
|
|
411
646
|
if (error instanceof NotFoundError) {
|
|
412
647
|
console.log('Collection not found');
|
|
413
648
|
} else if (error instanceof ValidationError) {
|
|
414
649
|
console.log('Invalid input:', error.message);
|
|
415
650
|
} else if (error instanceof ConnectionError) {
|
|
416
|
-
console.log('
|
|
651
|
+
console.log('Server unreachable:', error.message);
|
|
652
|
+
} else if (error instanceof BackpressureError) {
|
|
653
|
+
console.log('Server overloaded, retry later');
|
|
417
654
|
}
|
|
418
655
|
}
|
|
419
656
|
```
|
|
420
657
|
|
|
658
|
+
## Exports
|
|
659
|
+
|
|
660
|
+
Everything is importable from the package root:
|
|
661
|
+
|
|
662
|
+
```typescript
|
|
663
|
+
import {
|
|
664
|
+
// Client
|
|
665
|
+
VelesDB,
|
|
666
|
+
AgentMemoryClient,
|
|
667
|
+
|
|
668
|
+
// Backends (advanced: use VelesDB client instead)
|
|
669
|
+
WasmBackend,
|
|
670
|
+
RestBackend,
|
|
671
|
+
|
|
672
|
+
// Query builder
|
|
673
|
+
VelesQLBuilder,
|
|
674
|
+
velesql,
|
|
675
|
+
|
|
676
|
+
// Error classes
|
|
677
|
+
VelesDBError,
|
|
678
|
+
ValidationError,
|
|
679
|
+
ConnectionError,
|
|
680
|
+
NotFoundError,
|
|
681
|
+
BackpressureError,
|
|
682
|
+
|
|
683
|
+
// Types (selected)
|
|
684
|
+
type VelesDBConfig,
|
|
685
|
+
type CollectionConfig,
|
|
686
|
+
type VectorDocument,
|
|
687
|
+
type SearchOptions,
|
|
688
|
+
type SearchResult,
|
|
689
|
+
type SparseVector,
|
|
690
|
+
type MultiQuerySearchOptions,
|
|
691
|
+
type GraphEdge,
|
|
692
|
+
type AddEdgeRequest,
|
|
693
|
+
type TraverseRequest,
|
|
694
|
+
type TraverseResponse,
|
|
695
|
+
type QueryApiResponse,
|
|
696
|
+
type AgentMemoryConfig,
|
|
697
|
+
type SemanticEntry,
|
|
698
|
+
type EpisodicEvent,
|
|
699
|
+
type ProceduralPattern,
|
|
700
|
+
} from '@wiscale/velesdb-sdk';
|
|
701
|
+
```
|
|
702
|
+
|
|
421
703
|
## Performance Tips
|
|
422
704
|
|
|
423
|
-
1. **Use
|
|
424
|
-
2. **Reuse Float32Array
|
|
425
|
-
3. **Use WASM backend** for browser apps (
|
|
426
|
-
4. **
|
|
705
|
+
1. **Use `insertBatch()`** instead of repeated `insert()` calls
|
|
706
|
+
2. **Reuse `Float32Array`** buffers for query vectors when possible
|
|
707
|
+
3. **Use WASM backend** for browser apps (zero network latency)
|
|
708
|
+
4. **Use `searchIds()`** when you only need IDs and scores (skips payload transfer)
|
|
709
|
+
5. **Use `streamInsert()`** for high-throughput ingestion with backpressure handling
|
|
710
|
+
6. **Pre-initialize** the client at app startup (`await db.init()`)
|
|
711
|
+
7. **Tune HNSW** with `hnsw: { m: 16, efConstruction: 200 }` for higher recall
|
|
427
712
|
|
|
428
713
|
## License
|
|
429
714
|
|
|
430
|
-
MIT License
|
|
715
|
+
MIT License -- See [LICENSE](./LICENSE) for details.
|
|
431
716
|
|
|
432
|
-
VelesDB Core
|
|
717
|
+
VelesDB Core and Server are licensed under VelesDB Core License 1.0 (source-available).
|