@wiscale/velesdb-sdk 1.0.0 → 1.1.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 CHANGED
@@ -188,6 +188,41 @@ const results = await db.query(
188
188
  );
189
189
  ```
190
190
 
191
+ ### `db.multiQuerySearch(collection, vectors, options)` (v1.1.0+) ⭐ NEW
192
+
193
+ Multi-query fusion search for RAG pipelines using Multiple Query Generation (MQG).
194
+
195
+ | Option | Type | Default | Description |
196
+ |--------|------|---------|-------------|
197
+ | `k` | `number` | `10` | Number of results |
198
+ | `fusion` | `'rrf' \| 'average' \| 'maximum' \| 'weighted'` | `'rrf'` | Fusion strategy |
199
+ | `fusionParams` | `object` | `{ k: 60 }` | Strategy-specific parameters |
200
+ | `filter` | `object` | - | Filter expression |
201
+
202
+ ```typescript
203
+ // RRF fusion (default) - best for most RAG use cases
204
+ const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
205
+ k: 10,
206
+ fusion: 'rrf',
207
+ fusionParams: { k: 60 }
208
+ });
209
+
210
+ // Weighted fusion - like SearchXP scoring
211
+ const results = await db.multiQuerySearch('docs', [emb1, emb2], {
212
+ k: 10,
213
+ fusion: 'weighted',
214
+ fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
215
+ });
216
+
217
+ // Average/Maximum fusion
218
+ const results = await db.multiQuerySearch('docs', vectors, {
219
+ k: 10,
220
+ fusion: 'average' // or 'maximum'
221
+ });
222
+ ```
223
+
224
+ > **Note:** Multi-query fusion is only available with the REST backend.
225
+
191
226
  ### `db.isEmpty(collection)` (v0.8.11+)
192
227
 
193
228
  Check if a collection is empty.
package/dist/index.d.mts CHANGED
@@ -19,10 +19,12 @@ interface VelesDBConfig {
19
19
  /** Request timeout in milliseconds (default: 30000) */
20
20
  timeout?: number;
21
21
  }
22
+ /** Collection type */
23
+ type CollectionType = 'vector' | 'metadata_only';
22
24
  /** Collection configuration */
23
25
  interface CollectionConfig {
24
- /** Vector dimension (e.g., 768 for BERT, 1536 for GPT) */
25
- dimension: number;
26
+ /** Vector dimension (e.g., 768 for BERT, 1536 for GPT). Required for vector collections. */
27
+ dimension?: number;
26
28
  /** Distance metric (default: 'cosine') */
27
29
  metric?: DistanceMetric;
28
30
  /** Storage mode for vector quantization (default: 'full')
@@ -31,6 +33,8 @@ interface CollectionConfig {
31
33
  * - 'binary': 1-bit binary quantization, 32x memory reduction (edge/IoT)
32
34
  */
33
35
  storageMode?: StorageMode;
36
+ /** Collection type: 'vector' (default) or 'metadata_only' */
37
+ collectionType?: CollectionType;
34
38
  /** Optional collection description */
35
39
  description?: string;
36
40
  }
@@ -67,6 +71,28 @@ interface SearchOptions {
67
71
  /** Include vectors in results (default: false) */
68
72
  includeVectors?: boolean;
69
73
  }
74
+ /** Fusion strategy for multi-query search */
75
+ type FusionStrategy = 'rrf' | 'average' | 'maximum' | 'weighted';
76
+ /** Multi-query search options */
77
+ interface MultiQuerySearchOptions {
78
+ /** Number of results to return (default: 10) */
79
+ k?: number;
80
+ /** Fusion strategy (default: 'rrf') */
81
+ fusion?: FusionStrategy;
82
+ /** Fusion parameters */
83
+ fusionParams?: {
84
+ /** RRF k parameter (default: 60) */
85
+ k?: number;
86
+ /** Weighted fusion: average weight (default: 0.6) */
87
+ avgWeight?: number;
88
+ /** Weighted fusion: max weight (default: 0.3) */
89
+ maxWeight?: number;
90
+ /** Weighted fusion: hit weight (default: 0.1) */
91
+ hitWeight?: number;
92
+ };
93
+ /** Filter expression (optional) */
94
+ filter?: Record<string, unknown>;
95
+ }
70
96
  /** Search result */
71
97
  interface SearchResult {
72
98
  /** Document ID */
@@ -121,6 +147,8 @@ interface IVelesDBBackend {
121
147
  }): Promise<SearchResult[]>;
122
148
  /** Execute VelesQL query */
123
149
  query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
150
+ /** Multi-query fusion search */
151
+ multiQuerySearch(collection: string, vectors: Array<number[] | Float32Array>, options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
124
152
  /** Check if collection is empty */
125
153
  isEmpty(collection: string): Promise<boolean>;
126
154
  /** Flush pending changes to disk */
@@ -195,6 +223,20 @@ declare class VelesDB {
195
223
  * @param config - Collection configuration
196
224
  */
197
225
  createCollection(name: string, config: CollectionConfig): Promise<void>;
226
+ /**
227
+ * Create a metadata-only collection (no vectors, just payload data)
228
+ *
229
+ * Useful for storing reference data that can be JOINed with vector collections.
230
+ *
231
+ * @param name - Collection name
232
+ *
233
+ * @example
234
+ * ```typescript
235
+ * await db.createMetadataCollection('products');
236
+ * await db.insertMetadata('products', { id: 'P001', name: 'Widget', price: 99 });
237
+ * ```
238
+ */
239
+ createMetadataCollection(name: string): Promise<void>;
198
240
  /**
199
241
  * Delete a collection
200
242
  *
@@ -300,6 +342,34 @@ declare class VelesDB {
300
342
  * @returns Query results
301
343
  */
302
344
  query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
345
+ /**
346
+ * Multi-query fusion search combining results from multiple query vectors
347
+ *
348
+ * Ideal for RAG pipelines using Multiple Query Generation (MQG).
349
+ *
350
+ * @param collection - Collection name
351
+ * @param vectors - Array of query vectors
352
+ * @param options - Search options (k, fusion strategy, fusionParams, filter)
353
+ * @returns Fused search results
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * // RRF fusion (default)
358
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
359
+ * k: 10,
360
+ * fusion: 'rrf',
361
+ * fusionParams: { k: 60 }
362
+ * });
363
+ *
364
+ * // Weighted fusion
365
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2], {
366
+ * k: 10,
367
+ * fusion: 'weighted',
368
+ * fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
369
+ * });
370
+ * ```
371
+ */
372
+ multiQuerySearch(collection: string, vectors: Array<number[] | Float32Array>, options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
303
373
  /**
304
374
  * Check if a collection is empty
305
375
  *
@@ -366,6 +436,7 @@ declare class WasmBackend implements IVelesDBBackend {
366
436
  filter?: Record<string, unknown>;
367
437
  }): Promise<SearchResult[]>;
368
438
  query(_queryString: string, _params?: Record<string, unknown>): Promise<SearchResult[]>;
439
+ multiQuerySearch(_collection: string, _vectors: Array<number[] | Float32Array>, _options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
369
440
  isEmpty(collectionName: string): Promise<boolean>;
370
441
  flush(collectionName: string): Promise<void>;
371
442
  close(): Promise<void>;
@@ -417,9 +488,10 @@ declare class RestBackend implements IVelesDBBackend {
417
488
  filter?: Record<string, unknown>;
418
489
  }): Promise<SearchResult[]>;
419
490
  query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
491
+ multiQuerySearch(collection: string, vectors: Array<number[] | Float32Array>, options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
420
492
  isEmpty(collection: string): Promise<boolean>;
421
493
  flush(collection: string): Promise<void>;
422
494
  close(): Promise<void>;
423
495
  }
424
496
 
425
- export { type BackendType, type Collection, type CollectionConfig, ConnectionError, type DistanceMetric, type IVelesDBBackend, NotFoundError, RestBackend, type SearchOptions, type SearchResult, type StorageMode, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, WasmBackend };
497
+ export { type BackendType, type Collection, type CollectionConfig, type CollectionType, ConnectionError, type DistanceMetric, type FusionStrategy, type IVelesDBBackend, type MultiQuerySearchOptions, NotFoundError, RestBackend, type SearchOptions, type SearchResult, type StorageMode, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, WasmBackend };
package/dist/index.d.ts CHANGED
@@ -19,10 +19,12 @@ interface VelesDBConfig {
19
19
  /** Request timeout in milliseconds (default: 30000) */
20
20
  timeout?: number;
21
21
  }
