@wiscale/velesdb-sdk 0.8.4 → 0.8.9
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 +44 -0
- package/dist/index.d.mts +95 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.js +177 -0
- package/dist/index.mjs +177 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -144,6 +144,50 @@ Delete a vector by ID. Returns `true` if deleted.
|
|
|
144
144
|
|
|
145
145
|
Get a vector by ID. Returns `null` if not found.
|
|
146
146
|
|
|
147
|
+
### `db.textSearch(collection, query, options)` (v0.8.5+)
|
|
148
|
+
|
|
149
|
+
Full-text search using BM25 algorithm.
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const results = await db.textSearch('docs', 'machine learning', { k: 10 });
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### `db.hybridSearch(collection, vector, textQuery, options)` (v0.8.5+)
|
|
156
|
+
|
|
157
|
+
Combined vector + text search with RRF fusion.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const results = await db.hybridSearch(
|
|
161
|
+
'docs',
|
|
162
|
+
queryVector,
|
|
163
|
+
'machine learning',
|
|
164
|
+
{ k: 10, vectorWeight: 0.7 } // 0.7 = 70% vector, 30% text
|
|
165
|
+
);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `db.query(queryString, params)` (v0.8.5+)
|
|
169
|
+
|
|
170
|
+
Execute a VelesQL query.
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
// Simple query
|
|
174
|
+
const results = await db.query(
|
|
175
|
+
"SELECT * FROM documents WHERE category = 'tech' LIMIT 10"
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// With vector parameter
|
|
179
|
+
const results = await db.query(
|
|
180
|
+
"SELECT * FROM documents WHERE VECTOR NEAR $query LIMIT 5",
|
|
181
|
+
{ query: [0.1, 0.2, ...] }
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
// Hybrid query
|
|
185
|
+
const results = await db.query(
|
|
186
|
+
"SELECT * FROM docs WHERE VECTOR NEAR $v AND content MATCH 'rust' LIMIT 10",
|
|
187
|
+
{ v: queryVector }
|
|
188
|
+
);
|
|
189
|
+
```
|
|
190
|
+
|
|
147
191
|
### `db.close()`
|
|
148
192
|
|
|
149
193
|
Close the client and release resources.
|
package/dist/index.d.mts
CHANGED
|
@@ -102,6 +102,25 @@ interface IVelesDBBackend {
|
|
|
102
102
|
delete(collection: string, id: string | number): Promise<boolean>;
|
|
103
103
|
/** Get a vector by ID */
|
|
104
104
|
get(collection: string, id: string | number): Promise<VectorDocument | null>;
|
|
105
|
+
/** Search for multiple vectors in batch */
|
|
106
|
+
searchBatch(collection: string, searches: Array<{
|
|
107
|
+
vector: number[] | Float32Array;
|
|
108
|
+
k?: number;
|
|
109
|
+
filter?: Record<string, unknown>;
|
|
110
|
+
}>): Promise<SearchResult[][]>;
|
|
111
|
+
/** Full-text search using BM25 */
|
|
112
|
+
textSearch(collection: string, query: string, options?: {
|
|
113
|
+
k?: number;
|
|
114
|
+
filter?: Record<string, unknown>;
|
|
115
|
+
}): Promise<SearchResult[]>;
|
|
116
|
+
/** Hybrid search combining vector and text */
|
|
117
|
+
hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
|
|
118
|
+
k?: number;
|
|
119
|
+
vectorWeight?: number;
|
|
120
|
+
filter?: Record<string, unknown>;
|
|
121
|
+
}): Promise<SearchResult[]>;
|
|
122
|
+
/** Execute VelesQL query */
|
|
123
|
+
query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
105
124
|
/** Close/cleanup the backend */
|
|
106
125
|
close(): Promise<void>;
|
|
107
126
|
}
|
|
@@ -215,6 +234,18 @@ declare class VelesDB {
|
|
|
215
234
|
* @returns Search results sorted by relevance
|
|
216
235
|
*/
|
|
217
236
|
search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
|
|
237
|
+
/**
|
|
238
|
+
* Search for multiple vectors in parallel
|
|
239
|
+
*
|
|
240
|
+
* @param collection - Collection name
|
|
241
|
+
* @param searches - List of search queries
|
|
242
|
+
* @returns List of search results for each query
|
|
243
|
+
*/
|
|
244
|
+
searchBatch(collection: string, searches: Array<{
|
|
245
|
+
vector: number[] | Float32Array;
|
|
246
|
+
k?: number;
|
|
247
|
+
filter?: Record<string, unknown>;
|
|
248
|
+
}>): Promise<SearchResult[][]>;
|
|
218
249
|
/**
|
|
219
250
|
* Delete a vector by ID
|
|
220
251
|
*
|
|
@@ -231,6 +262,40 @@ declare class VelesDB {
|
|
|
231
262
|
* @returns Document or null if not found
|
|
232
263
|
*/
|
|
233
264
|
get(collection: string, id: string | number): Promise<VectorDocument | null>;
|
|
265
|
+
/**
|
|
266
|
+
* Perform full-text search using BM25
|
|
267
|
+
*
|
|
268
|
+
* @param collection - Collection name
|
|
269
|
+
* @param query - Text query
|
|
270
|
+
* @param options - Search options (k, filter)
|
|
271
|
+
* @returns Search results sorted by BM25 score
|
|
272
|
+
*/
|
|
273
|
+
textSearch(collection: string, query: string, options?: {
|
|
274
|
+
k?: number;
|
|
275
|
+
filter?: Record<string, unknown>;
|
|
276
|
+
}): Promise<SearchResult[]>;
|
|
277
|
+
/**
|
|
278
|
+
* Perform hybrid search combining vector similarity and BM25 text search
|
|
279
|
+
*
|
|
280
|
+
* @param collection - Collection name
|
|
281
|
+
* @param vector - Query vector
|
|
282
|
+
* @param textQuery - Text query for BM25
|
|
283
|
+
* @param options - Search options (k, vectorWeight, filter)
|
|
284
|
+
* @returns Search results sorted by fused score
|
|
285
|
+
*/
|
|
286
|
+
hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
|
|
287
|
+
k?: number;
|
|
288
|
+
vectorWeight?: number;
|
|
289
|
+
filter?: Record<string, unknown>;
|
|
290
|
+
}): Promise<SearchResult[]>;
|
|
291
|
+
/**
|
|
292
|
+
* Execute a VelesQL query
|
|
293
|
+
*
|
|
294
|
+
* @param queryString - VelesQL query string
|
|
295
|
+
* @param params - Optional query parameters
|
|
296
|
+
* @returns Query results
|
|
297
|
+
*/
|
|
298
|
+
query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
234
299
|
/**
|
|
235
300
|
* Close the client and release resources
|
|
236
301
|
*/
|
|
@@ -267,8 +332,23 @@ declare class WasmBackend implements IVelesDBBackend {
|
|
|
267
332
|
insert(collectionName: string, doc: VectorDocument): Promise<void>;
|
|
268
333
|
insertBatch(collectionName: string, docs: VectorDocument[]): Promise<void>;
|
|
269
334
|
search(collectionName: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
|
|
335
|
+
searchBatch(collectionName: string, searches: Array<{
|
|
336
|
+
vector: number[] | Float32Array;
|
|
337
|
+
k?: number;
|
|
338
|
+
filter?: Record<string, unknown>;
|
|
339
|
+
}>): Promise<SearchResult[][]>;
|
|
270
340
|
delete(collectionName: string, id: string | number): Promise<boolean>;
|
|
271
341
|
get(collectionName: string, id: string | number): Promise<VectorDocument | null>;
|
|
342
|
+
textSearch(_collection: string, _query: string, _options?: {
|
|
343
|
+
k?: number;
|
|
344
|
+
filter?: Record<string, unknown>;
|
|
345
|
+
}): Promise<SearchResult[]>;
|
|
346
|
+
hybridSearch(_collection: string, _vector: number[] | Float32Array, _textQuery: string, _options?: {
|
|
347
|
+
k?: number;
|
|
348
|
+
vectorWeight?: number;
|
|
349
|
+
filter?: Record<string, unknown>;
|
|
350
|
+
}): Promise<SearchResult[]>;
|
|
351
|
+
query(_queryString: string, _params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
272
352
|
close(): Promise<void>;
|
|
273
353
|
private toNumericId;
|
|
274
354
|
}
|
|
@@ -301,8 +381,23 @@ declare class RestBackend implements IVelesDBBackend {
|
|
|
301
381
|
insert(collection: string, doc: VectorDocument): Promise<void>;
|
|
302
382
|
insertBatch(collection: string, docs: VectorDocument[]): Promise<void>;
|
|
303
383
|
search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
|
|
384
|
+
searchBatch(collection: string, searches: Array<{
|
|
385
|
+
vector: number[] | Float32Array;
|
|
386
|
+
k?: number;
|
|
387
|
+
filter?: Record<string, unknown>;
|
|
388
|
+
}>): Promise<SearchResult[][]>;
|
|
304
389
|
delete(collection: string, id: string | number): Promise<boolean>;
|
|
305
390
|
get(collection: string, id: string | number): Promise<VectorDocument | null>;
|
|
391
|
+
textSearch(collection: string, query: string, options?: {
|
|
392
|
+
k?: number;
|
|
393
|
+
filter?: Record<string, unknown>;
|
|
394
|
+
}): Promise<SearchResult[]>;
|
|
395
|
+
hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
|
|
396
|
+
k?: number;
|
|
397
|
+
vectorWeight?: number;
|
|
398
|
+
filter?: Record<string, unknown>;
|
|
399
|
+
}): Promise<SearchResult[]>;
|
|
400
|
+
query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
306
401
|
close(): Promise<void>;
|
|
307
402
|
}
|
|
308
403
|
|
package/dist/index.d.ts
CHANGED
|
@@ -102,6 +102,25 @@ interface IVelesDBBackend {
|
|
|
102
102
|
delete(collection: string, id: string | number): Promise<boolean>;
|
|
103
103
|
/** Get a vector by ID */
|
|
104
104
|
get(collection: string, id: string | number): Promise<VectorDocument | null>;
|
|
105
|
+
/** Search for multiple vectors in batch */
|
|
106
|
+
searchBatch(collection: string, searches: Array<{
|
|
107
|
+
vector: number[] | Float32Array;
|
|
108
|
+
k?: number;
|
|
109
|
+
filter?: Record<string, unknown>;
|
|
110
|
+
}>): Promise<SearchResult[][]>;
|
|
111
|
+
/** Full-text search using BM25 */
|
|
112
|
+
textSearch(collection: string, query: string, options?: {
|
|
113
|
+
k?: number;
|
|
114
|
+
filter?: Record<string, unknown>;
|
|
115
|
+
}): Promise<SearchResult[]>;
|
|
116
|
+
/** Hybrid search combining vector and text */
|
|
117
|
+
hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
|
|
118
|
+
k?: number;
|
|
119
|
+
vectorWeight?: number;
|
|
120
|
+
filter?: Record<string, unknown>;
|
|
121
|
+
}): Promise<SearchResult[]>;
|
|
122
|
+
/** Execute VelesQL query */
|
|
123
|
+
query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
105
124
|
/** Close/cleanup the backend */
|
|
106
125
|
close(): Promise<void>;
|
|
107
126
|
}
|
|
@@ -215,6 +234,18 @@ declare class VelesDB {
|
|
|
215
234
|
* @returns Search results sorted by relevance
|
|
216
235
|
*/
|
|
217
236
|
search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
|
|
237
|
+
/**
|
|
238
|
+
* Search for multiple vectors in parallel
|
|
239
|
+
*
|
|
240
|
+
* @param collection - Collection name
|
|
241
|
+
* @param searches - List of search queries
|
|
242
|
+
* @returns List of search results for each query
|
|
243
|
+
*/
|
|
244
|
+
searchBatch(collection: string, searches: Array<{
|
|
245
|
+
vector: number[] | Float32Array;
|
|
246
|
+
k?: number;
|
|
247
|
+
filter?: Record<string, unknown>;
|
|
248
|
+
}>): Promise<SearchResult[][]>;
|
|
218
249
|
/**
|
|
219
250
|
* Delete a vector by ID
|
|
220
251
|
*
|
|
@@ -231,6 +262,40 @@ declare class VelesDB {
|
|
|
231
262
|
* @returns Document or null if not found
|
|
232
263
|
*/
|
|
233
264
|
get(collection: string, id: string | number): Promise<VectorDocument | null>;
|
|
265
|
+
/**
|
|
266
|
+
* Perform full-text search using BM25
|
|
267
|
+
*
|
|
268
|
+
* @param collection - Collection name
|
|
269
|
+
* @param query - Text query
|
|
270
|
+
* @param options - Search options (k, filter)
|
|
271
|
+
* @returns Search results sorted by BM25 score
|
|
272
|
+
*/
|
|
273
|
+
textSearch(collection: string, query: string, options?: {
|
|
274
|
+
k?: number;
|
|
275
|
+
filter?: Record<string, unknown>;
|
|
276
|
+
}): Promise<SearchResult[]>;
|
|
277
|
+
/**
|
|
278
|
+
* Perform hybrid search combining vector similarity and BM25 text search
|
|
279
|
+
*
|
|
280
|
+
* @param collection - Collection name
|
|
281
|
+
* @param vector - Query vector
|
|
282
|
+
* @param textQuery - Text query for BM25
|
|
283
|
+
* @param options - Search options (k, vectorWeight, filter)
|
|
284
|
+
* @returns Search results sorted by fused score
|
|
285
|
+
*/
|
|
286
|
+
hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
|
|
287
|
+
k?: number;
|
|
288
|
+
vectorWeight?: number;
|
|
289
|
+
filter?: Record<string, unknown>;
|
|
290
|
+
}): Promise<SearchResult[]>;
|
|
291
|
+
/**
|
|
292
|
+
* Execute a VelesQL query
|
|
293
|
+
*
|
|
294
|
+
* @param queryString - VelesQL query string
|
|
295
|
+
* @param params - Optional query parameters
|
|
296
|
+
* @returns Query results
|
|
297
|
+
*/
|
|
298
|
+
query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
234
299
|
/**
|
|
235
300
|
* Close the client and release resources
|
|
236
301
|
*/
|
|
@@ -267,8 +332,23 @@ declare class WasmBackend implements IVelesDBBackend {
|
|
|
267
332
|
insert(collectionName: string, doc: VectorDocument): Promise<void>;
|
|
268
333
|
insertBatch(collectionName: string, docs: VectorDocument[]): Promise<void>;
|
|
269
334
|
search(collectionName: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
|
|
335
|
+
searchBatch(collectionName: string, searches: Array<{
|
|
336
|
+
vector: number[] | Float32Array;
|
|
337
|
+
k?: number;
|
|
338
|
+
filter?: Record<string, unknown>;
|
|
339
|
+
}>): Promise<SearchResult[][]>;
|
|
270
340
|
delete(collectionName: string, id: string | number): Promise<boolean>;
|
|
271
341
|
get(collectionName: string, id: string | number): Promise<VectorDocument | null>;
|
|
342
|
+
textSearch(_collection: string, _query: string, _options?: {
|
|
343
|
+
k?: number;
|
|
344
|
+
filter?: Record<string, unknown>;
|
|
345
|
+
}): Promise<SearchResult[]>;
|
|
346
|
+
hybridSearch(_collection: string, _vector: number[] | Float32Array, _textQuery: string, _options?: {
|
|
347
|
+
k?: number;
|
|
348
|
+
vectorWeight?: number;
|
|
349
|
+
filter?: Record<string, unknown>;
|
|
350
|
+
}): Promise<SearchResult[]>;
|
|
351
|
+
query(_queryString: string, _params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
272
352
|
close(): Promise<void>;
|
|
273
353
|
private toNumericId;
|
|
274
354
|
}
|
|
@@ -301,8 +381,23 @@ declare class RestBackend implements IVelesDBBackend {
|
|
|
301
381
|
insert(collection: string, doc: VectorDocument): Promise<void>;
|
|
302
382
|
insertBatch(collection: string, docs: VectorDocument[]): Promise<void>;
|
|
303
383
|
search(collection: string, query: number[] | Float32Array, options?: SearchOptions): Promise<SearchResult[]>;
|
|
384
|
+
searchBatch(collection: string, searches: Array<{
|
|
385
|
+
vector: number[] | Float32Array;
|
|
386
|
+
k?: number;
|
|
387
|
+
filter?: Record<string, unknown>;
|
|
388
|
+
}>): Promise<SearchResult[][]>;
|
|
304
389
|
delete(collection: string, id: string | number): Promise<boolean>;
|
|
305
390
|
get(collection: string, id: string | number): Promise<VectorDocument | null>;
|
|
391
|
+
textSearch(collection: string, query: string, options?: {
|
|
392
|
+
k?: number;
|
|
393
|
+
filter?: Record<string, unknown>;
|
|
394
|
+
}): Promise<SearchResult[]>;
|
|
395
|
+
hybridSearch(collection: string, vector: number[] | Float32Array, textQuery: string, options?: {
|
|
396
|
+
k?: number;
|
|
397
|
+
vectorWeight?: number;
|
|
398
|
+
filter?: Record<string, unknown>;
|
|
399
|
+
}): Promise<SearchResult[]>;
|
|
400
|
+
query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
|
|
306
401
|
close(): Promise<void>;
|
|
307
402
|
}
|
|
308
403
|
|
package/dist/index.js
CHANGED
|
@@ -209,6 +209,14 @@ var WasmBackend = class {
|
|
|
209
209
|
);
|
|
210
210
|
}
|
|
211
211
|
const k = options?.k ?? 10;
|
|
212
|
+
if (options?.filter) {
|
|
213
|
+
const results = collection.store.search_with_filter(queryVector, k, options.filter);
|
|
214
|
+
return results.map((r) => ({
|
|
215
|
+
id: String(r.id),
|
|
216
|
+
score: r.score,
|
|
217
|
+
payload: r.payload || collection.payloads.get(String(r.id))
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
212
220
|
const rawResults = collection.store.search(queryVector, k);
|
|
213
221
|
return rawResults.map(([id, score]) => {
|
|
214
222
|
const stringId = String(id);
|
|
@@ -223,6 +231,14 @@ var WasmBackend = class {
|
|
|
223
231
|
return result;
|
|
224
232
|
});
|
|
225
233
|
}
|
|
234
|
+
async searchBatch(collectionName, searches) {
|
|
235
|
+
this.ensureInitialized();
|
|
236
|
+
const results = [];
|
|
237
|
+
for (const s of searches) {
|
|
238
|
+
results.push(await this.search(collectionName, s.vector, { k: s.k, filter: s.filter }));
|
|
239
|
+
}
|
|
240
|
+
return results;
|
|
241
|
+
}
|
|
226
242
|
async delete(collectionName, id) {
|
|
227
243
|
this.ensureInitialized();
|
|
228
244
|
const collection = this.collections.get(collectionName);
|
|
@@ -253,6 +269,24 @@ var WasmBackend = class {
|
|
|
253
269
|
payload
|
|
254
270
|
};
|
|
255
271
|
}
|
|
272
|
+
async textSearch(_collection, _query, _options) {
|
|
273
|
+
throw new VelesDBError(
|
|
274
|
+
"Text search is not supported in WASM backend. Use REST backend for BM25 search.",
|
|
275
|
+
"NOT_SUPPORTED"
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
async hybridSearch(_collection, _vector, _textQuery, _options) {
|
|
279
|
+
throw new VelesDBError(
|
|
280
|
+
"Hybrid search is not supported in WASM backend. Use REST backend for hybrid search.",
|
|
281
|
+
"NOT_SUPPORTED"
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
async query(_queryString, _params) {
|
|
285
|
+
throw new VelesDBError(
|
|
286
|
+
"VelesQL queries are not supported in WASM backend. Use REST backend for query support.",
|
|
287
|
+
"NOT_SUPPORTED"
|
|
288
|
+
);
|
|
289
|
+
}
|
|
256
290
|
async close() {
|
|
257
291
|
for (const [, data] of this.collections) {
|
|
258
292
|
data.store.free();
|
|
@@ -453,6 +487,26 @@ var RestBackend = class {
|
|
|
453
487
|
}
|
|
454
488
|
return response.data ?? [];
|
|
455
489
|
}
|
|
490
|
+
async searchBatch(collection, searches) {
|
|
491
|
+
this.ensureInitialized();
|
|
492
|
+
const formattedSearches = searches.map((s) => ({
|
|
493
|
+
vector: s.vector instanceof Float32Array ? Array.from(s.vector) : s.vector,
|
|
494
|
+
top_k: s.k ?? 10,
|
|
495
|
+
filter: s.filter
|
|
496
|
+
}));
|
|
497
|
+
const response = await this.request(
|
|
498
|
+
"POST",
|
|
499
|
+
`/collections/${encodeURIComponent(collection)}/search/batch`,
|
|
500
|
+
{ searches: formattedSearches }
|
|
501
|
+
);
|
|
502
|
+
if (response.error) {
|
|
503
|
+
if (response.error.code === "NOT_FOUND") {
|
|
504
|
+
throw new NotFoundError(`Collection '${collection}'`);
|
|
505
|
+
}
|
|
506
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
507
|
+
}
|
|
508
|
+
return response.data?.results.map((r) => r.results) ?? [];
|
|
509
|
+
}
|
|
456
510
|
async delete(collection, id) {
|
|
457
511
|
this.ensureInitialized();
|
|
458
512
|
const response = await this.request(
|
|
@@ -481,6 +535,62 @@ var RestBackend = class {
|
|
|
481
535
|
}
|
|
482
536
|
return response.data ?? null;
|
|
483
537
|
}
|
|
538
|
+
async textSearch(collection, query, options) {
|
|
539
|
+
this.ensureInitialized();
|
|
540
|
+
const response = await this.request(
|
|
541
|
+
"POST",
|
|
542
|
+
`/collections/${encodeURIComponent(collection)}/search/text`,
|
|
543
|
+
{
|
|
544
|
+
query,
|
|
545
|
+
top_k: options?.k ?? 10,
|
|
546
|
+
filter: options?.filter
|
|
547
|
+
}
|
|
548
|
+
);
|
|
549
|
+
if (response.error) {
|
|
550
|
+
if (response.error.code === "NOT_FOUND") {
|
|
551
|
+
throw new NotFoundError(`Collection '${collection}'`);
|
|
552
|
+
}
|
|
553
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
554
|
+
}
|
|
555
|
+
return response.data?.results ?? [];
|
|
556
|
+
}
|
|
557
|
+
async hybridSearch(collection, vector, textQuery, options) {
|
|
558
|
+
this.ensureInitialized();
|
|
559
|
+
const queryVector = vector instanceof Float32Array ? Array.from(vector) : vector;
|
|
560
|
+
const response = await this.request(
|
|
561
|
+
"POST",
|
|
562
|
+
`/collections/${encodeURIComponent(collection)}/search/hybrid`,
|
|
563
|
+
{
|
|
564
|
+
vector: queryVector,
|
|
565
|
+
query: textQuery,
|
|
566
|
+
top_k: options?.k ?? 10,
|
|
567
|
+
vector_weight: options?.vectorWeight ?? 0.5,
|
|
568
|
+
filter: options?.filter
|
|
569
|
+
}
|
|
570
|
+
);
|
|
571
|
+
if (response.error) {
|
|
572
|
+
if (response.error.code === "NOT_FOUND") {
|
|
573
|
+
throw new NotFoundError(`Collection '${collection}'`);
|
|
574
|
+
}
|
|
575
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
576
|
+
}
|
|
577
|
+
return response.data?.results ?? [];
|
|
578
|
+
}
|
|
579
|
+
async query(queryString, params) {
|
|
580
|
+
this.ensureInitialized();
|
|
581
|
+
const response = await this.request(
|
|
582
|
+
"POST",
|
|
583
|
+
"/query",
|
|
584
|
+
{
|
|
585
|
+
query: queryString,
|
|
586
|
+
params: params ?? {}
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
if (response.error) {
|
|
590
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
591
|
+
}
|
|
592
|
+
return response.data?.results ?? [];
|
|
593
|
+
}
|
|
484
594
|
async close() {
|
|
485
595
|
this._initialized = false;
|
|
486
596
|
}
|
|
@@ -640,6 +750,25 @@ var VelesDB = class {
|
|
|
640
750
|
}
|
|
641
751
|
return this.backend.search(collection, query, options);
|
|
642
752
|
}
|
|
753
|
+
/**
|
|
754
|
+
* Search for multiple vectors in parallel
|
|
755
|
+
*
|
|
756
|
+
* @param collection - Collection name
|
|
757
|
+
* @param searches - List of search queries
|
|
758
|
+
* @returns List of search results for each query
|
|
759
|
+
*/
|
|
760
|
+
async searchBatch(collection, searches) {
|
|
761
|
+
this.ensureInitialized();
|
|
762
|
+
if (!Array.isArray(searches)) {
|
|
763
|
+
throw new ValidationError("Searches must be an array");
|
|
764
|
+
}
|
|
765
|
+
for (const s of searches) {
|
|
766
|
+
if (!s.vector || !Array.isArray(s.vector) && !(s.vector instanceof Float32Array)) {
|
|
767
|
+
throw new ValidationError("Each search must have a vector (array or Float32Array)");
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
return this.backend.searchBatch(collection, searches);
|
|
771
|
+
}
|
|
643
772
|
/**
|
|
644
773
|
* Delete a vector by ID
|
|
645
774
|
*
|
|
@@ -662,6 +791,54 @@ var VelesDB = class {
|
|
|
662
791
|
this.ensureInitialized();
|
|
663
792
|
return this.backend.get(collection, id);
|
|
664
793
|
}
|
|
794
|
+
/**
|
|
795
|
+
* Perform full-text search using BM25
|
|
796
|
+
*
|
|
797
|
+
* @param collection - Collection name
|
|
798
|
+
* @param query - Text query
|
|
799
|
+
* @param options - Search options (k, filter)
|
|
800
|
+
* @returns Search results sorted by BM25 score
|
|
801
|
+
*/
|
|
802
|
+
async textSearch(collection, query, options) {
|
|
803
|
+
this.ensureInitialized();
|
|
804
|
+
if (!query || typeof query !== "string") {
|
|
805
|
+
throw new ValidationError("Query must be a non-empty string");
|
|
806
|
+
}
|
|
807
|
+
return this.backend.textSearch(collection, query, options);
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Perform hybrid search combining vector similarity and BM25 text search
|
|
811
|
+
*
|
|
812
|
+
* @param collection - Collection name
|
|
813
|
+
* @param vector - Query vector
|
|
814
|
+
* @param textQuery - Text query for BM25
|
|
815
|
+
* @param options - Search options (k, vectorWeight, filter)
|
|
816
|
+
* @returns Search results sorted by fused score
|
|
817
|
+
*/
|
|
818
|
+
async hybridSearch(collection, vector, textQuery, options) {
|
|
819
|
+
this.ensureInitialized();
|
|
820
|
+
if (!vector || !Array.isArray(vector) && !(vector instanceof Float32Array)) {
|
|
821
|
+
throw new ValidationError("Vector must be an array or Float32Array");
|
|
822
|
+
}
|
|
823
|
+
if (!textQuery || typeof textQuery !== "string") {
|
|
824
|
+
throw new ValidationError("Text query must be a non-empty string");
|
|
825
|
+
}
|
|
826
|
+
return this.backend.hybridSearch(collection, vector, textQuery, options);
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Execute a VelesQL query
|
|
830
|
+
*
|
|
831
|
+
* @param queryString - VelesQL query string
|
|
832
|
+
* @param params - Optional query parameters
|
|
833
|
+
* @returns Query results
|
|
834
|
+
*/
|
|
835
|
+
async query(queryString, params) {
|
|
836
|
+
this.ensureInitialized();
|
|
837
|
+
if (!queryString || typeof queryString !== "string") {
|
|
838
|
+
throw new ValidationError("Query string must be a non-empty string");
|
|
839
|
+
}
|
|
840
|
+
return this.backend.query(queryString, params);
|
|
841
|
+
}
|
|
665
842
|
/**
|
|
666
843
|
* Close the client and release resources
|
|
667
844
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -167,6 +167,14 @@ var WasmBackend = class {
|
|
|
167
167
|
);
|
|
168
168
|
}
|
|
169
169
|
const k = options?.k ?? 10;
|
|
170
|
+
if (options?.filter) {
|
|
171
|
+
const results = collection.store.search_with_filter(queryVector, k, options.filter);
|
|
172
|
+
return results.map((r) => ({
|
|
173
|
+
id: String(r.id),
|
|
174
|
+
score: r.score,
|
|
175
|
+
payload: r.payload || collection.payloads.get(String(r.id))
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
170
178
|
const rawResults = collection.store.search(queryVector, k);
|
|
171
179
|
return rawResults.map(([id, score]) => {
|
|
172
180
|
const stringId = String(id);
|
|
@@ -181,6 +189,14 @@ var WasmBackend = class {
|
|
|
181
189
|
return result;
|
|
182
190
|
});
|
|
183
191
|
}
|
|
192
|
+
async searchBatch(collectionName, searches) {
|
|
193
|
+
this.ensureInitialized();
|
|
194
|
+
const results = [];
|
|
195
|
+
for (const s of searches) {
|
|
196
|
+
results.push(await this.search(collectionName, s.vector, { k: s.k, filter: s.filter }));
|
|
197
|
+
}
|
|
198
|
+
return results;
|
|
199
|
+
}
|
|
184
200
|
async delete(collectionName, id) {
|
|
185
201
|
this.ensureInitialized();
|
|
186
202
|
const collection = this.collections.get(collectionName);
|
|
@@ -211,6 +227,24 @@ var WasmBackend = class {
|
|
|
211
227
|
payload
|
|
212
228
|
};
|
|
213
229
|
}
|
|
230
|
+
async textSearch(_collection, _query, _options) {
|
|
231
|
+
throw new VelesDBError(
|
|
232
|
+
"Text search is not supported in WASM backend. Use REST backend for BM25 search.",
|
|
233
|
+
"NOT_SUPPORTED"
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
async hybridSearch(_collection, _vector, _textQuery, _options) {
|
|
237
|
+
throw new VelesDBError(
|
|
238
|
+
"Hybrid search is not supported in WASM backend. Use REST backend for hybrid search.",
|
|
239
|
+
"NOT_SUPPORTED"
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
async query(_queryString, _params) {
|
|
243
|
+
throw new VelesDBError(
|
|
244
|
+
"VelesQL queries are not supported in WASM backend. Use REST backend for query support.",
|
|
245
|
+
"NOT_SUPPORTED"
|
|
246
|
+
);
|
|
247
|
+
}
|
|
214
248
|
async close() {
|
|
215
249
|
for (const [, data] of this.collections) {
|
|
216
250
|
data.store.free();
|
|
@@ -411,6 +445,26 @@ var RestBackend = class {
|
|
|
411
445
|
}
|
|
412
446
|
return response.data ?? [];
|
|
413
447
|
}
|
|
448
|
+
async searchBatch(collection, searches) {
|
|
449
|
+
this.ensureInitialized();
|
|
450
|
+
const formattedSearches = searches.map((s) => ({
|
|
451
|
+
vector: s.vector instanceof Float32Array ? Array.from(s.vector) : s.vector,
|
|
452
|
+
top_k: s.k ?? 10,
|
|
453
|
+
filter: s.filter
|
|
454
|
+
}));
|
|
455
|
+
const response = await this.request(
|
|
456
|
+
"POST",
|
|
457
|
+
`/collections/${encodeURIComponent(collection)}/search/batch`,
|
|
458
|
+
{ searches: formattedSearches }
|
|
459
|
+
);
|
|
460
|
+
if (response.error) {
|
|
461
|
+
if (response.error.code === "NOT_FOUND") {
|
|
462
|
+
throw new NotFoundError(`Collection '${collection}'`);
|
|
463
|
+
}
|
|
464
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
465
|
+
}
|
|
466
|
+
return response.data?.results.map((r) => r.results) ?? [];
|
|
467
|
+
}
|
|
414
468
|
async delete(collection, id) {
|
|
415
469
|
this.ensureInitialized();
|
|
416
470
|
const response = await this.request(
|
|
@@ -439,6 +493,62 @@ var RestBackend = class {
|
|
|
439
493
|
}
|
|
440
494
|
return response.data ?? null;
|
|
441
495
|
}
|
|
496
|
+
async textSearch(collection, query, options) {
|
|
497
|
+
this.ensureInitialized();
|
|
498
|
+
const response = await this.request(
|
|
499
|
+
"POST",
|
|
500
|
+
`/collections/${encodeURIComponent(collection)}/search/text`,
|
|
501
|
+
{
|
|
502
|
+
query,
|
|
503
|
+
top_k: options?.k ?? 10,
|
|
504
|
+
filter: options?.filter
|
|
505
|
+
}
|
|
506
|
+
);
|
|
507
|
+
if (response.error) {
|
|
508
|
+
if (response.error.code === "NOT_FOUND") {
|
|
509
|
+
throw new NotFoundError(`Collection '${collection}'`);
|
|
510
|
+
}
|
|
511
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
512
|
+
}
|
|
513
|
+
return response.data?.results ?? [];
|
|
514
|
+
}
|
|
515
|
+
async hybridSearch(collection, vector, textQuery, options) {
|
|
516
|
+
this.ensureInitialized();
|
|
517
|
+
const queryVector = vector instanceof Float32Array ? Array.from(vector) : vector;
|
|
518
|
+
const response = await this.request(
|
|
519
|
+
"POST",
|
|
520
|
+
`/collections/${encodeURIComponent(collection)}/search/hybrid`,
|
|
521
|
+
{
|
|
522
|
+
vector: queryVector,
|
|
523
|
+
query: textQuery,
|
|
524
|
+
top_k: options?.k ?? 10,
|
|
525
|
+
vector_weight: options?.vectorWeight ?? 0.5,
|
|
526
|
+
filter: options?.filter
|
|
527
|
+
}
|
|
528
|
+
);
|
|
529
|
+
if (response.error) {
|
|
530
|
+
if (response.error.code === "NOT_FOUND") {
|
|
531
|
+
throw new NotFoundError(`Collection '${collection}'`);
|
|
532
|
+
}
|
|
533
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
534
|
+
}
|
|
535
|
+
return response.data?.results ?? [];
|
|
536
|
+
}
|
|
537
|
+
async query(queryString, params) {
|
|
538
|
+
this.ensureInitialized();
|
|
539
|
+
const response = await this.request(
|
|
540
|
+
"POST",
|
|
541
|
+
"/query",
|
|
542
|
+
{
|
|
543
|
+
query: queryString,
|
|
544
|
+
params: params ?? {}
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
if (response.error) {
|
|
548
|
+
throw new VelesDBError(response.error.message, response.error.code);
|
|
549
|
+
}
|
|
550
|
+
return response.data?.results ?? [];
|
|
551
|
+
}
|
|
442
552
|
async close() {
|
|
443
553
|
this._initialized = false;
|
|
444
554
|
}
|
|
@@ -598,6 +708,25 @@ var VelesDB = class {
|
|
|
598
708
|
}
|
|
599
709
|
return this.backend.search(collection, query, options);
|
|
600
710
|
}
|
|
711
|
+
/**
|
|
712
|
+
* Search for multiple vectors in parallel
|
|
713
|
+
*
|
|
714
|
+
* @param collection - Collection name
|
|
715
|
+
* @param searches - List of search queries
|
|
716
|
+
* @returns List of search results for each query
|
|
717
|
+
*/
|
|
718
|
+
async searchBatch(collection, searches) {
|
|
719
|
+
this.ensureInitialized();
|
|
720
|
+
if (!Array.isArray(searches)) {
|
|
721
|
+
throw new ValidationError("Searches must be an array");
|
|
722
|
+
}
|
|
723
|
+
for (const s of searches) {
|
|
724
|
+
if (!s.vector || !Array.isArray(s.vector) && !(s.vector instanceof Float32Array)) {
|
|
725
|
+
throw new ValidationError("Each search must have a vector (array or Float32Array)");
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return this.backend.searchBatch(collection, searches);
|
|
729
|
+
}
|
|
601
730
|
/**
|
|
602
731
|
* Delete a vector by ID
|
|
603
732
|
*
|
|
@@ -620,6 +749,54 @@ var VelesDB = class {
|
|
|
620
749
|
this.ensureInitialized();
|
|
621
750
|
return this.backend.get(collection, id);
|
|
622
751
|
}
|
|
752
|
+
/**
|
|
753
|
+
* Perform full-text search using BM25
|
|
754
|
+
*
|
|
755
|
+
* @param collection - Collection name
|
|
756
|
+
* @param query - Text query
|
|
757
|
+
* @param options - Search options (k, filter)
|
|
758
|
+
* @returns Search results sorted by BM25 score
|
|
759
|
+
*/
|
|
760
|
+
async textSearch(collection, query, options) {
|
|
761
|
+
this.ensureInitialized();
|
|
762
|
+
if (!query || typeof query !== "string") {
|
|
763
|
+
throw new ValidationError("Query must be a non-empty string");
|
|
764
|
+
}
|
|
765
|
+
return this.backend.textSearch(collection, query, options);
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Perform hybrid search combining vector similarity and BM25 text search
|
|
769
|
+
*
|
|
770
|
+
* @param collection - Collection name
|
|
771
|
+
* @param vector - Query vector
|
|
772
|
+
* @param textQuery - Text query for BM25
|
|
773
|
+
* @param options - Search options (k, vectorWeight, filter)
|
|
774
|
+
* @returns Search results sorted by fused score
|
|
775
|
+
*/
|
|
776
|
+
async hybridSearch(collection, vector, textQuery, options) {
|
|
777
|
+
this.ensureInitialized();
|
|
778
|
+
if (!vector || !Array.isArray(vector) && !(vector instanceof Float32Array)) {
|
|
779
|
+
throw new ValidationError("Vector must be an array or Float32Array");
|
|
780
|
+
}
|
|
781
|
+
if (!textQuery || typeof textQuery !== "string") {
|
|
782
|
+
throw new ValidationError("Text query must be a non-empty string");
|
|
783
|
+
}
|
|
784
|
+
return this.backend.hybridSearch(collection, vector, textQuery, options);
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Execute a VelesQL query
|
|
788
|
+
*
|
|
789
|
+
* @param queryString - VelesQL query string
|
|
790
|
+
* @param params - Optional query parameters
|
|
791
|
+
* @returns Query results
|
|
792
|
+
*/
|
|
793
|
+
async query(queryString, params) {
|
|
794
|
+
this.ensureInitialized();
|
|
795
|
+
if (!queryString || typeof queryString !== "string") {
|
|
796
|
+
throw new ValidationError("Query string must be a non-empty string");
|
|
797
|
+
}
|
|
798
|
+
return this.backend.query(queryString, params);
|
|
799
|
+
}
|
|
623
800
|
/**
|
|
624
801
|
* Close the client and release resources
|
|
625
802
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wiscale/velesdb-sdk",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.9",
|
|
4
4
|
"description": "Official TypeScript SDK for VelesDB - Vector Search in Microseconds",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"vitest": "^4.0.16"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@wiscale/velesdb-wasm": "^0.
|
|
66
|
+
"@wiscale/velesdb-wasm": "^0.8.9"
|
|
67
67
|
},
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": ">=18.0.0"
|