Skip to content

fix(lumina): store the canonical native metric name in index metadata - #895

Merged
JingsongLi merged 1 commit into
apache:mainfrom
jackylee-ch:fix/lumina-canonical-metric-in-index-meta
Sep 22, 2026
Merged

JingsongLi merged 1 commit into
apache:mainfrom
jackylee-ch:fix/lumina-canonical-metric-in-index-meta

Conversation

@jackylee-ch

Copy link
Copy Markdown
Contributor

lumina.distance.metric accepts the enum spellings (L2) as well as the native ones, but the raw string was copied into the native option map that LuminaIndexBuildBuilder commits as index metadata. LuminaIndexMeta::metric() decodes with exact-match from_lumina_name, so every query against such an index failed with Unknown lumina metric name: L2. Fixed by persisting metric.lumina_name(), as Java does (apache/paimon#8676).

For reviewers: the strip_lumina_options call is not redundant. LuminaVectorReader::ensure_loaded overlays the stripped table options on top of the metadata before creating the searcher, so the configured spelling would otherwise be what crosses the FFI, not the one the index was built with.

Readers stay exact-match and an unrecognized value passes through untouched, both pinned by tests. An index already committed with an enum spelling needs a rebuild.

lumina.distance.metric accepts the enum spellings L2/COSINE/INNER_PRODUCT
as well as the native ones, but the raw string was copied into the native
option map that becomes the committed index metadata. The read side is
exact-match only, so LuminaIndexMeta::metric() then failed with "Unknown
lumina metric name: L2" on every query against such an index.

Persist metric.lumina_name() instead, mirroring Java
LuminaVectorIndexOptions (apache/paimon#8676).

strip_lumina_options needs the same treatment. Java crosses its native
boundary with a typed MetricType, so the string is inert there, but Rust
hands the whole option map to the native library and ensure_loaded
overlays the stripped table options on top of the index metadata -- the
configured spelling would otherwise come straight back.

An unrecognized value is left untouched so its error surface does not
move, and the readers stay exact-match: from_lumina_name is the wire
decoder and widening it would accept metadata Java rejects.

@JingsongLi JingsongLi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed head b961ff6. Requirement fit: supported; implementation: no blocking findings. This is caller-visible: LuminaIndexBuildBuilder::execute commits to_lumina_options() as index metadata, while LuminaIndexMeta::metric() accepts only native spellings; both Lumina search paths and the DE/PK vector planners consume that parser. A configured L2 could therefore build successfully but make subsequent searches fail. Canonicalizing before metadata serialization fixes that without weakening the wire decoder, and canonicalizing stripped options avoids reintroducing the alias at the native reader boundary. In an isolated build, cargo test -p paimon --lib lumina::tests:: passed all 17 tests, including the enum/native spelling and unknown-value cases. Existing indexes whose metadata already contains the alias still need rebuilding, as the PR notes.

@JingsongLi
JingsongLi merged commit 444da2a into apache:main Sep 22, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants