sliftutils 1.4.86 → 1.4.87

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/index.d.ts CHANGED
@@ -2393,7 +2393,7 @@ declare module "sliftutils/storage/proxydatabase/ivfEmbeddingDatabase" {
2393
2393
  };
2394
2394
  export declare function rebuildStructure(database: Database<IvfEmbeddingRoot>): void;
2395
2395
  export declare function searchEmbeddings(database: Database<IvfEmbeddingRoot>, query: StoredEmbedding, options: {
2396
- probeBudget: number;
2396
+ probeCellCount: number;
2397
2397
  resultCount: number;
2398
2398
  }): SearchHit[] | undefined;
2399
2399
  export declare function lookupEmbeddings(database: Database<IvfEmbeddingRoot>, refs: string[]): Map<string, StoredEmbedding> | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "1.4.86",
3
+ "version": "1.4.87",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -72,7 +72,7 @@ async function main() {
72
72
  const sampleCount = 100;
73
73
  for (let index = 0; index < sampleCount; index++) {
74
74
  const query = allInputs[Math.floor(index * run.size / sampleCount)];
75
- const hits = searchEmbeddings(database, query.embedding, { probeBudget: 512, resultCount: 1 });
75
+ const hits = searchEmbeddings(database, query.embedding, { probeCellCount: 64, resultCount: 1 });
76
76
  if (hits && hits.length && hits[0].ref === query.ref) {
77
77
  found++;
78
78
  }
@@ -31,7 +31,7 @@ export type SearchHit = {
31
31
  };
32
32
  export declare function rebuildStructure(database: Database<IvfEmbeddingRoot>): void;
33
33
  export declare function searchEmbeddings(database: Database<IvfEmbeddingRoot>, query: StoredEmbedding, options: {
34
- probeBudget: number;
34
+ probeCellCount: number;
35
35
  resultCount: number;
36
36
  }): SearchHit[] | undefined;
37
37
  export declare function lookupEmbeddings(database: Database<IvfEmbeddingRoot>, refs: string[]): Map<string, StoredEmbedding> | undefined;
@@ -218,7 +218,8 @@ export function rebuildStructure(database: Database<IvfEmbeddingRoot>): void {
218
218
  export function searchEmbeddings(
219
219
  database: Database<IvfEmbeddingRoot>,
220
220
  query: StoredEmbedding,
221
- options: { probeBudget: number; resultCount: number },
221
+ // NOTE: We do a progressive search, so probe cell count can be very high.
222
+ options: { probeCellCount: number; resultCount: number },
222
223
  ): SearchHit[] | undefined {
223
224
  const config = database.readData(root => root.config);
224
225
  if (!config) return undefined;
@@ -239,13 +240,36 @@ export function searchEmbeddings(
239
240
  const centroids = transactionRead(centroidStore(database));
240
241
  if (!centroids) return undefined;
241
242
  if (!centroids.size) return [];
242
- const probeCellCount = Math.max(1, Math.ceil(options.probeBudget / config.cellTargetSize));
243
- const probeCellIds = rankCellsByCloseness(query, centroids).slice(0, probeCellCount);
244
- const stores = probeCellIds.map(cellId => database.readData(root => root.cells[cellId])).filter(isDefined);
243
+ const probeCellCount = Math.min(centroids.size, options.probeCellCount);
244
+
245
+ let rankedCellIds = rankCellsByCloseness(query, centroids);
246
+ let stores: TransactionSetStore<StoredEmbedding>[] = [];
247
+ // A somewhat strange search, trying to load more and more data. The reason we can't load everything at once is because the server has no way of knowing what we want first, and so it'll just wait until it can give us everything at once. By waiting until all of the earlier values load before even requesting the later values, it means that we will receive the earlier values sooner. Which will result in the search immediately returning results with very few accesses, And then the results improving in quality as time goes on, which is very desirable.
248
+ {
249
+ let stopAtNextKeyPoint = false;
250
+ let keyPoints: number[] = [];
251
+ let currentProbeAdd = 4;
252
+ let currentTarget = currentProbeAdd;
253
+ while (currentTarget < probeCellCount) {
254
+ keyPoints.push(currentTarget);
255
+ currentTarget += currentProbeAdd;
256
+ currentProbeAdd *= 2;
257
+ }
258
+ for (let i = 0; i < probeCellCount; i++) {
259
+ if (keyPoints.includes(i) && stopAtNextKeyPoint) break;
260
+ let store = database.readData(root => root.cells[rankedCellIds[i]]);
261
+ if (!store) {
262
+ stopAtNextKeyPoint = true;
263
+ continue;
264
+ }
265
+ stores.push(store);
266
+ }
267
+ }
268
+
245
269
  for (const store of stores) {
246
270
  const members = replayTransactionStore<StoredEmbedding>(store);
247
- for (const ref of members.keys()) {
248
- hits.push({ ref, closeness: getCloseness(query, members.get(ref)!) });
271
+ for (const [ref, value] of members) {
272
+ hits.push({ ref, closeness: getCloseness(query, value) });
249
273
  }
250
274
  }
251
275
  hits.sort((left, right) => right.closeness - left.closeness);