@mastra/lance 1.1.0-alpha.0 → 1.1.1-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/CHANGELOG.md +40 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +92 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +92 -12
- 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/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @mastra/lance
|
|
2
2
|
|
|
3
|
+
## 1.1.1-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed `LanceVectorStore.query()` returning a raw LanceDB distance in the `score` field, which inverted ranking compared to every other Mastra vector store. ([#18104](https://github.com/mastra-ai/mastra/pull/18104))
|
|
8
|
+
|
|
9
|
+
LanceDB's `_distance` is a distance (lower = more similar), while Mastra's `score` is a similarity (higher = more similar). Returning the distance unchanged meant the closest match got the _lowest_ score, silently breaking `Memory` semantic recall, `rerank()` vector weighting, and any `minScore`/threshold filtering written against other stores (pg, Chroma, S3 Vectors, Pinecone, …).
|
|
10
|
+
|
|
11
|
+
`query()` now converts `_distance` into a similarity score consistent with the other stores and sets the search distance type to match the detected index metric, or an explicit query metric when no physical Lance index exists:
|
|
12
|
+
- cosine → `1 - distance` (cosine similarity)
|
|
13
|
+
- dot product → `1 - distance` (recovers the dot product, matching `@mastra/pg`)
|
|
14
|
+
- euclidean → `1 / (1 + sqrt(distance))` (Lance `l2` returns squared L2, so this maps to Mastra's L2 similarity semantics)
|
|
15
|
+
|
|
16
|
+
The metric defaults to the table's vector index metric when one exists, otherwise `cosine` (matching `createIndex`'s default). For small/unindexed tables where LanceDB has no physical index metadata to inspect, pass `metric` to `query()` when using a non-cosine metric. If a query metric conflicts with an existing Lance index metric, the index metric is used because Lance requires indexed searches to use the index's distance type:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// Before: `exact` got score 0, `far` got score 2 — ranking inverted.
|
|
20
|
+
// After: `exact` gets the highest score and ranks first.
|
|
21
|
+
const results = await store.query({
|
|
22
|
+
indexName: 'docs',
|
|
23
|
+
queryVector: [1, 0, 0],
|
|
24
|
+
topK: 2,
|
|
25
|
+
metric: 'cosine', // optional; resolved from the index by default
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [[`6a1428a`](https://github.com/mastra-ai/mastra/commit/6a1428a23133fc070fc6c1caa08d28f3ba4fe5ff), [`7f51548`](https://github.com/mastra-ai/mastra/commit/7f515481213780be7047cef00640b9d35f3d545c)]:
|
|
30
|
+
- @mastra/core@1.46.0-alpha.2
|
|
31
|
+
|
|
32
|
+
## 1.1.0
|
|
33
|
+
|
|
34
|
+
### Minor Changes
|
|
35
|
+
|
|
36
|
+
- Random bump ([#18178](https://github.com/mastra-ai/mastra/pull/18178))
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- Updated dependencies [[`7c0d868`](https://github.com/mastra-ai/mastra/commit/7c0d868d97d0fdbc04c14d0166dbf44d4c5a4a62), [`d9d2273`](https://github.com/mastra-ai/mastra/commit/d9d2273c702690c9a26eab2aebea879701d4355a), [`b04369d`](https://github.com/mastra-ai/mastra/commit/b04369d6b167c698ef103981171a8bf92808e756), [`8f3c262`](https://github.com/mastra-ai/mastra/commit/8f3c262587b335588a02d96b17fd6aca34c885b3)]:
|
|
41
|
+
- @mastra/core@1.45.0
|
|
42
|
+
|
|
3
43
|
## 1.1.0-alpha.0
|
|
4
44
|
|
|
5
45
|
### Minor Changes
|
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -2647,7 +2647,8 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2647
2647
|
includeVector = false,
|
|
2648
2648
|
topK = 10,
|
|
2649
2649
|
columns = [],
|
|
2650
|
-
includeAllColumns = false
|
|
2650
|
+
includeAllColumns = false,
|
|
2651
|
+
metric
|
|
2651
2652
|
}) {
|
|
2652
2653
|
const resolvedTableName = tableName ?? indexName;
|
|
2653
2654
|
if (!queryVector) {
|
|
@@ -2685,7 +2686,11 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2685
2686
|
return [];
|
|
2686
2687
|
}
|
|
2687
2688
|
const table = await this.lanceClient.openTable(resolvedTableName);
|
|
2688
|
-
|
|
2689
|
+
const resolvedMetric = await this.resolveQueryMetric(table, {
|
|
2690
|
+
columnName: tableName ? indexName : "vector",
|
|
2691
|
+
explicitMetric: metric
|
|
2692
|
+
});
|
|
2693
|
+
let query = table.vectorSearch(queryVector).distanceType(this.mastraMetricToLance(resolvedMetric));
|
|
2689
2694
|
if (filter && Object.keys(filter).length > 0) {
|
|
2690
2695
|
const whereClause = this.filterTranslator(filter);
|
|
2691
2696
|
this.logger.debug(`Where clause generated: ${whereClause}`);
|
|
@@ -2706,6 +2711,9 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2706
2711
|
if (!selectColumns.includes("id")) {
|
|
2707
2712
|
selectColumns.push("id");
|
|
2708
2713
|
}
|
|
2714
|
+
if (!selectColumns.includes("_distance")) {
|
|
2715
|
+
selectColumns.push("_distance");
|
|
2716
|
+
}
|
|
2709
2717
|
query = query.select(selectColumns);
|
|
2710
2718
|
}
|
|
2711
2719
|
query = query.limit(topK);
|
|
@@ -2726,7 +2734,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2726
2734
|
metadata,
|
|
2727
2735
|
vector: includeVector && result.vector ? Array.isArray(result.vector) ? result.vector : Array.from(result.vector) : void 0,
|
|
2728
2736
|
document: result.document,
|
|
2729
|
-
score: result._distance
|
|
2737
|
+
score: this.distanceToScore(result._distance, resolvedMetric)
|
|
2730
2738
|
};
|
|
2731
2739
|
});
|
|
2732
2740
|
} catch (error$1) {
|
|
@@ -2741,6 +2749,85 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2741
2749
|
);
|
|
2742
2750
|
}
|
|
2743
2751
|
}
|
|
2752
|
+
/**
|
|
2753
|
+
* Maps a Mastra distance metric to the LanceDB distance type.
|
|
2754
|
+
*/
|
|
2755
|
+
mastraMetricToLance(metric) {
|
|
2756
|
+
switch (metric) {
|
|
2757
|
+
case "euclidean":
|
|
2758
|
+
return "l2";
|
|
2759
|
+
case "dotproduct":
|
|
2760
|
+
return "dot";
|
|
2761
|
+
case "cosine":
|
|
2762
|
+
default:
|
|
2763
|
+
return "cosine";
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
/**
|
|
2767
|
+
* Determines the distance metric to use for a query.
|
|
2768
|
+
*
|
|
2769
|
+
* Precedence: the table's vector index metric wins when an index exists because
|
|
2770
|
+
* LanceDB requires indexed searches to use the same distance type the index was
|
|
2771
|
+
* trained with; otherwise an explicitly provided metric is used; otherwise it
|
|
2772
|
+
* defaults to 'cosine'.
|
|
2773
|
+
*/
|
|
2774
|
+
async resolveQueryMetric(table, {
|
|
2775
|
+
columnName,
|
|
2776
|
+
explicitMetric
|
|
2777
|
+
}) {
|
|
2778
|
+
try {
|
|
2779
|
+
const indices = await table.listIndices();
|
|
2780
|
+
const matchingIndices = indices.filter((index) => index.columns?.includes(columnName));
|
|
2781
|
+
for (const index of matchingIndices.length > 0 ? matchingIndices : indices) {
|
|
2782
|
+
const stats = await table.indexStats(index.name);
|
|
2783
|
+
const resolved = this.lanceMetricToMastra(stats?.distanceType);
|
|
2784
|
+
if (resolved) {
|
|
2785
|
+
if (explicitMetric && explicitMetric !== resolved) {
|
|
2786
|
+
this.logger.warn(
|
|
2787
|
+
`Ignoring query metric "${explicitMetric}" because Lance index "${index.name}" uses "${resolved}".`
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
return resolved;
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
} catch (error) {
|
|
2794
|
+
this.logger.debug("Failed to resolve metric from Lance index stats.", error);
|
|
2795
|
+
}
|
|
2796
|
+
return explicitMetric ?? "cosine";
|
|
2797
|
+
}
|
|
2798
|
+
lanceMetricToMastra(metric) {
|
|
2799
|
+
switch (metric) {
|
|
2800
|
+
case "l2":
|
|
2801
|
+
return "euclidean";
|
|
2802
|
+
case "dot":
|
|
2803
|
+
return "dotproduct";
|
|
2804
|
+
case "cosine":
|
|
2805
|
+
return "cosine";
|
|
2806
|
+
default:
|
|
2807
|
+
return void 0;
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
/**
|
|
2811
|
+
* Converts a LanceDB `_distance` (smaller = more similar) into a Mastra similarity
|
|
2812
|
+
* `score` (larger = more similar), consistent with every other Mastra vector store.
|
|
2813
|
+
*
|
|
2814
|
+
* - cosine: LanceDB returns cosine distance (`1 - cosine_similarity`), so `1 - distance`
|
|
2815
|
+
* recovers the cosine similarity.
|
|
2816
|
+
* - dotproduct: LanceDB's dot distance is `1 - dot_product`, so `1 - distance` recovers
|
|
2817
|
+
* the dot product (matching `@mastra/pg`).
|
|
2818
|
+
* - euclidean: LanceDB returns squared L2 distance for `l2`, so use its square root
|
|
2819
|
+
* before mapping into (0, 1] (matching `@mastra/pg`).
|
|
2820
|
+
*/
|
|
2821
|
+
distanceToScore(distance, metric) {
|
|
2822
|
+
switch (metric) {
|
|
2823
|
+
case "euclidean":
|
|
2824
|
+
return 1 / (1 + Math.sqrt(distance));
|
|
2825
|
+
case "dotproduct":
|
|
2826
|
+
case "cosine":
|
|
2827
|
+
default:
|
|
2828
|
+
return 1 - distance;
|
|
2829
|
+
}
|
|
2830
|
+
}
|
|
2744
2831
|
filterTranslator(filter) {
|
|
2745
2832
|
const processFilterKeys = (filterObj) => {
|
|
2746
2833
|
const result = {};
|
|
@@ -3033,14 +3120,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3033
3120
|
} else {
|
|
3034
3121
|
table = await this.lanceClient.openTable(resolvedTableName);
|
|
3035
3122
|
}
|
|
3036
|
-
|
|
3037
|
-
if (metric === "euclidean") {
|
|
3038
|
-
metricType = "l2";
|
|
3039
|
-
} else if (metric === "dotproduct") {
|
|
3040
|
-
metricType = "dot";
|
|
3041
|
-
} else if (metric === "cosine") {
|
|
3042
|
-
metricType = "cosine";
|
|
3043
|
-
}
|
|
3123
|
+
const metricType = this.mastraMetricToLance(metric);
|
|
3044
3124
|
const rowCount = await table.countRows();
|
|
3045
3125
|
if (rowCount < 256) {
|
|
3046
3126
|
this.logger.warn(
|
|
@@ -3145,7 +3225,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3145
3225
|
const dimension = vectorField?.type?.["listSize"] || 0;
|
|
3146
3226
|
return {
|
|
3147
3227
|
dimension,
|
|
3148
|
-
metric: stats.distanceType,
|
|
3228
|
+
metric: this.lanceMetricToMastra(stats.distanceType),
|
|
3149
3229
|
count: stats.numIndexedRows
|
|
3150
3230
|
};
|
|
3151
3231
|
}
|