22
+ /** Collection type */
23
+ type CollectionType = 'vector' | 'metadata_only';
22
24
  /** Collection configuration */
23
25
  interface CollectionConfig {
24
- /** Vector dimension (e.g., 768 for BERT, 1536 for GPT) */
25
- dimension: number;
26
+ /** Vector dimension (e.g., 768 for BERT, 1536 for GPT). Required for vector collections. */
27
+ dimension?: number;
26
28
  /** Distance metric (default: 'cosine') */
27
29
  metric?: DistanceMetric;
28
30
  /** Storage mode for vector quantization (default: 'full')
@@ -31,6 +33,8 @@ interface CollectionConfig {
31
33
  * - 'binary': 1-bit binary quantization, 32x memory reduction (edge/IoT)
32
34
  */
33
35
  storageMode?: StorageMode;
36
+ /** Collection type: 'vector' (default) or 'metadata_only' */
37
+ collectionType?: CollectionType;
34
38
  /** Optional collection description */
35
39
  description?: string;
36
40
  }
@@ -67,6 +71,28 @@ interface SearchOptions {
67
71
  /** Include vectors in results (default: false) */
68
72
  includeVectors?: boolean;
69
73
  }
74
+ /** Fusion strategy for multi-query search */
75
+ type FusionStrategy = 'rrf' | 'average' | 'maximum' | 'weighted';
76
+ /** Multi-query search options */
77
+ interface MultiQuerySearchOptions {
78
+ /** Number of results to return (default: 10) */
79
+ k?: number;
80
+ /** Fusion strategy (default: 'rrf') */
81
+ fusion?: FusionStrategy;
82
+ /** Fusion parameters */
83
+ fusionParams?: {
84
+ /** RRF k parameter (default: 60) */
85
+ k?: number;
86
+ /** Weighted fusion: average weight (default: 0.6) */
87
+ avgWeight?: number;
88
+ /** Weighted fusion: max weight (default: 0.3) */
89
+ maxWeight?: number;
90
+ /** Weighted fusion: hit weight (default: 0.1) */
91
+ hitWeight?: number;
92
+ };
93
+ /** Filter expression (optional) */
94
+ filter?: Record<string, unknown>;
95
+ }
70
96
  /** Search result */
