@mastra/lance 1.4.0 → 1.5.0-alpha.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/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-vectors-lance.md +56 -10
- package/dist/index.cjs +153 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +153 -5
- package/dist/index.js.map +1 -1
- package/dist/vector/index.d.ts +33 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/dist/vector/types.d.ts +1 -1
- package/dist/vector/types.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -2189,8 +2189,11 @@ var LanceFilterTranslator = class extends BaseFilterTranslator {
|
|
|
2189
2189
|
};
|
|
2190
2190
|
//#endregion
|
|
2191
2191
|
//#region src/vector/index.ts
|
|
2192
|
+
const LANCE_INDEX_FINGERPRINT_KEY = "mastra.index.fingerprint";
|
|
2193
|
+
const LANCE_INDEX_UUID_KEY = "mastra.index.uuid";
|
|
2192
2194
|
var LanceVectorStore = class LanceVectorStore extends MastraVector {
|
|
2193
2195
|
lanceClient;
|
|
2196
|
+
optimizeInFlight = /* @__PURE__ */ new Map();
|
|
2194
2197
|
/**
|
|
2195
2198
|
* Creates a new instance of LanceVectorStore
|
|
2196
2199
|
* @param uri The URI to connect to LanceDB
|
|
@@ -2575,6 +2578,7 @@ var LanceVectorStore = class LanceVectorStore extends MastraVector {
|
|
|
2575
2578
|
}
|
|
2576
2579
|
}, err);
|
|
2577
2580
|
}
|
|
2581
|
+
if (indexConfig.type === "ivfflat" && indexConfig.numSubVectors !== void 0) this.logger.warn(`numSubVectors is ignored for 'ivfflat' indexes. Use type 'ivfpq' for product-quantized IVF indexes.`);
|
|
2578
2582
|
try {
|
|
2579
2583
|
const tables = await this.lanceClient.tableNames();
|
|
2580
2584
|
let table;
|
|
@@ -2600,19 +2604,51 @@ var LanceVectorStore = class LanceVectorStore extends MastraVector {
|
|
|
2600
2604
|
this.logger.warn(`Table ${resolvedTableName} has ${rowCount} rows, which is below the 256 row minimum for index creation. Skipping index creation.`);
|
|
2601
2605
|
return;
|
|
2602
2606
|
}
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2607
|
+
const numPartitions = indexConfig.numPartitions || 128;
|
|
2608
|
+
const buildParams = indexConfig.type === "ivfflat" ? { numPartitions } : indexConfig.type === "ivfpq" ? {
|
|
2609
|
+
numPartitions,
|
|
2610
|
+
numSubVectors: indexConfig.numSubVectors || 16
|
|
2611
|
+
} : {
|
|
2612
|
+
m: indexConfig?.hnsw?.m || 16,
|
|
2613
|
+
efConstruction: indexConfig?.hnsw?.efConstruction || 100
|
|
2614
|
+
};
|
|
2615
|
+
const fingerprintType = indexConfig.type === "ivfflat" ? "ivf_flat" : indexConfig.type === "ivfpq" ? "ivf_pq" : "hnsw_pq";
|
|
2616
|
+
const fingerprint = JSON.stringify({
|
|
2617
|
+
type: fingerprintType,
|
|
2618
|
+
metric: metricType,
|
|
2619
|
+
...buildParams
|
|
2620
|
+
});
|
|
2621
|
+
const existingIndex = (await table.listIndices()).find((index) => index.columns.includes(columnToIndex));
|
|
2622
|
+
if (existingIndex?.indexUuid) {
|
|
2623
|
+
const field = (await table.schema()).fields.find((f) => f.name === columnToIndex);
|
|
2624
|
+
if (field?.metadata.get(LANCE_INDEX_FINGERPRINT_KEY) === fingerprint && field.metadata.get(LANCE_INDEX_UUID_KEY) === existingIndex.indexUuid) {
|
|
2625
|
+
this.logger.debug(`Index ${existingIndex.name} on ${resolvedTableName} is unchanged. Skipping rebuild.`);
|
|
2626
|
+
return;
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
if (indexConfig.type === "ivfflat") await table.createIndex(columnToIndex, { config: Index.ivfFlat({
|
|
2630
|
+
numPartitions,
|
|
2631
|
+
distanceType: metricType
|
|
2632
|
+
}) });
|
|
2633
|
+
else if (indexConfig.type === "ivfpq") await table.createIndex(columnToIndex, { config: Index.ivfPq({
|
|
2634
|
+
...buildParams,
|
|
2606
2635
|
distanceType: metricType
|
|
2607
2636
|
}) });
|
|
2608
2637
|
else {
|
|
2609
2638
|
this.logger.debug("Creating HNSW PQ index with config:", indexConfig);
|
|
2610
2639
|
await table.createIndex(columnToIndex, { config: Index.hnswPq({
|
|
2611
|
-
|
|
2612
|
-
efConstruction: indexConfig?.hnsw?.efConstruction || 100,
|
|
2640
|
+
...buildParams,
|
|
2613
2641
|
distanceType: metricType
|
|
2614
2642
|
}) });
|
|
2615
2643
|
}
|
|
2644
|
+
const builtUuid = (await table.listIndices()).find((index) => index.columns.includes(columnToIndex))?.indexUuid;
|
|
2645
|
+
if (builtUuid && builtUuid !== existingIndex?.indexUuid) await table.updateFieldMetadata([{
|
|
2646
|
+
path: columnToIndex,
|
|
2647
|
+
metadata: {
|
|
2648
|
+
[LANCE_INDEX_FINGERPRINT_KEY]: fingerprint,
|
|
2649
|
+
[LANCE_INDEX_UUID_KEY]: builtUuid
|
|
2650
|
+
}
|
|
2651
|
+
}]);
|
|
2616
2652
|
} catch (error) {
|
|
2617
2653
|
throw new MastraError({
|
|
2618
2654
|
id: createVectorErrorId("LANCE", "CREATE_INDEX", "FAILED"),
|
|
@@ -2721,6 +2757,118 @@ var LanceVectorStore = class LanceVectorStore extends MastraVector {
|
|
|
2721
2757
|
}, error);
|
|
2722
2758
|
}
|
|
2723
2759
|
}
|
|
2760
|
+
async openExistingTable({ tableName, indexName }, operation) {
|
|
2761
|
+
const resolvedTableName = tableName ?? indexName;
|
|
2762
|
+
let validationError;
|
|
2763
|
+
if (!this.lanceClient) validationError = "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance";
|
|
2764
|
+
else if (!resolvedTableName) validationError = "tableName or indexName is required";
|
|
2765
|
+
if (validationError || !resolvedTableName || !this.lanceClient) throw new MastraError({
|
|
2766
|
+
id: createVectorErrorId("LANCE", operation, "INVALID_ARGS"),
|
|
2767
|
+
text: validationError,
|
|
2768
|
+
domain: ErrorDomain.STORAGE,
|
|
2769
|
+
category: ErrorCategory.USER,
|
|
2770
|
+
details: { tableName: resolvedTableName ?? "" }
|
|
2771
|
+
});
|
|
2772
|
+
let tableExists;
|
|
2773
|
+
try {
|
|
2774
|
+
tableExists = (await this.lanceClient.tableNames()).includes(resolvedTableName);
|
|
2775
|
+
if (tableExists) return {
|
|
2776
|
+
table: await this.lanceClient.openTable(resolvedTableName),
|
|
2777
|
+
resolvedTableName
|
|
2778
|
+
};
|
|
2779
|
+
} catch (error) {
|
|
2780
|
+
throw new MastraError({
|
|
2781
|
+
id: createVectorErrorId("LANCE", operation, "FAILED"),
|
|
2782
|
+
domain: ErrorDomain.STORAGE,
|
|
2783
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2784
|
+
details: { tableName: resolvedTableName }
|
|
2785
|
+
}, error);
|
|
2786
|
+
}
|
|
2787
|
+
throw new MastraError({
|
|
2788
|
+
id: createVectorErrorId("LANCE", operation, "INVALID_ARGS"),
|
|
2789
|
+
text: `Table ${resolvedTableName} does not exist`,
|
|
2790
|
+
domain: ErrorDomain.STORAGE,
|
|
2791
|
+
category: ErrorCategory.USER,
|
|
2792
|
+
details: { tableName: resolvedTableName }
|
|
2793
|
+
});
|
|
2794
|
+
}
|
|
2795
|
+
/**
|
|
2796
|
+
* Runs LanceDB table maintenance: compacts fragments, adds unindexed rows to existing indexes
|
|
2797
|
+
* (without retraining them), and prunes old table versions.
|
|
2798
|
+
*
|
|
2799
|
+
* Never runs implicitly. Concurrent calls for the same table share a single in-flight run.
|
|
2800
|
+
*/
|
|
2801
|
+
async optimize(params) {
|
|
2802
|
+
const key = params.tableName ?? params.indexName;
|
|
2803
|
+
const inFlight = key ? this.optimizeInFlight.get(key) : void 0;
|
|
2804
|
+
if (inFlight) return inFlight;
|
|
2805
|
+
const run = (async () => {
|
|
2806
|
+
try {
|
|
2807
|
+
const { table, resolvedTableName } = await this.openExistingTable(params, "OPTIMIZE");
|
|
2808
|
+
try {
|
|
2809
|
+
const schema = await table.schema();
|
|
2810
|
+
const tracked = (await table.listIndices()).filter((index) => index.columns.some((column) => schema.fields.find((f) => f.name === column)?.metadata.get(LANCE_INDEX_UUID_KEY) === index.indexUuid));
|
|
2811
|
+
const stats = await table.optimize({
|
|
2812
|
+
...params.cleanupOlderThan ? { cleanupOlderThan: params.cleanupOlderThan } : {},
|
|
2813
|
+
deleteUnverified: params.deleteUnverified ?? false
|
|
2814
|
+
});
|
|
2815
|
+
if (tracked.length) {
|
|
2816
|
+
const after = await table.listIndices();
|
|
2817
|
+
const updates = tracked.flatMap((before) => {
|
|
2818
|
+
const current = after.find((index) => index.name === before.name);
|
|
2819
|
+
return current?.indexUuid && current.indexUuid !== before.indexUuid ? before.columns.map((path) => ({
|
|
2820
|
+
path,
|
|
2821
|
+
metadata: { [LANCE_INDEX_UUID_KEY]: current.indexUuid }
|
|
2822
|
+
})) : [];
|
|
2823
|
+
});
|
|
2824
|
+
if (updates.length) await table.updateFieldMetadata(updates);
|
|
2825
|
+
}
|
|
2826
|
+
return stats;
|
|
2827
|
+
} catch (error) {
|
|
2828
|
+
throw new MastraError({
|
|
2829
|
+
id: createVectorErrorId("LANCE", "OPTIMIZE", "FAILED"),
|
|
2830
|
+
domain: ErrorDomain.STORAGE,
|
|
2831
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2832
|
+
details: { tableName: resolvedTableName }
|
|
2833
|
+
}, error);
|
|
2834
|
+
}
|
|
2835
|
+
} finally {
|
|
2836
|
+
if (key) this.optimizeInFlight.delete(key);
|
|
2837
|
+
}
|
|
2838
|
+
})();
|
|
2839
|
+
if (key) this.optimizeInFlight.set(key, run);
|
|
2840
|
+
return run;
|
|
2841
|
+
}
|
|
2842
|
+
/**
|
|
2843
|
+
* Reports how many rows each index on a table covers. Rows written after an index was built
|
|
2844
|
+
* stay unindexed until `optimize()` runs; use this to decide when to optimize.
|
|
2845
|
+
*/
|
|
2846
|
+
async getIndexCoverage(params) {
|
|
2847
|
+
const { table, resolvedTableName } = await this.openExistingTable(params, "GET_INDEX_COVERAGE");
|
|
2848
|
+
try {
|
|
2849
|
+
const indices = await table.listIndices();
|
|
2850
|
+
const coverage = [];
|
|
2851
|
+
for (const index of indices) {
|
|
2852
|
+
const stats = await table.indexStats(index.name);
|
|
2853
|
+
if (!stats) continue;
|
|
2854
|
+
coverage.push({
|
|
2855
|
+
indexName: index.name,
|
|
2856
|
+
indexType: stats.indexType,
|
|
2857
|
+
columns: index.columns,
|
|
2858
|
+
numIndexedRows: stats.numIndexedRows,
|
|
2859
|
+
numUnindexedRows: stats.numUnindexedRows
|
|
2860
|
+
});
|
|
2861
|
+
}
|
|
2862
|
+
return coverage;
|
|
2863
|
+
} catch (error) {
|
|
2864
|
+
throw new MastraError({
|
|
2865
|
+
id: createVectorErrorId("LANCE", "GET_INDEX_COVERAGE", "FAILED"),
|
|
2866
|
+
domain: ErrorDomain.STORAGE,
|
|
2867
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2868
|
+
details: { tableName: resolvedTableName }
|
|
2869
|
+
}, error);
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2724
2872
|
/**
|
|
2725
2873
|
* Deletes all tables in the database
|
|
2726
2874
|
*/
|