From 8c504101aaf8380ede4f07d253fc23e8d60ed9b7 Mon Sep 17 00:00:00 2001 From: Daniel Rammer Date: Fri, 9 Oct 2026 14:12:16 -0500 Subject: [PATCH 1/3] fix(mem_wal): rank every vector search arm on one distance scale The LSM vector planner merges its arms by `_distance`, but cosine reached the merge on two scales: flushed generations index as IVF_HNSW_SQ, which ranks cosine as L2 over normalized vectors (twice `1 - cos`), while the memtable ranks it exactly. Flush also wrote unnormalized vectors into the cosine index, so a generation's search ranked non-unit embeddings by L2 against a normalized query. Normalize vectors at flush for a cosine index, and add two planner builders: `with_refine_factor` refines the base and SSTable arms so every arm is exact, and `with_distance_scale` puts unrefined arms on the scale a caller's own base search reports, converting the distance range to match. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../lance/memwal/LsmVectorSearchPlanner.java | 9 +- python/python/lance/mem_wal.py | 8 +- rust/lance/src/dataset/mem_wal/index/hnsw.rs | 11 + .../src/dataset/mem_wal/memtable/flush.rs | 127 +++++++++ .../src/dataset/mem_wal/scanner/builder.rs | 21 +- .../src/dataset/mem_wal/scanner/projection.rs | 37 ++- .../dataset/mem_wal/scanner/vector_search.rs | 269 ++++++++++++++++-- 7 files changed, 435 insertions(+), 47 deletions(-) diff --git a/java/src/main/java/org/lance/memwal/LsmVectorSearchPlanner.java b/java/src/main/java/org/lance/memwal/LsmVectorSearchPlanner.java index b91e5ae4a7d..34e424c49ba 100644 --- a/java/src/main/java/org/lance/memwal/LsmVectorSearchPlanner.java +++ b/java/src/main/java/org/lance/memwal/LsmVectorSearchPlanner.java @@ -117,9 +117,9 @@ private native void nativeCreate( * @param nprobes number of IVF partitions to probe * @param columns columns to project; pass {@code null} to return all columns plus {@code * _distance} - * @param refineBaseTable when true, the base-table arm re-ranks candidates with exact distances - * (refine factor 1). Useful when the base table uses an approximate index (IVF-PQ). - * Auto-enabled whenever stale filtering is on (see {@code overfetchFactor}). + * @param refineBaseTable when true, the base-table and SSTable arms re-rank candidates with + * exact distances (refine factor 1), so every arm reports exact distances. Auto-enabled + * whenever stale filtering is on (see {@code overfetchFactor}). * @param overfetchFactor over-fetch multiple for sources with rows superseded by newer * generations. Must be at least {@code 1.0}: *