71
97
  interface SearchResult {
72
98
  /** Document ID */
@@ -121,6 +147,8 @@ interface IVelesDBBackend {
121
147
  }): Promise<SearchResult[]>;
122
148
  /** Execute VelesQL query */
123
149
  query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
150
+ /** Multi-query fusion search */
151
+ multiQuerySearch(collection: string, vectors: Array<number[] | Float32Array>, options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
124
152
  /** Check if collection is empty */
125
153
  isEmpty(collection: string): Promise<boolean>;
126
154
  /** Flush pending changes to disk */
@@ -195,6 +223,20 @@ declare class VelesDB {
195
223
  * @param config - Collection configuration
196
224
  */
197
225
  createCollection(name: string, config: CollectionConfig): Promise<void>;
226
+ /**
227
+ * Create a metadata-only collection (no vectors, just payload data)
228
+ *
229
+ * Useful for storing reference data that can be JOINed with vector collections.
230
+ *
231
+ * @param name - Collection name
232
+ *
233
+ * @example
234
+ * ```typescript
235
+ * await db.createMetadataCollection('products');
236
+ * await db.insertMetadata('products', { id: 'P001', name: 'Widget', price: 99 });
237
+ * ```
238
+ */
239
+ createMetadataCollection(name: string): Promise<void>;
198
240
  /**
199
241
  * Delete a collection
200
242
  *
@@ -300,6 +342,34 @@ declare class VelesDB {
300
342
  * @returns Query results
301
343
  */
302
344
  query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
345
+ /**
346
+ * Multi-query fusion search combining results from multiple query vectors
347
+ *
348
+ * Ideal for RAG pipelines using Multiple Query Generation (MQG).
349
+ *
350
+ * @param collection - Collection name
351
+ * @param vectors - Array of query vectors
352
+ * @param options - Search options (k, fusion strategy, fusionParams, filter)
353
+ * @returns Fused search results
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * // RRF fusion (default)
358
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
359
+ * k: 10,
360
+ * fusion: 'rrf',
361
+ * fusionParams: { k: 60 }
362
+ * });
363
+ *
364
+ * // Weighted fusion
365
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2], {
366
+ * k: 10,
367
+ * fusion: 'weighted',
368
+ * fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
369
+ * });
370
+ * ```
371
+ */
372
+ multiQuerySearch(collection: string, vectors: Array<number[] | Float32Array>, options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
303
373
  /**
304
374
  * Check if a collection is empty
305
375
  *
@@ -366,6 +436,7 @@ declare class WasmBackend implements IVelesDBBackend {
366
436
  filter?: Record<string, unknown>;
367
437
  }): Promise<SearchResult[]>;
368
438
  query(_queryString: string, _params?: Record<string, unknown>): Promise<SearchResult[]>;
439
+ multiQuerySearch(_collection: string, _vectors: Array<number[] | Float32Array>, _options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
369
440
  isEmpty(collectionName: string): Promise<boolean>;
370
441
  flush(collectionName: string): Promise<void>;
371
442
  close(): Promise<void>;
@@ -417,9 +488,10 @@ declare class RestBackend implements IVelesDBBackend {
417
488
  filter?: Record<string, unknown>;
418
489
  }): Promise<SearchResult[]>;
419
490
  query(queryString: string, params?: Record<string, unknown>): Promise<SearchResult[]>;
491
+ multiQuerySearch(collection: string, vectors: Array<number[] | Float32Array>, options?: MultiQuerySearchOptions): Promise<SearchResult[]>;
420
492
  isEmpty(collection: string): Promise<boolean>;
421
493
  flush(collection: string): Promise<void>;
422
494
  close(): Promise<void>;
423
495
  }
424
496
 
425
- export { type BackendType, type Collection, type CollectionConfig, ConnectionError, type DistanceMetric, type IVelesDBBackend, NotFoundError, RestBackend, type SearchOptions, type SearchResult, type StorageMode, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, WasmBackend };
497
+ export { type BackendType, type Collection, type CollectionConfig, type CollectionType, ConnectionError, type DistanceMetric, type FusionStrategy, type IVelesDBBackend, type MultiQuerySearchOptions, NotFoundError, RestBackend, type SearchOptions, type SearchResult, type StorageMode, ValidationError, type VectorDocument, VelesDB, type VelesDBConfig, VelesDBError, WasmBackend };
package/dist/index.js CHANGED
@@ -129,7 +129,7 @@ var WasmBackend = class {
129
129
  }
130
130
  return {
131
131
  name,
132
- dimension: collection.config.dimension,
132
+ dimension: collection.config.dimension ?? 0,
133
133
  metric: collection.config.metric ?? "cosine",
134
134
  count: collection.store.len,
135
135
  createdAt: collection.createdAt
@@ -141,7 +141,7 @@ var WasmBackend = class {
141
141
  for (const [name, data] of this.collections) {
142
142
  result.push({
143
143
  name,
144
- dimension: data.config.dimension,
144
+ dimension: data.config.dimension ?? 0,
145
145
  metric: data.config.metric ?? "cosine",
146
146
  count: data.store.len,
147
147
  createdAt: data.createdAt
@@ -287,6 +287,12 @@ var WasmBackend = class {
287
287
  "NOT_SUPPORTED"
288
288
  );
289
289
  }
290
+ async multiQuerySearch(_collection, _vectors, _options) {
291
+ throw new VelesDBError(
292
+ "Multi-query fusion is not supported in WASM backend. Use REST backend for MQF search.",
293
+ "NOT_SUPPORTED"
294
+ );
295
+ }
290
296
  async isEmpty(collectionName) {
291
297
  this.ensureInitialized();
292
298
  const collection = this.collections.get(collectionName);
@@ -405,6 +411,8 @@ var RestBackend = class {
405
411
  name,
406
412
  dimension: config.dimension,
407
413
  metric: config.metric ?? "cosine",
414
+ storage_mode: config.storageMode ?? "full",
415
+ collection_type: config.collectionType ?? "vector",
408
416
  description: config.description
409
417
  });
410
418
  if (response.error) {
@@ -606,6 +614,30 @@ var RestBackend = class {
606
614
  }
607
615
  return response.data?.results ?? [];
608
616
  }
617
+ async multiQuerySearch(collection, vectors, options) {
618
+ this.ensureInitialized();
619
+ const formattedVectors = vectors.map(
620
+ (v) => v instanceof Float32Array ? Array.from(v) : v
621
+ );
622
+ const response = await this.request(
623
+ "POST",
624
+ `/collections/${encodeURIComponent(collection)}/search/multi`,
625
+ {
626
+ vectors: formattedVectors,
627
+ top_k: options?.k ?? 10,
628
+ fusion: options?.fusion ?? "rrf",
629
+ fusion_params: options?.fusionParams ?? { k: 60 },
630
+ filter: options?.filter
631
+ }
632
+ );
633
+ if (response.error) {
634
+ if (response.error.code === "NOT_FOUND") {
635
+ throw new NotFoundError(`Collection '${collection}'`);
636
+ }
637
+ throw new VelesDBError(response.error.message, response.error.code);
638
+ }
639
+ return response.data?.results ?? [];
640
+ }
609
641
  async isEmpty(collection) {
610
642
  this.ensureInitialized();
611
643
  const response = await this.request(
@@ -706,11 +738,32 @@ var VelesDB = class {
706
738
  if (!name || typeof name !== "string") {
707
739
  throw new ValidationError("Collection name must be a non-empty string");
708
740
  }
709
- if (!config.dimension || config.dimension <= 0) {
710
- throw new ValidationError("Dimension must be a positive integer");
741
+ const isMetadataOnly = config.collectionType === "metadata_only";
742
+ if (!isMetadataOnly && (!config.dimension || config.dimension <= 0)) {
743
+ throw new ValidationError("Dimension must be a positive integer for vector collections");
711
744
  }
712
745
  await this.backend.createCollection(name, config);
713
746
  }
747
+ /**
748
+ * Create a metadata-only collection (no vectors, just payload data)
749
+ *
750
+ * Useful for storing reference data that can be JOINed with vector collections.
751
+ *
752
+ * @param name - Collection name
753
+ *
754
+ * @example
755
+ * ```typescript
756
+ * await db.createMetadataCollection('products');
757
+ * await db.insertMetadata('products', { id: 'P001', name: 'Widget', price: 99 });
758
+ * ```
759
+ */
760
+ async createMetadataCollection(name) {
761
+ this.ensureInitialized();
762
+ if (!name || typeof name !== "string") {
763
+ throw new ValidationError("Collection name must be a non-empty string");
764
+ }
765
+ await this.backend.createCollection(name, { collectionType: "metadata_only" });
766
+ }
714
767
  /**
715
768
  * Delete a collection
716
769
  *
@@ -881,6 +934,45 @@ var VelesDB = class {
881
934
  }
882
935
  return this.backend.query(queryString, params);
883
936
  }
937
+ /**
938
+ * Multi-query fusion search combining results from multiple query vectors
939
+ *
940
+ * Ideal for RAG pipelines using Multiple Query Generation (MQG).
941
+ *
942
+ * @param collection - Collection name
943
+ * @param vectors - Array of query vectors
944
+ * @param options - Search options (k, fusion strategy, fusionParams, filter)
945
+ * @returns Fused search results
946
+ *
947
+ * @example
948
+ * ```typescript
949
+ * // RRF fusion (default)
950
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
951
+ * k: 10,
952
+ * fusion: 'rrf',
953
+ * fusionParams: { k: 60 }
954
+ * });
955
+ *
956
+ * // Weighted fusion
957
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2], {
958
+ * k: 10,
959
+ * fusion: 'weighted',
960
+ * fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
961
+ * });
962
+ * ```
963
+ */
964
+ async multiQuerySearch(collection, vectors, options) {
965
+ this.ensureInitialized();
966
+ if (!Array.isArray(vectors) || vectors.length === 0) {
967
+ throw new ValidationError("Vectors must be a non-empty array");
968
+ }
969
+ for (const v of vectors) {
970
+ if (!Array.isArray(v) && !(v instanceof Float32Array)) {
971
+ throw new ValidationError("Each vector must be an array or Float32Array");
972
+ }
973
+ }
974
+ return this.backend.multiQuerySearch(collection, vectors, options);
975
+ }
884
976
  /**
885
977
  * Check if a collection is empty
886
978
  *
package/dist/index.mjs CHANGED
@@ -87,7 +87,7 @@ var WasmBackend = class {
87
87
  }
88
88
  return {
89
89
  name,
90
- dimension: collection.config.dimension,
90
+ dimension: collection.config.dimension ?? 0,
91
91
  metric: collection.config.metric ?? "cosine",
92
92
  count: collection.store.len,
93
93
  createdAt: collection.createdAt
@@ -99,7 +99,7 @@ var WasmBackend = class {
99
99
  for (const [name, data] of this.collections) {
100
100
  result.push({
101
101
  name,
102
- dimension: data.config.dimension,
102
+ dimension: data.config.dimension ?? 0,
103
103
  metric: data.config.metric ?? "cosine",
104
104
  count: data.store.len,
105
105
  createdAt: data.createdAt
@@ -245,6 +245,12 @@ var WasmBackend = class {
245
245
  "NOT_SUPPORTED"
246
246
  );
247
247
  }
248
+ async multiQuerySearch(_collection, _vectors, _options) {
249
+ throw new VelesDBError(
250
+ "Multi-query fusion is not supported in WASM backend. Use REST backend for MQF search.",
251
+ "NOT_SUPPORTED"
252
+ );
253
+ }
248
254
  async isEmpty(collectionName) {
249
255
  this.ensureInitialized();
250
256
  const collection = this.collections.get(collectionName);
@@ -363,6 +369,8 @@ var RestBackend = class {
363
369
  name,
364
370
  dimension: config.dimension,
365
371
  metric: config.metric ?? "cosine",
372
+ storage_mode: config.storageMode ?? "full",
373
+ collection_type: config.collectionType ?? "vector",
366
374
  description: config.description
367
375
  });
368
376
  if (response.error) {
@@ -564,6 +572,30 @@ var RestBackend = class {
564
572
  }
565
573
  return response.data?.results ?? [];
566
574
  }
575
+ async multiQuerySearch(collection, vectors, options) {
576
+ this.ensureInitialized();
577
+ const formattedVectors = vectors.map(
578
+ (v) => v instanceof Float32Array ? Array.from(v) : v
579
+ );
580
+ const response = await this.request(
581
+ "POST",
582
+ `/collections/${encodeURIComponent(collection)}/search/multi`,
583
+ {
584
+ vectors: formattedVectors,
585
+ top_k: options?.k ?? 10,
586
+ fusion: options?.fusion ?? "rrf",
587
+ fusion_params: options?.fusionParams ?? { k: 60 },
588
+ filter: options?.filter
589
+ }
590
+ );
591
+ if (response.error) {
592
+ if (response.error.code === "NOT_FOUND") {
593
+ throw new NotFoundError(`Collection '${collection}'`);
594
+ }
595
+ throw new VelesDBError(response.error.message, response.error.code);
596
+ }
597
+ return response.data?.results ?? [];
598
+ }
567
599
  async isEmpty(collection) {
568
600
  this.ensureInitialized();
569
601
  const response = await this.request(
@@ -664,11 +696,32 @@ var VelesDB = class {
664
696
  if (!name || typeof name !== "string") {
665
697
  throw new ValidationError("Collection name must be a non-empty string");
666
698
  }
667
- if (!config.dimension || config.dimension <= 0) {
668
- throw new ValidationError("Dimension must be a positive integer");
699
+ const isMetadataOnly = config.collectionType === "metadata_only";
700
+ if (!isMetadataOnly && (!config.dimension || config.dimension <= 0)) {
701
+ throw new ValidationError("Dimension must be a positive integer for vector collections");
669
702
  }
670
703
  await this.backend.createCollection(name, config);
671
704
  }
705
+ /**
706
+ * Create a metadata-only collection (no vectors, just payload data)
707
+ *
708
+ * Useful for storing reference data that can be JOINed with vector collections.
709
+ *
710
+ * @param name - Collection name
711
+ *
712
+ * @example
713
+ * ```typescript
714
+ * await db.createMetadataCollection('products');
715
+ * await db.insertMetadata('products', { id: 'P001', name: 'Widget', price: 99 });
716
+ * ```
717
+ */
718
+ async createMetadataCollection(name) {
719
+ this.ensureInitialized();
720
+ if (!name || typeof name !== "string") {
721
+ throw new ValidationError("Collection name must be a non-empty string");
722
+ }
723
+ await this.backend.createCollection(name, { collectionType: "metadata_only" });
724
+ }
672
725
  /**
673
726
  * Delete a collection
674
727
  *
@@ -839,6 +892,45 @@ var VelesDB = class {
839
892
  }
840
893
  return this.backend.query(queryString, params);
841
894
  }
895
+ /**
896
+ * Multi-query fusion search combining results from multiple query vectors
897
+ *
898
+ * Ideal for RAG pipelines using Multiple Query Generation (MQG).
899
+ *
900
+ * @param collection - Collection name
901
+ * @param vectors - Array of query vectors
902
+ * @param options - Search options (k, fusion strategy, fusionParams, filter)
903
+ * @returns Fused search results
904
+ *
905
+ * @example
906
+ * ```typescript
907
+ * // RRF fusion (default)
908
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2, emb3], {
909
+ * k: 10,
910
+ * fusion: 'rrf',
911
+ * fusionParams: { k: 60 }
912
+ * });
913
+ *
914
+ * // Weighted fusion
915
+ * const results = await db.multiQuerySearch('docs', [emb1, emb2], {
916
+ * k: 10,
917
+ * fusion: 'weighted',
918
+ * fusionParams: { avgWeight: 0.6, maxWeight: 0.3, hitWeight: 0.1 }
919
+ * });
920
+ * ```
921
+ */
922
+ async multiQuerySearch(collection, vectors, options) {
923
+ this.ensureInitialized();
924
+ if (!Array.isArray(vectors) || vectors.length === 0) {
925
+ throw new ValidationError("Vectors must be a non-empty array");
926
+ }
927
+ for (const v of vectors) {
928
+ if (!Array.isArray(v) && !(v instanceof Float32Array)) {
929
+ throw new ValidationError("Each vector must be an array or Float32Array");
930
+ }
931
+ }
932
+ return this.backend.multiQuerySearch(collection, vectors, options);
933
+ }
842
934
  /**
843
935
  * Check if a collection is empty
844
936
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wiscale/velesdb-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
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": "^1.0.0"
66
+ "@wiscale/velesdb-wasm": "^1.1.0"
67
67
  },
68
68
  "engines": {
69
69
  "node": ">=18.0.0"