hyperspace-sdk-ts 3.1.1 → 3.1.3
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 +158 -13
- package/dist/client.d.ts +122 -5
- package/dist/client.js +828 -168
- package/dist/math.d.ts +4 -0
- package/dist/math.js +150 -0
- package/dist/proto/hyperspace_grpc_pb.js +222 -0
- package/dist/proto/hyperspace_pb.js +9862 -4739
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -33,13 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.HyperspaceClient = exports.HyperbolicMath = exports.DurabilityLevel = exports.TribunalContext = exports.
|
|
36
|
+
exports.HyperspaceClient = exports.HyperbolicMath = exports.DurabilityLevel = exports.TribunalContext = exports.CognitiveMathExport = void 0;
|
|
37
37
|
const grpc = __importStar(require("@grpc/grpc-js"));
|
|
38
38
|
const hyperspace_grpc_pb_1 = require("./proto/hyperspace_grpc_pb");
|
|
39
39
|
const hyperspace_pb_1 = require("./proto/hyperspace_pb");
|
|
40
40
|
Object.defineProperty(exports, "DurabilityLevel", { enumerable: true, get: function () { return hyperspace_pb_1.DurabilityLevel; } });
|
|
41
41
|
const hyperspace_pb = __importStar(require("./proto/hyperspace_pb")); // New, for direct access to types
|
|
42
|
-
|
|
42
|
+
const CognitiveMath = __importStar(require("./math"));
|
|
43
|
+
exports.CognitiveMathExport = __importStar(require("./math"));
|
|
43
44
|
var agents_1 = require("./agents");
|
|
44
45
|
Object.defineProperty(exports, "TribunalContext", { enumerable: true, get: function () { return agents_1.TribunalContext; } });
|
|
45
46
|
exports.HyperbolicMath = {
|
|
@@ -224,7 +225,82 @@ class HyperspaceClient {
|
|
|
224
225
|
});
|
|
225
226
|
return out;
|
|
226
227
|
}
|
|
228
|
+
toProtoFilter(f) {
|
|
229
|
+
const pf = new hyperspace_pb.Filter();
|
|
230
|
+
if (f.match) {
|
|
231
|
+
const m = new hyperspace_pb.Match();
|
|
232
|
+
m.setKey(f.match.key);
|
|
233
|
+
m.setValue(f.match.value);
|
|
234
|
+
pf.setMatch(m);
|
|
235
|
+
}
|
|
236
|
+
else if (f.prefix) {
|
|
237
|
+
const p = new hyperspace_pb.Prefix();
|
|
238
|
+
p.setKey(f.prefix.key);
|
|
239
|
+
p.setPrefix(f.prefix.prefix);
|
|
240
|
+
pf.setPrefix(p);
|
|
241
|
+
}
|
|
242
|
+
else if (f.range) {
|
|
243
|
+
const r = new hyperspace_pb.Range();
|
|
244
|
+
r.setKey(f.range.key);
|
|
245
|
+
if (f.range.gte !== undefined) {
|
|
246
|
+
if (Number.isInteger(f.range.gte))
|
|
247
|
+
r.setGte(f.range.gte);
|
|
248
|
+
else
|
|
249
|
+
r.setGteF64(f.range.gte);
|
|
250
|
+
}
|
|
251
|
+
if (f.range.lte !== undefined) {
|
|
252
|
+
if (Number.isInteger(f.range.lte))
|
|
253
|
+
r.setLte(f.range.lte);
|
|
254
|
+
else
|
|
255
|
+
r.setLteF64(f.range.lte);
|
|
256
|
+
}
|
|
257
|
+
pf.setRange(r);
|
|
258
|
+
}
|
|
259
|
+
else if (f.inCone) {
|
|
260
|
+
const c = new hyperspace_pb.InCone();
|
|
261
|
+
c.setAxesList(f.inCone.axes);
|
|
262
|
+
c.setAperturesList(f.inCone.apertures);
|
|
263
|
+
c.setCen(f.inCone.cen[0] || 0);
|
|
264
|
+
pf.setInCone(c);
|
|
265
|
+
}
|
|
266
|
+
else if (f.inBall) {
|
|
267
|
+
const b = new hyperspace_pb.InBall();
|
|
268
|
+
b.setCenterList(f.inBall.center);
|
|
269
|
+
b.setRadius(f.inBall.radius);
|
|
270
|
+
pf.setInBall(b);
|
|
271
|
+
}
|
|
272
|
+
else if (f.inBox) {
|
|
273
|
+
const b = new hyperspace_pb.InBox();
|
|
274
|
+
b.setMinBoundsList(f.inBox.minBounds);
|
|
275
|
+
b.setMaxBoundsList(f.inBox.maxBounds);
|
|
276
|
+
pf.setInBox(b);
|
|
277
|
+
}
|
|
278
|
+
else if (f.and) {
|
|
279
|
+
const andOp = new hyperspace_pb.FilterAnd();
|
|
280
|
+
andOp.setConditionsList(f.and.map(cond => this.toProtoFilter(cond)));
|
|
281
|
+
pf.setAndOp(andOp);
|
|
282
|
+
}
|
|
283
|
+
else if (f.or) {
|
|
284
|
+
const orOp = new hyperspace_pb.FilterOr();
|
|
285
|
+
orOp.setConditionsList(f.or.map(cond => this.toProtoFilter(cond)));
|
|
286
|
+
pf.setOrOp(orOp);
|
|
287
|
+
}
|
|
288
|
+
else if (f.not) {
|
|
289
|
+
const notOp = new hyperspace_pb.FilterNot();
|
|
290
|
+
notOp.setCondition(this.toProtoFilter(f.not));
|
|
291
|
+
pf.setNotOp(notOp);
|
|
292
|
+
}
|
|
293
|
+
return pf;
|
|
294
|
+
}
|
|
227
295
|
constructor(host = 'localhost:50051', apiKey, userId) {
|
|
296
|
+
this.collectionKeys = {};
|
|
297
|
+
this.encryptionContexts = {};
|
|
298
|
+
this.collectionMetrics = {};
|
|
299
|
+
this.collectionNoiseSigmas = {};
|
|
300
|
+
this.collectionSchemas = {};
|
|
301
|
+
this.host = host;
|
|
302
|
+
this.apiKey = apiKey;
|
|
303
|
+
this.userId = userId;
|
|
228
304
|
const options = {
|
|
229
305
|
'grpc.max_send_message_length': 64 * 1024 * 1024,
|
|
230
306
|
'grpc.max_receive_message_length': 64 * 1024 * 1024,
|
|
@@ -243,13 +319,246 @@ class HyperspaceClient {
|
|
|
243
319
|
this.metadata.add('x-hyperspace-user-id', userId);
|
|
244
320
|
}
|
|
245
321
|
}
|
|
322
|
+
registerCollectionKey(collectionName, key, metric = "l2", noiseSigma = 0.02, schema) {
|
|
323
|
+
this.collectionKeys[collectionName] = key;
|
|
324
|
+
this.collectionMetrics[collectionName] = metric;
|
|
325
|
+
this.collectionNoiseSigmas[collectionName] = noiseSigma;
|
|
326
|
+
if (schema) {
|
|
327
|
+
this.collectionSchemas[collectionName] = schema;
|
|
328
|
+
}
|
|
329
|
+
if (this.encryptionContexts[collectionName]) {
|
|
330
|
+
delete this.encryptionContexts[collectionName];
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
deriveKeys(password, collectionName) {
|
|
334
|
+
const crypto = require('crypto');
|
|
335
|
+
const salt = crypto.createHash('sha256').update(collectionName).digest();
|
|
336
|
+
const aesKey = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
|
|
337
|
+
const hmacKey = crypto.pbkdf2Sync(password, salt, 100000, 32, 'sha256');
|
|
338
|
+
return { aesKey, hmacKey };
|
|
339
|
+
}
|
|
340
|
+
encryptPayload(plaintext, aesKey) {
|
|
341
|
+
const crypto = require('crypto');
|
|
342
|
+
const iv = crypto.randomBytes(12);
|
|
343
|
+
const pbkdf2Salt = crypto.randomBytes(16);
|
|
344
|
+
const derivedAesKey = crypto.pbkdf2Sync(aesKey, pbkdf2Salt, 100000, 32, 'sha256');
|
|
345
|
+
const cipherPayload = crypto.createCipheriv('aes-256-gcm', derivedAesKey, iv);
|
|
346
|
+
const encryptedPayload = Buffer.concat([cipherPayload.update(plaintext), cipherPayload.final()]);
|
|
347
|
+
const payloadTag = cipherPayload.getAuthTag();
|
|
348
|
+
return Buffer.concat([pbkdf2Salt, iv, encryptedPayload, payloadTag]);
|
|
349
|
+
}
|
|
350
|
+
decryptPayload(data, aesKey) {
|
|
351
|
+
const crypto = require('crypto');
|
|
352
|
+
if (data.length < 16 + 12 + 16) {
|
|
353
|
+
throw new Error("Invalid encrypted payload size");
|
|
354
|
+
}
|
|
355
|
+
const pbkdf2Salt = data.subarray(0, 16);
|
|
356
|
+
const iv = data.subarray(16, 28);
|
|
357
|
+
const ciphertext = data.subarray(28, data.length - 16);
|
|
358
|
+
const tag = data.subarray(data.length - 16);
|
|
359
|
+
const derivedAesKey = crypto.pbkdf2Sync(aesKey, pbkdf2Salt, 100000, 32, 'sha256');
|
|
360
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', derivedAesKey, iv);
|
|
361
|
+
decipher.setAuthTag(tag);
|
|
362
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
363
|
+
}
|
|
364
|
+
hashMetadataKey(key, hmacKey) {
|
|
365
|
+
const crypto = require('crypto');
|
|
366
|
+
const hash = crypto.createHmac('sha256', hmacKey).update(key).digest('hex');
|
|
367
|
+
return "tag_" + hash.slice(0, 16);
|
|
368
|
+
}
|
|
369
|
+
hashMetadataValue(value, hmacKey) {
|
|
370
|
+
const crypto = require('crypto');
|
|
371
|
+
const hash = crypto.createHmac('sha256', hmacKey).update(value).digest('hex');
|
|
372
|
+
return "val_" + hash;
|
|
373
|
+
}
|
|
374
|
+
async _getEncryptionContext(collection, vectorDim, metric = "l2") {
|
|
375
|
+
if (!collection)
|
|
376
|
+
return null;
|
|
377
|
+
const key = this.collectionKeys[collection];
|
|
378
|
+
if (!key)
|
|
379
|
+
return null;
|
|
380
|
+
if (!this.collectionSchemas[collection]) {
|
|
381
|
+
try {
|
|
382
|
+
const stats = await this.getCollectionStats(collection);
|
|
383
|
+
if (stats && stats.schema) {
|
|
384
|
+
this.collectionSchemas[collection] = stats.schema;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch (e) { }
|
|
388
|
+
}
|
|
389
|
+
if (!this.encryptionContexts[collection]) {
|
|
390
|
+
const { aesKey, hmacKey } = this.deriveKeys(key, collection);
|
|
391
|
+
this.encryptionContexts[collection] = {
|
|
392
|
+
aesKey,
|
|
393
|
+
hmacKey,
|
|
394
|
+
projectionMatrices: {}
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
const context = this.encryptionContexts[collection];
|
|
398
|
+
if (vectorDim !== undefined) {
|
|
399
|
+
if (!context.projectionMatrices[vectorDim]) {
|
|
400
|
+
const isLorentz = ["lorentz", "poincare"].includes(metric.toLowerCase());
|
|
401
|
+
const matrixDim = metric.toLowerCase() === "poincare" ? vectorDim + 1 : vectorDim;
|
|
402
|
+
if (isLorentz) {
|
|
403
|
+
context.projectionMatrices[vectorDim] = CognitiveMath.generateLorentzMatrix(matrixDim, context.hmacKey);
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
context.projectionMatrices[vectorDim] = CognitiveMath.generateOrthogonalMatrix(matrixDim, context.hmacKey);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return context;
|
|
411
|
+
}
|
|
412
|
+
_projectSingleBlock(subVec, metric, context, blockId) {
|
|
413
|
+
const dim = subVec.length;
|
|
414
|
+
if (dim === 0)
|
|
415
|
+
return [];
|
|
416
|
+
const cacheKey = blockId ? `${dim}_${blockId}` : `${dim}`;
|
|
417
|
+
if (!context.projectionMatrices[cacheKey]) {
|
|
418
|
+
const isLorentz = ["lorentz", "poincare"].includes(metric.toLowerCase());
|
|
419
|
+
const matrixDim = metric.toLowerCase() === "poincare" ? dim + 1 : dim;
|
|
420
|
+
const crypto = require('crypto');
|
|
421
|
+
let seed = context.hmacKey;
|
|
422
|
+
if (blockId) {
|
|
423
|
+
seed = crypto.createHash('sha256').update(seed).update(blockId).digest();
|
|
424
|
+
}
|
|
425
|
+
if (isLorentz) {
|
|
426
|
+
context.projectionMatrices[cacheKey] = CognitiveMath.generateLorentzMatrix(matrixDim, seed);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
context.projectionMatrices[cacheKey] = CognitiveMath.generateOrthogonalMatrix(matrixDim, seed);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const matrix = context.projectionMatrices[cacheKey];
|
|
433
|
+
if (metric.toLowerCase() === "poincare") {
|
|
434
|
+
const lorentzVec = CognitiveMath.poincareToLorentz(subVec);
|
|
435
|
+
const projLorentz = CognitiveMath.projectVector(lorentzVec, matrix);
|
|
436
|
+
return CognitiveMath.lorentzToPoincare(projLorentz);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
return CognitiveMath.projectVector(subVec, matrix);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
_projectCollectionVector(collection, vector, context, metric = "l2") {
|
|
443
|
+
const schema = this.collectionSchemas[collection];
|
|
444
|
+
if (!schema || !schema.components || schema.components.length === 0) {
|
|
445
|
+
return this._projectSingleBlock(vector, metric, context);
|
|
446
|
+
}
|
|
447
|
+
const components = schema.components;
|
|
448
|
+
const cascade = schema.cascadePipeline || [];
|
|
449
|
+
const componentCutoffs = {};
|
|
450
|
+
for (const layer of cascade) {
|
|
451
|
+
const compName = layer.componentName;
|
|
452
|
+
const cutoff = layer.cutoffDimension;
|
|
453
|
+
if (compName && cutoff) {
|
|
454
|
+
if (!componentCutoffs[compName]) {
|
|
455
|
+
componentCutoffs[compName] = [];
|
|
456
|
+
}
|
|
457
|
+
componentCutoffs[compName].push(cutoff);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
for (const compName in componentCutoffs) {
|
|
461
|
+
componentCutoffs[compName] = Array.from(new Set(componentCutoffs[compName])).sort((a, b) => a - b);
|
|
462
|
+
}
|
|
463
|
+
const projectedParts = [];
|
|
464
|
+
let currentOffset = 0;
|
|
465
|
+
for (const comp of components) {
|
|
466
|
+
const compName = comp.name;
|
|
467
|
+
const compMetric = comp.metric;
|
|
468
|
+
const compDim = comp.fullDimension;
|
|
469
|
+
if (currentOffset >= vector.length) {
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
let subVec = vector.slice(currentOffset, currentOffset + compDim);
|
|
473
|
+
if (subVec.length < compDim) {
|
|
474
|
+
subVec = subVec.concat(new Array(compDim - subVec.length).fill(0));
|
|
475
|
+
}
|
|
476
|
+
const cutoffs = componentCutoffs[compName] || [];
|
|
477
|
+
const validCutoffs = cutoffs.filter(c => c < compDim);
|
|
478
|
+
let projSub = [];
|
|
479
|
+
if (validCutoffs.length === 0) {
|
|
480
|
+
projSub = this._projectSingleBlock(subVec, compMetric, context);
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
let blockStart = 0;
|
|
484
|
+
for (const cutoff of validCutoffs) {
|
|
485
|
+
const blockData = subVec.slice(blockStart, cutoff);
|
|
486
|
+
const projBlock = this._projectSingleBlock(blockData, compMetric, context, `${compName}_block_${blockStart}_${cutoff}`);
|
|
487
|
+
projSub = projSub.concat(projBlock);
|
|
488
|
+
blockStart = cutoff;
|
|
489
|
+
}
|
|
490
|
+
if (blockStart < compDim) {
|
|
491
|
+
const blockData = subVec.slice(blockStart, compDim);
|
|
492
|
+
const projBlock = this._projectSingleBlock(blockData, compMetric, context, `${compName}_block_${blockStart}_${compDim}`);
|
|
493
|
+
projSub = projSub.concat(projBlock);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
projectedParts.push(...projSub);
|
|
497
|
+
currentOffset += compDim;
|
|
498
|
+
}
|
|
499
|
+
if (currentOffset < vector.length) {
|
|
500
|
+
projectedParts.push(...vector.slice(currentOffset));
|
|
501
|
+
}
|
|
502
|
+
return projectedParts;
|
|
503
|
+
}
|
|
504
|
+
_encryptFilters(filters, context) {
|
|
505
|
+
if (!filters)
|
|
506
|
+
return filters;
|
|
507
|
+
return filters.map(f => {
|
|
508
|
+
const nf = { ...f };
|
|
509
|
+
if (nf.match) {
|
|
510
|
+
nf.match = {
|
|
511
|
+
key: this.hashMetadataKey(nf.match.key, context.hmacKey),
|
|
512
|
+
value: this.hashMetadataValue(nf.match.value, context.hmacKey)
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
if (nf.prefix) {
|
|
516
|
+
nf.prefix = {
|
|
517
|
+
key: this.hashMetadataKey(nf.prefix.key, context.hmacKey),
|
|
518
|
+
prefix: this.hashMetadataValue(nf.prefix.prefix, context.hmacKey)
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
if (nf.and) {
|
|
522
|
+
nf.and = this._encryptFilters(nf.and, context);
|
|
523
|
+
}
|
|
524
|
+
if (nf.or) {
|
|
525
|
+
nf.or = this._encryptFilters(nf.or, context);
|
|
526
|
+
}
|
|
527
|
+
if (nf.not) {
|
|
528
|
+
nf.not = this._encryptFilters([nf.not], context)[0];
|
|
529
|
+
}
|
|
530
|
+
return nf;
|
|
531
|
+
});
|
|
532
|
+
}
|
|
246
533
|
// ... (create/delete unchanged) ...
|
|
247
|
-
createCollection(name,
|
|
534
|
+
createCollection(name, schema, encryptionKey = '', noiseSigma = 0.02) {
|
|
535
|
+
const metric = (schema.components && schema.components[0]) ? schema.components[0].metric : "l2";
|
|
536
|
+
if (encryptionKey) {
|
|
537
|
+
this.registerCollectionKey(name, encryptionKey, metric, noiseSigma, schema);
|
|
538
|
+
}
|
|
248
539
|
return new Promise((resolve, reject) => {
|
|
249
540
|
const req = new hyperspace_pb_1.CreateCollectionRequest();
|
|
250
541
|
req.setName(name);
|
|
251
|
-
|
|
252
|
-
|
|
542
|
+
const protoSchema = new hyperspace_pb.CollectionSchema();
|
|
543
|
+
const components = schema.components.map(c => {
|
|
544
|
+
const comp = new hyperspace_pb.VectorComponent();
|
|
545
|
+
comp.setName(c.name);
|
|
546
|
+
comp.setMetric(c.metric);
|
|
547
|
+
comp.setFullDimension(c.fullDimension);
|
|
548
|
+
comp.setWeight(c.weight);
|
|
549
|
+
return comp;
|
|
550
|
+
});
|
|
551
|
+
protoSchema.setComponentsList(components);
|
|
552
|
+
const pipeline = schema.cascadePipeline.map(l => {
|
|
553
|
+
const layer = new hyperspace_pb.MrlLayer();
|
|
554
|
+
layer.setComponentName(l.componentName);
|
|
555
|
+
layer.setCutoffDimension(l.cutoffDimension);
|
|
556
|
+
layer.setStoreInRam(l.storeInRam);
|
|
557
|
+
layer.setRerankTopK(l.rerankTopK);
|
|
558
|
+
return layer;
|
|
559
|
+
});
|
|
560
|
+
protoSchema.setCascadePipelineList(pipeline);
|
|
561
|
+
req.setSchema(protoSchema);
|
|
253
562
|
this.client.createCollection(req, this.metadata, (err, resp) => {
|
|
254
563
|
if (err)
|
|
255
564
|
return reject(err);
|
|
@@ -268,22 +577,79 @@ class HyperspaceClient {
|
|
|
268
577
|
});
|
|
269
578
|
});
|
|
270
579
|
}
|
|
580
|
+
freezeCollection(name) {
|
|
581
|
+
return new Promise((resolve, reject) => {
|
|
582
|
+
const req = new hyperspace_pb.FreezeCollectionRequest();
|
|
583
|
+
req.setName(name);
|
|
584
|
+
this.client.freezeCollection(req, this.metadata, (err, resp) => {
|
|
585
|
+
if (err)
|
|
586
|
+
return reject(err);
|
|
587
|
+
resolve(resp.getStatus());
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
unfreezeCollection(name) {
|
|
592
|
+
return new Promise((resolve, reject) => {
|
|
593
|
+
const req = new hyperspace_pb.UnfreezeCollectionRequest();
|
|
594
|
+
req.setName(name);
|
|
595
|
+
this.client.unfreezeCollection(req, this.metadata, (err, resp) => {
|
|
596
|
+
if (err)
|
|
597
|
+
return reject(err);
|
|
598
|
+
resolve(resp.getStatus());
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
}
|
|
271
602
|
listCollections() {
|
|
272
603
|
return new Promise((resolve, reject) => {
|
|
273
604
|
const req = new hyperspace_pb_1.Empty();
|
|
274
605
|
this.client.listCollections(req, this.metadata, (err, resp) => {
|
|
275
606
|
if (err)
|
|
276
607
|
return reject(err);
|
|
277
|
-
const list = resp.getCollectionsList().map(c =>
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
608
|
+
const list = resp.getCollectionsList().map(c => {
|
|
609
|
+
const info = {
|
|
610
|
+
name: c.getName(),
|
|
611
|
+
count: c.getCount()
|
|
612
|
+
};
|
|
613
|
+
const protoSchema = c.getSchema();
|
|
614
|
+
if (protoSchema) {
|
|
615
|
+
info.schema = {
|
|
616
|
+
components: protoSchema.getComponentsList().map((comp) => ({
|
|
617
|
+
name: comp.getName(),
|
|
618
|
+
metric: comp.getMetric(),
|
|
619
|
+
fullDimension: comp.getFullDimension(),
|
|
620
|
+
weight: comp.getWeight()
|
|
621
|
+
})),
|
|
622
|
+
cascadePipeline: protoSchema.getCascadePipelineList().map((layer) => ({
|
|
623
|
+
componentName: layer.getComponentName(),
|
|
624
|
+
cutoffDimension: layer.getCutoffDimension(),
|
|
625
|
+
storeInRam: layer.getStoreInRam(),
|
|
626
|
+
rerankTopK: layer.getRerankTopK()
|
|
627
|
+
}))
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
return info;
|
|
631
|
+
});
|
|
283
632
|
resolve(list);
|
|
284
633
|
});
|
|
285
634
|
});
|
|
286
635
|
}
|
|
636
|
+
getPoints(ids, collection = '') {
|
|
637
|
+
return new Promise((resolve, reject) => {
|
|
638
|
+
const req = new hyperspace_pb_1.GetPointsRequest();
|
|
639
|
+
req.setCollection(collection);
|
|
640
|
+
req.setIdsList(ids);
|
|
641
|
+
this.client.getPoints(req, this.metadata, (err, resp) => {
|
|
642
|
+
if (err)
|
|
643
|
+
return reject(err);
|
|
644
|
+
const points = resp.getPointsList().map((p) => ({
|
|
645
|
+
id: p.getId(),
|
|
646
|
+
vector: p.getVectorList(),
|
|
647
|
+
metadata: p.getMetadataMap().toObject()
|
|
648
|
+
}));
|
|
649
|
+
resolve(points);
|
|
650
|
+
});
|
|
651
|
+
});
|
|
652
|
+
}
|
|
287
653
|
delete(id, collection = '') {
|
|
288
654
|
return new Promise((resolve, reject) => {
|
|
289
655
|
const req = new hyperspace_pb.DeleteRequest();
|
|
@@ -296,33 +662,87 @@ class HyperspaceClient {
|
|
|
296
662
|
});
|
|
297
663
|
});
|
|
298
664
|
}
|
|
299
|
-
insert(id, vector, meta, collection = '', durability = hyperspace_pb_1.DurabilityLevel.DEFAULT_LEVEL, typedMetadata)
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
665
|
+
insert(id, vector, meta, collection = '', durability = hyperspace_pb_1.DurabilityLevel.DEFAULT_LEVEL, typedMetadata, payload // Sidecar Payload Storage (v3.2)
|
|
666
|
+
) {
|
|
667
|
+
return new Promise(async (resolve, reject) => {
|
|
668
|
+
var _a;
|
|
669
|
+
try {
|
|
670
|
+
const req = new hyperspace_pb_1.InsertRequest();
|
|
671
|
+
let vectorList = HyperspaceClient.toVectorList(vector);
|
|
672
|
+
const metric = this.collectionMetrics[collection] || "l2";
|
|
673
|
+
const context = await this._getEncryptionContext(collection, vectorList.length, metric);
|
|
674
|
+
if (context) {
|
|
675
|
+
const sigma = (_a = this.collectionNoiseSigmas[collection]) !== null && _a !== void 0 ? _a : 0.02;
|
|
676
|
+
if (sigma > 0.0) {
|
|
677
|
+
vectorList = CognitiveMath.injectAnisotropicNoise(vectorList, context.hmacKey, sigma);
|
|
678
|
+
}
|
|
679
|
+
vectorList = this._projectCollectionVector(collection, vectorList, context, metric);
|
|
680
|
+
let rawPayload = null;
|
|
681
|
+
if (payload) {
|
|
682
|
+
rawPayload = Buffer.from(payload);
|
|
683
|
+
}
|
|
684
|
+
if (rawPayload) {
|
|
685
|
+
const encrypted = this.encryptPayload(rawPayload, context.aesKey);
|
|
686
|
+
req.setPayload(new Uint8Array(encrypted));
|
|
687
|
+
}
|
|
688
|
+
if (meta) {
|
|
689
|
+
const map = req.getMetadataMap();
|
|
690
|
+
for (const k in meta) {
|
|
691
|
+
const ek = this.hashMetadataKey(k, context.hmacKey);
|
|
692
|
+
const ev = this.hashMetadataValue(meta[k], context.hmacKey);
|
|
693
|
+
map.set(ek, ev);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
if (typedMetadata) {
|
|
697
|
+
const map = req.getTypedMetadataMap();
|
|
698
|
+
for (const k in typedMetadata) {
|
|
699
|
+
const ek = this.hashMetadataKey(k, context.hmacKey);
|
|
700
|
+
const ev = this.hashMetadataValue(String(typedMetadata[k]), context.hmacKey);
|
|
701
|
+
map.set(ek, HyperspaceClient.toProtoMetadataValue(ev));
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
if (meta) {
|
|
707
|
+
const map = req.getMetadataMap();
|
|
708
|
+
for (const k in meta)
|
|
709
|
+
map.set(k, meta[k]);
|
|
710
|
+
}
|
|
711
|
+
if (typedMetadata) {
|
|
712
|
+
const map = req.getTypedMetadataMap();
|
|
713
|
+
for (const k in typedMetadata)
|
|
714
|
+
map.set(k, HyperspaceClient.toProtoMetadataValue(typedMetadata[k]));
|
|
715
|
+
}
|
|
716
|
+
if (payload) {
|
|
717
|
+
req.setPayload(payload);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
req.setVectorList(vectorList);
|
|
721
|
+
req.setId(id);
|
|
722
|
+
req.setCollection(collection);
|
|
723
|
+
req.setOriginNodeId('');
|
|
724
|
+
req.setLogicalClock(0);
|
|
725
|
+
req.setDurability(durability);
|
|
726
|
+
this.client.insert(req, this.metadata, (err, resp) => {
|
|
727
|
+
if (err)
|
|
728
|
+
return reject(err);
|
|
729
|
+
resolve(resp.getSuccess());
|
|
730
|
+
});
|
|
308
731
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
for (const k in typedMetadata)
|
|
312
|
-
map.set(k, HyperspaceClient.toProtoMetadataValue(typedMetadata[k]));
|
|
732
|
+
catch (e) {
|
|
733
|
+
reject(e);
|
|
313
734
|
}
|
|
314
|
-
req.setCollection(collection);
|
|
315
|
-
req.setOriginNodeId('');
|
|
316
|
-
req.setLogicalClock(0);
|
|
317
|
-
req.setDurability(durability);
|
|
318
|
-
this.client.insert(req, this.metadata, (err, resp) => {
|
|
319
|
-
if (err)
|
|
320
|
-
return reject(err);
|
|
321
|
-
resolve(resp.getSuccess());
|
|
322
|
-
});
|
|
323
735
|
});
|
|
324
736
|
}
|
|
325
737
|
insertText(id, text, meta, collection = '', durability = hyperspace_pb_1.DurabilityLevel.DEFAULT_LEVEL) {
|
|
738
|
+
if (this.collectionKeys[collection]) {
|
|
739
|
+
if (!this.embedder) {
|
|
740
|
+
return Promise.reject(new Error("An embedder must be configured to use insertText on encrypted collections."));
|
|
741
|
+
}
|
|
742
|
+
return Promise.resolve(this.embedder.encode(text)).then(vector => {
|
|
743
|
+
return this.insert(id, vector, meta, collection, durability, undefined, Buffer.from(text, 'utf-8'));
|
|
744
|
+
});
|
|
745
|
+
}
|
|
326
746
|
return new Promise((resolve, reject) => {
|
|
327
747
|
const req = new hyperspace_pb_1.InsertTextRequest();
|
|
328
748
|
req.setText(text);
|
|
@@ -383,126 +803,145 @@ class HyperspaceClient {
|
|
|
383
803
|
});
|
|
384
804
|
}
|
|
385
805
|
search(vector, topK, collection = '', options) {
|
|
386
|
-
return new Promise((resolve, reject) => {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
806
|
+
return new Promise(async (resolve, reject) => {
|
|
807
|
+
var _a;
|
|
808
|
+
try {
|
|
809
|
+
const req = new hyperspace_pb_1.SearchRequest();
|
|
810
|
+
let vectorList = HyperspaceClient.toVectorList(vector);
|
|
811
|
+
req.setTopK(topK);
|
|
812
|
+
req.setCollection(collection);
|
|
813
|
+
const metric = this.collectionMetrics[collection] || "l2";
|
|
814
|
+
const context = await this._getEncryptionContext(collection, vectorList.length, metric);
|
|
815
|
+
let optFilters = options === null || options === void 0 ? void 0 : options.filters;
|
|
816
|
+
let optFilter = options === null || options === void 0 ? void 0 : options.filter;
|
|
817
|
+
let includePayload = options === null || options === void 0 ? void 0 : options.includePayload;
|
|
818
|
+
if (context) {
|
|
819
|
+
const sigma = (_a = this.collectionNoiseSigmas[collection]) !== null && _a !== void 0 ? _a : 0.02;
|
|
820
|
+
if (sigma > 0.0) {
|
|
821
|
+
vectorList = CognitiveMath.injectAnisotropicNoise(vectorList, context.hmacKey, sigma);
|
|
399
822
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
r.setGteF64(f.range.gte);
|
|
823
|
+
vectorList = this._projectCollectionVector(collection, vectorList, context, metric);
|
|
824
|
+
if (optFilter) {
|
|
825
|
+
const hashedFilter = {};
|
|
826
|
+
for (const k in optFilter) {
|
|
827
|
+
const ek = this.hashMetadataKey(k, context.hmacKey);
|
|
828
|
+
const ev = this.hashMetadataValue(optFilter[k], context.hmacKey);
|
|
829
|
+
hashedFilter[ek] = ev;
|
|
408
830
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
831
|
+
optFilter = hashedFilter;
|
|
832
|
+
}
|
|
833
|
+
if (optFilters) {
|
|
834
|
+
optFilters = this._encryptFilters(optFilters, context);
|
|
835
|
+
}
|
|
836
|
+
includePayload = true;
|
|
837
|
+
}
|
|
838
|
+
req.setVectorList(vectorList);
|
|
839
|
+
if (optFilter) {
|
|
840
|
+
const map = req.getFilterMap();
|
|
841
|
+
for (const k in optFilter) {
|
|
842
|
+
map.set(k, optFilter[k]);
|
|
416
843
|
}
|
|
417
|
-
|
|
844
|
+
}
|
|
845
|
+
if ((options === null || options === void 0 ? void 0 : options.restartFactor) !== undefined) {
|
|
846
|
+
const map = req.getFilterMap();
|
|
847
|
+
map.set('wave_restart_factor', options.restartFactor.toString());
|
|
848
|
+
}
|
|
849
|
+
if ((options === null || options === void 0 ? void 0 : options.useWave) !== undefined) {
|
|
850
|
+
req.setUseWave(options.useWave);
|
|
851
|
+
}
|
|
852
|
+
if (optFilters) {
|
|
853
|
+
req.setFiltersList(optFilters.map(f => this.toProtoFilter(f)));
|
|
854
|
+
}
|
|
855
|
+
if (options === null || options === void 0 ? void 0 : options.hybridQuery)
|
|
856
|
+
req.setHybridQuery(options.hybridQuery);
|
|
857
|
+
if ((options === null || options === void 0 ? void 0 : options.hybridAlpha) !== undefined)
|
|
858
|
+
req.setHybridAlpha(options.hybridAlpha);
|
|
859
|
+
if ((options === null || options === void 0 ? void 0 : options.mrlDimension) !== undefined)
|
|
860
|
+
req.setMrlDimension(options.mrlDimension);
|
|
861
|
+
if ((options === null || options === void 0 ? void 0 : options.useWasserstein) !== undefined)
|
|
862
|
+
req.setUseWasserstein(options.useWasserstein);
|
|
863
|
+
if (includePayload !== undefined)
|
|
864
|
+
req.setIncludePayload(includePayload);
|
|
865
|
+
if (options === null || options === void 0 ? void 0 : options.componentWeights) {
|
|
866
|
+
const map = req.getComponentWeightsMap();
|
|
867
|
+
for (const k in options.componentWeights) {
|
|
868
|
+
map.set(k, options.componentWeights[k]);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
if (options === null || options === void 0 ? void 0 : options.bm25) {
|
|
872
|
+
const bm25Msg = new hyperspace_pb_1.Bm25Options();
|
|
873
|
+
if (options.bm25.method !== undefined)
|
|
874
|
+
bm25Msg.setMethod(options.bm25.method);
|
|
875
|
+
if (options.bm25.k1 !== undefined)
|
|
876
|
+
bm25Msg.setK1(options.bm25.k1);
|
|
877
|
+
if (options.bm25.b !== undefined)
|
|
878
|
+
bm25Msg.setB(options.bm25.b);
|
|
879
|
+
if (options.bm25.delta !== undefined)
|
|
880
|
+
bm25Msg.setDelta(options.bm25.delta);
|
|
881
|
+
if (options.bm25.language !== undefined)
|
|
882
|
+
bm25Msg.setLanguage(options.bm25.language);
|
|
883
|
+
if (options.bm25.ngrams !== undefined)
|
|
884
|
+
bm25Msg.setNgrams(options.bm25.ngrams);
|
|
885
|
+
if (options.bm25.fusionMethod !== undefined)
|
|
886
|
+
bm25Msg.setFusionMethod(options.bm25.fusionMethod);
|
|
887
|
+
req.setBm25Options(bm25Msg);
|
|
888
|
+
}
|
|
889
|
+
this.client.search(req, this.metadata, (err, resp) => {
|
|
890
|
+
if (err)
|
|
891
|
+
return reject(err);
|
|
892
|
+
const results = resp.getResultsList().map(r => {
|
|
893
|
+
const metaMap = r.getMetadataMap();
|
|
894
|
+
const meta = {};
|
|
895
|
+
if (metaMap.getLength() > 0) {
|
|
896
|
+
metaMap.forEach((entry, key) => {
|
|
897
|
+
meta[key] = entry;
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
let payloadBytes = r.getPayload_asU8();
|
|
901
|
+
if (context && payloadBytes && payloadBytes.length > 0) {
|
|
902
|
+
try {
|
|
903
|
+
const decrypted = this.decryptPayload(Buffer.from(payloadBytes), context.aesKey);
|
|
904
|
+
payloadBytes = new Uint8Array(decrypted);
|
|
905
|
+
}
|
|
906
|
+
catch (e) {
|
|
907
|
+
// Decryption error
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
return {
|
|
911
|
+
id: r.getId(),
|
|
912
|
+
distance: r.getDistance(),
|
|
913
|
+
metadata: meta,
|
|
914
|
+
typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap()),
|
|
915
|
+
payload: payloadBytes
|
|
916
|
+
};
|
|
917
|
+
});
|
|
918
|
+
resolve(results);
|
|
418
919
|
});
|
|
419
|
-
req.setFiltersList(protoFilters);
|
|
420
920
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
if ((options === null || options === void 0 ? void 0 : options.hybridAlpha) !== undefined)
|
|
424
|
-
req.setHybridAlpha(options.hybridAlpha);
|
|
425
|
-
if (options === null || options === void 0 ? void 0 : options.bm25) {
|
|
426
|
-
// @ts-ignore: Bm25Options might not be in generated proto yet
|
|
427
|
-
const bm25Msg = new hyperspace_pb.Bm25Options();
|
|
428
|
-
if (options.bm25.method !== undefined)
|
|
429
|
-
bm25Msg.setMethod(options.bm25.method);
|
|
430
|
-
if (options.bm25.k1 !== undefined)
|
|
431
|
-
bm25Msg.setK1(options.bm25.k1);
|
|
432
|
-
if (options.bm25.b !== undefined)
|
|
433
|
-
bm25Msg.setB(options.bm25.b);
|
|
434
|
-
if (options.bm25.delta !== undefined)
|
|
435
|
-
bm25Msg.setDelta(options.bm25.delta);
|
|
436
|
-
if (options.bm25.language !== undefined)
|
|
437
|
-
bm25Msg.setLanguage(options.bm25.language);
|
|
438
|
-
if (options.bm25.ngrams !== undefined)
|
|
439
|
-
bm25Msg.setNgrams(options.bm25.ngrams);
|
|
440
|
-
if (options.bm25.fusionMethod !== undefined)
|
|
441
|
-
bm25Msg.setFusionMethod(options.bm25.fusionMethod);
|
|
442
|
-
// @ts-ignore
|
|
443
|
-
req.setBm25Options(bm25Msg);
|
|
921
|
+
catch (e) {
|
|
922
|
+
reject(e);
|
|
444
923
|
}
|
|
445
|
-
this.client.search(req, this.metadata, (err, resp) => {
|
|
446
|
-
if (err)
|
|
447
|
-
return reject(err);
|
|
448
|
-
const results = resp.getResultsList().map(r => {
|
|
449
|
-
const metaMap = r.getMetadataMap();
|
|
450
|
-
const meta = {};
|
|
451
|
-
if (metaMap.getLength() > 0) {
|
|
452
|
-
metaMap.forEach((entry, key) => {
|
|
453
|
-
meta[key] = entry;
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
return {
|
|
457
|
-
id: r.getId(),
|
|
458
|
-
distance: r.getDistance(),
|
|
459
|
-
metadata: meta,
|
|
460
|
-
typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap())
|
|
461
|
-
};
|
|
462
|
-
});
|
|
463
|
-
resolve(results);
|
|
464
|
-
});
|
|
465
924
|
});
|
|
466
925
|
}
|
|
467
926
|
searchText(text, topK, collection = '', options) {
|
|
927
|
+
if (this.collectionKeys[collection]) {
|
|
928
|
+
if (!this.embedder) {
|
|
929
|
+
return Promise.reject(new Error("An embedder must be configured to use searchText on encrypted collections."));
|
|
930
|
+
}
|
|
931
|
+
return Promise.resolve(this.embedder.encode(text)).then(vector => {
|
|
932
|
+
return this.search(vector, topK, collection, options);
|
|
933
|
+
});
|
|
934
|
+
}
|
|
468
935
|
return new Promise((resolve, reject) => {
|
|
469
936
|
const req = new hyperspace_pb_1.SearchTextRequest();
|
|
470
937
|
req.setText(text);
|
|
471
938
|
req.setTopK(topK);
|
|
472
939
|
req.setCollection(collection);
|
|
473
940
|
if (options === null || options === void 0 ? void 0 : options.filters) {
|
|
474
|
-
|
|
475
|
-
const pf = new hyperspace_pb.Filter();
|
|
476
|
-
if (f.match) {
|
|
477
|
-
const m = new hyperspace_pb.Match();
|
|
478
|
-
m.setKey(f.match.key);
|
|
479
|
-
m.setValue(f.match.value);
|
|
480
|
-
pf.setMatch(m);
|
|
481
|
-
}
|
|
482
|
-
else if (f.range) {
|
|
483
|
-
const r = new hyperspace_pb.Range();
|
|
484
|
-
r.setKey(f.range.key);
|
|
485
|
-
if (f.range.gte !== undefined) {
|
|
486
|
-
if (Number.isInteger(f.range.gte))
|
|
487
|
-
r.setGte(f.range.gte);
|
|
488
|
-
else
|
|
489
|
-
r.setGteF64(f.range.gte);
|
|
490
|
-
}
|
|
491
|
-
if (f.range.lte !== undefined) {
|
|
492
|
-
if (Number.isInteger(f.range.lte))
|
|
493
|
-
r.setLte(f.range.lte);
|
|
494
|
-
else
|
|
495
|
-
r.setLteF64(f.range.lte);
|
|
496
|
-
}
|
|
497
|
-
pf.setRange(r);
|
|
498
|
-
}
|
|
499
|
-
return pf;
|
|
500
|
-
});
|
|
501
|
-
req.setFiltersList(protoFilters);
|
|
941
|
+
req.setFiltersList(options.filters.map(f => this.toProtoFilter(f)));
|
|
502
942
|
}
|
|
503
943
|
if (options === null || options === void 0 ? void 0 : options.bm25) {
|
|
504
|
-
|
|
505
|
-
const bm25Msg = new hyperspace_pb.Bm25Options();
|
|
944
|
+
const bm25Msg = new hyperspace_pb_1.Bm25Options();
|
|
506
945
|
if (options.bm25.method !== undefined)
|
|
507
946
|
bm25Msg.setMethod(options.bm25.method);
|
|
508
947
|
if (options.bm25.k1 !== undefined)
|
|
@@ -517,13 +956,14 @@ class HyperspaceClient {
|
|
|
517
956
|
bm25Msg.setNgrams(options.bm25.ngrams);
|
|
518
957
|
if (options.bm25.fusionMethod !== undefined)
|
|
519
958
|
bm25Msg.setFusionMethod(options.bm25.fusionMethod);
|
|
520
|
-
// @ts-ignore
|
|
521
959
|
req.setBm25Options(bm25Msg);
|
|
522
960
|
}
|
|
523
961
|
if ((options === null || options === void 0 ? void 0 : options.hybridAlpha) !== undefined) {
|
|
524
|
-
// @ts-ignore
|
|
525
962
|
req.setHybridAlpha(options.hybridAlpha);
|
|
526
963
|
}
|
|
964
|
+
if ((options === null || options === void 0 ? void 0 : options.includePayload) !== undefined) {
|
|
965
|
+
req.setIncludePayload(options.includePayload);
|
|
966
|
+
}
|
|
527
967
|
this.client.searchText(req, this.metadata, (err, resp) => {
|
|
528
968
|
if (err)
|
|
529
969
|
return reject(err);
|
|
@@ -539,7 +979,8 @@ class HyperspaceClient {
|
|
|
539
979
|
id: r.getId(),
|
|
540
980
|
distance: r.getDistance(),
|
|
541
981
|
metadata: meta,
|
|
542
|
-
typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap())
|
|
982
|
+
typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap()),
|
|
983
|
+
payload: r.getPayload_asU8()
|
|
543
984
|
};
|
|
544
985
|
});
|
|
545
986
|
resolve(results);
|
|
@@ -571,7 +1012,8 @@ class HyperspaceClient {
|
|
|
571
1012
|
id: r.getId(),
|
|
572
1013
|
distance: r.getDistance(),
|
|
573
1014
|
metadata: meta,
|
|
574
|
-
typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap())
|
|
1015
|
+
typedMetadata: HyperspaceClient.parseTypedMetadata(r.getTypedMetadataMap()),
|
|
1016
|
+
payload: r.getPayload_asU8()
|
|
575
1017
|
};
|
|
576
1018
|
}));
|
|
577
1019
|
resolve(batch);
|
|
@@ -722,34 +1164,7 @@ class HyperspaceClient {
|
|
|
722
1164
|
}
|
|
723
1165
|
}
|
|
724
1166
|
if (options === null || options === void 0 ? void 0 : options.filters) {
|
|
725
|
-
|
|
726
|
-
const pf = new hyperspace_pb.Filter();
|
|
727
|
-
if (f.match) {
|
|
728
|
-
const m = new hyperspace_pb.Match();
|
|
729
|
-
m.setKey(f.match.key);
|
|
730
|
-
m.setValue(f.match.value);
|
|
731
|
-
pf.setMatch(m);
|
|
732
|
-
}
|
|
733
|
-
else if (f.range) {
|
|
734
|
-
const r = new hyperspace_pb.Range();
|
|
735
|
-
r.setKey(f.range.key);
|
|
736
|
-
if (f.range.gte !== undefined) {
|
|
737
|
-
if (Number.isInteger(f.range.gte))
|
|
738
|
-
r.setGte(f.range.gte);
|
|
739
|
-
else
|
|
740
|
-
r.setGteF64(f.range.gte);
|
|
741
|
-
}
|
|
742
|
-
if (f.range.lte !== undefined) {
|
|
743
|
-
if (Number.isInteger(f.range.lte))
|
|
744
|
-
r.setLte(f.range.lte);
|
|
745
|
-
else
|
|
746
|
-
r.setLteF64(f.range.lte);
|
|
747
|
-
}
|
|
748
|
-
pf.setRange(r);
|
|
749
|
-
}
|
|
750
|
-
return pf;
|
|
751
|
-
});
|
|
752
|
-
req.setFiltersList(protoFilters);
|
|
1167
|
+
req.setFiltersList(options.filters.map(f => this.toProtoFilter(f)));
|
|
753
1168
|
}
|
|
754
1169
|
this.client.traverse(req, this.metadata, (err, resp) => {
|
|
755
1170
|
if (err)
|
|
@@ -836,6 +1251,251 @@ class HyperspaceClient {
|
|
|
836
1251
|
}
|
|
837
1252
|
return stream;
|
|
838
1253
|
}
|
|
1254
|
+
getCollectionStats(name) {
|
|
1255
|
+
return new Promise((resolve, reject) => {
|
|
1256
|
+
const req = new hyperspace_pb_1.CollectionStatsRequest();
|
|
1257
|
+
req.setName(name);
|
|
1258
|
+
this.client.getCollectionStats(req, this.metadata, (err, resp) => {
|
|
1259
|
+
if (err)
|
|
1260
|
+
return reject(err);
|
|
1261
|
+
const stats = {
|
|
1262
|
+
count: resp.getCount(),
|
|
1263
|
+
indexingQueue: resp.getIndexingQueue(),
|
|
1264
|
+
diskUsageBytes: resp.getDiskUsageBytes(),
|
|
1265
|
+
ramUsageBytes: resp.getRamUsageBytes(),
|
|
1266
|
+
activeTasks: resp.getActiveTasks()
|
|
1267
|
+
};
|
|
1268
|
+
const protoSchema = resp.getSchema();
|
|
1269
|
+
if (protoSchema) {
|
|
1270
|
+
stats.schema = {
|
|
1271
|
+
components: protoSchema.getComponentsList().map((comp) => ({
|
|
1272
|
+
name: comp.getName(),
|
|
1273
|
+
metric: comp.getMetric(),
|
|
1274
|
+
fullDimension: comp.getFullDimension(),
|
|
1275
|
+
weight: comp.getWeight()
|
|
1276
|
+
})),
|
|
1277
|
+
cascadePipeline: protoSchema.getCascadePipelineList().map((layer) => ({
|
|
1278
|
+
componentName: layer.getComponentName(),
|
|
1279
|
+
cutoffDimension: layer.getCutoffDimension(),
|
|
1280
|
+
storeInRam: layer.getStoreInRam(),
|
|
1281
|
+
rerankTopK: layer.getRerankTopK()
|
|
1282
|
+
}))
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
resolve(stats);
|
|
1286
|
+
});
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
async exists(name) {
|
|
1290
|
+
try {
|
|
1291
|
+
await this.getCollectionStats(name);
|
|
1292
|
+
return true;
|
|
1293
|
+
}
|
|
1294
|
+
catch (e) {
|
|
1295
|
+
if (e.code === grpc.status.NOT_FOUND || (e.message && e.message.includes('not found'))) {
|
|
1296
|
+
return false;
|
|
1297
|
+
}
|
|
1298
|
+
throw e;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
async getCacheStats(name) {
|
|
1302
|
+
const ip = this.host.split(':')[0];
|
|
1303
|
+
const url = `http://${ip}:50050/api/collections/${name}/cache/stats`;
|
|
1304
|
+
const headers = {};
|
|
1305
|
+
if (this.apiKey)
|
|
1306
|
+
headers['x-api-key'] = this.apiKey;
|
|
1307
|
+
if (this.userId)
|
|
1308
|
+
headers['x-hyperspace-user-id'] = this.userId;
|
|
1309
|
+
const res = await fetch(url, { headers });
|
|
1310
|
+
if (!res.ok) {
|
|
1311
|
+
throw new Error(`Failed to get cache stats: ${res.statusText} (${await res.text()})`);
|
|
1312
|
+
}
|
|
1313
|
+
return res.json();
|
|
1314
|
+
}
|
|
1315
|
+
async clearCache(name) {
|
|
1316
|
+
const ip = this.host.split(':')[0];
|
|
1317
|
+
const url = `http://${ip}:50050/api/collections/${name}/cache/clear`;
|
|
1318
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
1319
|
+
if (this.apiKey)
|
|
1320
|
+
headers['x-api-key'] = this.apiKey;
|
|
1321
|
+
if (this.userId)
|
|
1322
|
+
headers['x-hyperspace-user-id'] = this.userId;
|
|
1323
|
+
const res = await fetch(url, {
|
|
1324
|
+
method: 'POST',
|
|
1325
|
+
headers,
|
|
1326
|
+
body: JSON.stringify({})
|
|
1327
|
+
});
|
|
1328
|
+
if (!res.ok) {
|
|
1329
|
+
throw new Error(`Failed to clear cache: ${res.statusText} (${await res.text()})`);
|
|
1330
|
+
}
|
|
1331
|
+
const data = await res.json();
|
|
1332
|
+
return data.status === 'success';
|
|
1333
|
+
}
|
|
1334
|
+
async updateCacheConfig(name, policy, annThreshold) {
|
|
1335
|
+
const ip = this.host.split(':')[0];
|
|
1336
|
+
const url = `http://${ip}:50050/api/collections/${name}/cache/config`;
|
|
1337
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
1338
|
+
if (this.apiKey)
|
|
1339
|
+
headers['x-api-key'] = this.apiKey;
|
|
1340
|
+
if (this.userId)
|
|
1341
|
+
headers['x-hyperspace-user-id'] = this.userId;
|
|
1342
|
+
const res = await fetch(url, {
|
|
1343
|
+
method: 'POST',
|
|
1344
|
+
headers,
|
|
1345
|
+
body: JSON.stringify({
|
|
1346
|
+
policy,
|
|
1347
|
+
ann_threshold: annThreshold
|
|
1348
|
+
})
|
|
1349
|
+
});
|
|
1350
|
+
if (!res.ok) {
|
|
1351
|
+
throw new Error(`Failed to update cache config: ${res.statusText} (${await res.text()})`);
|
|
1352
|
+
}
|
|
1353
|
+
const data = await res.json();
|
|
1354
|
+
return data.status === 'success';
|
|
1355
|
+
}
|
|
1356
|
+
updateCollection(name, config) {
|
|
1357
|
+
return new Promise((resolve, reject) => {
|
|
1358
|
+
const req = new hyperspace_pb_1.ConfigUpdate();
|
|
1359
|
+
req.setCollection(name);
|
|
1360
|
+
if (config.efSearch !== undefined)
|
|
1361
|
+
req.setEfSearch(config.efSearch);
|
|
1362
|
+
if (config.efConstruction !== undefined)
|
|
1363
|
+
req.setEfConstruction(config.efConstruction);
|
|
1364
|
+
if (config.m !== undefined)
|
|
1365
|
+
req.setM(config.m);
|
|
1366
|
+
this.client.configure(req, this.metadata, (err, resp) => {
|
|
1367
|
+
if (err)
|
|
1368
|
+
return reject(err);
|
|
1369
|
+
resolve(resp.getStatus() === 'success' || (!!resp.getStatus() && resp.getStatus().includes('updated')));
|
|
1370
|
+
});
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
createSnapshot() {
|
|
1374
|
+
return new Promise((resolve, reject) => {
|
|
1375
|
+
this.client.triggerSnapshot(new hyperspace_pb_1.Empty(), this.metadata, (err, resp) => {
|
|
1376
|
+
if (err)
|
|
1377
|
+
return reject(err);
|
|
1378
|
+
resolve(resp.getStatus() === 'success');
|
|
1379
|
+
});
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
vacuum() {
|
|
1383
|
+
return new Promise((resolve, reject) => {
|
|
1384
|
+
this.client.triggerVacuum(new hyperspace_pb_1.Empty(), this.metadata, (err, resp) => {
|
|
1385
|
+
if (err)
|
|
1386
|
+
return reject(err);
|
|
1387
|
+
resolve(resp.getStatus() === 'success');
|
|
1388
|
+
});
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
getMetrics(onData, onError) {
|
|
1392
|
+
const req = new hyperspace_pb_1.MonitorRequest();
|
|
1393
|
+
const stream = this.client.monitor(req, this.metadata);
|
|
1394
|
+
stream.on('data', onData);
|
|
1395
|
+
if (onError) {
|
|
1396
|
+
stream.on('error', onError);
|
|
1397
|
+
}
|
|
1398
|
+
return stream;
|
|
1399
|
+
}
|
|
1400
|
+
searchMultiCollection(collections, query) {
|
|
1401
|
+
return new Promise((resolve, reject) => {
|
|
1402
|
+
const req = new hyperspace_pb_1.SearchMultiCollectionRequest();
|
|
1403
|
+
req.setCollectionsList(collections);
|
|
1404
|
+
req.setVectorList(HyperspaceClient.toVectorList(query));
|
|
1405
|
+
req.setTopK(10);
|
|
1406
|
+
this.client.searchMultiCollection(req, this.metadata, (err, resp) => {
|
|
1407
|
+
if (err)
|
|
1408
|
+
return reject(err);
|
|
1409
|
+
resolve(resp.toObject());
|
|
1410
|
+
});
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
triggerReconsolidation(collection, targetVector, learningRate = 0.01) {
|
|
1414
|
+
return new Promise((resolve, reject) => {
|
|
1415
|
+
const req = new hyperspace_pb_1.ReconsolidationRequest();
|
|
1416
|
+
req.setCollection(collection);
|
|
1417
|
+
req.setTargetVectorList(targetVector);
|
|
1418
|
+
req.setLearningRate(learningRate);
|
|
1419
|
+
this.client.triggerReconsolidation(req, this.metadata, (err, resp) => {
|
|
1420
|
+
if (err)
|
|
1421
|
+
return reject(err);
|
|
1422
|
+
resolve(resp.getStatus() === 'success');
|
|
1423
|
+
});
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
getSubsumptionTree(rootId, maxDepth = 3, collection = '') {
|
|
1427
|
+
return new Promise((resolve, reject) => {
|
|
1428
|
+
const req = new hyperspace_pb.GetSubsumptionTreeRequest();
|
|
1429
|
+
req.setRootId(rootId);
|
|
1430
|
+
req.setMaxDepth(maxDepth);
|
|
1431
|
+
req.setCollection(collection);
|
|
1432
|
+
this.client.getSubsumptionTree(req, this.metadata, (err, resp) => {
|
|
1433
|
+
if (err)
|
|
1434
|
+
return reject(err);
|
|
1435
|
+
const nodes = resp.getNodesList().map((n) => ({
|
|
1436
|
+
id: n.getId(),
|
|
1437
|
+
metadata: n.getMetadataMap().toObject(),
|
|
1438
|
+
edgeTypes: n.getEdgeTypesList()
|
|
1439
|
+
}));
|
|
1440
|
+
resolve(nodes);
|
|
1441
|
+
});
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
async exploreGraph(startId, maxDepth = 2, maxNodes = 256, collection = '') {
|
|
1445
|
+
const req = new hyperspace_pb_1.TraverseRequest();
|
|
1446
|
+
req.setStartId(startId);
|
|
1447
|
+
req.setMaxDepth(maxDepth);
|
|
1448
|
+
req.setMaxNodes(maxNodes);
|
|
1449
|
+
req.setCollection(collection);
|
|
1450
|
+
req.setTraversalMode(1); // DIFFUSIVE
|
|
1451
|
+
req.setBreadthLimit(10);
|
|
1452
|
+
return new Promise((resolve, reject) => {
|
|
1453
|
+
this.client.traverse(req, this.metadata, (err, resp) => {
|
|
1454
|
+
if (err)
|
|
1455
|
+
return reject(err);
|
|
1456
|
+
const nodes = resp.getNodesList().map((n) => ({
|
|
1457
|
+
id: n.getId(),
|
|
1458
|
+
metadata: n.getMetadataMap().toObject(),
|
|
1459
|
+
edgeTypes: n.getEdgeTypesList(),
|
|
1460
|
+
neighbors: n.getNeighborsList()
|
|
1461
|
+
}));
|
|
1462
|
+
resolve({
|
|
1463
|
+
nodes,
|
|
1464
|
+
centerId: startId,
|
|
1465
|
+
count: nodes.length
|
|
1466
|
+
});
|
|
1467
|
+
});
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
async predictMomentum(trajectoryIds, steps = 1.0, collection = '', curvature = 1.0) {
|
|
1471
|
+
if (trajectoryIds.length < 2)
|
|
1472
|
+
return [];
|
|
1473
|
+
const pts = await this.getPoints(trajectoryIds, collection);
|
|
1474
|
+
const idToVec = new Map();
|
|
1475
|
+
pts.forEach(p => idToVec.set(p.id, p.vector));
|
|
1476
|
+
const vectors = trajectoryIds.map(id => idToVec.get(id)).filter(v => !!v);
|
|
1477
|
+
if (vectors.length < 2)
|
|
1478
|
+
return [];
|
|
1479
|
+
const past = vectors[vectors.length - 2];
|
|
1480
|
+
const current = vectors[vectors.length - 1];
|
|
1481
|
+
const { koopmanExtrapolate } = require('./math');
|
|
1482
|
+
return koopmanExtrapolate(past, current, steps, curvature);
|
|
1483
|
+
}
|
|
1484
|
+
async getTrustScore(trajectoryIds, collection = '', curvature = 1.0) {
|
|
1485
|
+
const pts = await this.getPoints(trajectoryIds, collection);
|
|
1486
|
+
const idToVec = new Map();
|
|
1487
|
+
pts.forEach(p => idToVec.set(p.id, p.vector));
|
|
1488
|
+
const vectors = trajectoryIds.map(id => idToVec.get(id)).filter(v => !!v);
|
|
1489
|
+
if (vectors.length < 3)
|
|
1490
|
+
return 0.0;
|
|
1491
|
+
const { lyapunovConvergence } = require('./math');
|
|
1492
|
+
try {
|
|
1493
|
+
return lyapunovConvergence(vectors, curvature);
|
|
1494
|
+
}
|
|
1495
|
+
catch (e) {
|
|
1496
|
+
return 1.0;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
839
1499
|
close() {
|
|
840
1500
|
this.client.close();
|
|
841
1501
|
}
|