Skip to content

[fix](lance) Select metric-compatible vector index - #67553

Merged
yiguolei merged 5 commits into
apache:branch-4.1from
FANNG1:fix/lance-metric-index-selection
Sep 16, 2026
Merged

yiguolei merged 5 commits into
apache:branch-4.1from
FANNG1:fix/lance-metric-index-selection

Conversation

@FANNG1

@FANNG1 FANNG1 commented Sep 7, 2026

Copy link
Copy Markdown

What problem does this PR solve?

Issue Number: close #67117

Related PR: None

Problem Summary: When multiple Lance vector indexes exist on the same column, Doris previously selected the first physical index segment before checking its metric. If that logical index used a different metric, Doris fell back to flat search without trying a later compatible index.

Group physical index segments by logical index name, visit logical indexes in lexicographic name order, filter each complete group by the requested metric, and select the first group that can be planned safely. If no compatible usable group exists, preserve the existing flat-search fallback. This keeps every physical segment of one logical index together and never mixes segment UUIDs from different logical indexes.

Release note

Fix Lance vector index selection when multiple indexes with different metrics exist on the same column.

Check List (For Author)

  • Test: Unit Test / FE validation
    • mvn validate -pl fe-core -am -DskipTests passed, including Checkstyle.
    • Added LanceScanNodeTest cases for metric matching, metadata-order independence, lexicographic logical-index selection, DEFAULT-to-L2 behavior, unsafe-group skipping, and multi-segment UUID grouping.
    • ./run-fe-ut.sh --run org.apache.doris.datasource.lance.source.LanceScanNodeTest was attempted but blocked before fe-core: the macOS prebuilt thirdparty Thrift compiler generates Java incompatible with this historical branch, causing fe-common compilation errors.
  • Behavior changed: Yes. Doris now tries metric-compatible logical Lance indexes in lexicographic index-name order before falling back to flat search.
  • Does this need documentation: No

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@FANNG1
FANNG1 marked this pull request as ready for review September 9, 2026 09:35
@FANNG1
FANNG1 requested a review from yiguolei as a code owner September 9, 2026 09:35
@FANNG1

FANNG1 commented Sep 9, 2026

Copy link
Copy Markdown
Author

/review

@FANNG1

FANNG1 commented Sep 9, 2026

Copy link
Copy Markdown
Author

run buildall

@FANNG1
FANNG1 force-pushed the fix/lance-metric-index-selection branch from 74eab3f to df7c762 Compare September 9, 2026 11:44
@FANNG1

FANNG1 commented Sep 9, 2026

Copy link
Copy Markdown
Author

run buildall

@FANNG1

FANNG1 commented Sep 9, 2026

Copy link
Copy Markdown
Author

@zhangstar333 PTAL, thx

@github-actions github-actions Bot 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.

Automated review status: complete after 2 of at most 3 rounds; every Round 2 normal and risk-focused pass returned NO_NEW_VALUABLE_FINDINGS. Reviewed exact head df7c762.

Requesting changes for one test-compilation blocker and two explicit issue-completeness gaps.

Critical checkpoints:

  • Build/test correctness: the ten added test fixtures omit the required IndexType constructor argument, so the modified test class cannot compile and the new assertions cannot run.
  • Selection correctness: the production grouping and lexicographic first-safe-plan logic is internally consistent; rejected plans are isolated, one logical index's UUIDs are routed, and uncovered visible fragments retain flat-search splits.
  • Metric and compatibility paths: omitted/DEFAULT L2 plus explicit L2/COSINE/DOT_PRODUCT/HAMMING agree across request parsing, metadata normalization, FE selection, and BE setup. NORMAL and FULL_TEXT paths are not changed by the new vector selector.
  • Regression evidence: issue #67117's required physical same-column multi-index EXPLAIN plus nprobes/ef discriminator is still missing; the added tests exercise injected metadata only.
  • Documentation: current English/Chinese 4.x docs and in-repository fixture comments still describe the removed one-index-only limitation instead of the new deterministic selection policy.
  • Security, concurrency, lifecycle, and performance: no additional distinct regression was substantiated.
  • User focus: no additional focus was provided; the full PR was reviewed.

No build was run, as this review runner explicitly prohibits builds. Existing review context was refreshed immediately before submission and contained no prior reviews or inline comments.

Arrays.asList(new LanceFragmentInfo(1, 8, 8), new LanceFragmentInfo(2, 7, 7)),
Collections.singletonMap("vector", 9),
Arrays.asList(
new LanceIndexSegmentInfo(l2Segment, "a_l2", Collections.singletonList(9),

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.

[P1] Supply the required index type in these fixtures

LanceIndexSegmentInfo has only the six-argument constructor ending in (IndexType, String), but this and the other nine added calls pass the metric as the fifth argument. fe-core test compilation therefore fails before any new regression assertion can run; the reported mvn validate phase only runs Checkstyle. Add IndexType.VECTOR before each "L2"/"COSINE" metric argument (including the null-bitmap case), then run a phase that reaches test compilation.

assertSplit(splits.get(1), 2, 8, 88);
}

@Test

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.

[P2] Add the required physical multi-index regression

These cases construct LanceTableMetadata directly, so they bypass Dataset.describeIndices(), LanceMetadataLoader, scan-range UUID serialization, and lance-c execution. Issue #67117 explicitly requires a same-column two-index fixture that proves nonzero indexed planning in EXPLAIN and uses an nprobes/ef discriminator; the existing matrix fixture still deliberately keeps one index per vector column. Please add that production-path regression so this fix's core scenario is exercised beyond the helper-level plan.

List<LanceIndexSegmentInfo> indexSegments, int fieldId) {
List<LanceIndexSegmentInfo> selectedSegments = new ArrayList<>();
String selectedIndexName = null;
// A stable order keeps index selection independent of Lance metadata ordering.

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.

[P2] Update the documented selection contract

This now selects the lexicographically first safely plannable metric match, but the current English and Chinese 4.x Lance catalog docs still say Doris considers only one vector index per column and recommend creating at most one. Issue #67117 also makes removing that guidance and documenting a deterministic policy an acceptance criterion, while the in-repo matrix fixture comments still describe the old first-index limitation. Please update those docs/comments (or link the companion documentation change) so users are not told the opposite of the new behavior.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 88.24% (15/17) 🎉
Increment coverage report
Complete coverage report

1 similar comment
@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 88.24% (15/17) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 25.42% (15/59) 🎉
Increment coverage report
Complete coverage report

zhangstar333
zhangstar333 previously approved these changes Sep 10, 2026
@zhangstar333

Copy link
Copy Markdown
Contributor

run buildall

FANNG1 added a commit to FANNG1/doris that referenced this pull request Sep 10, 2026
### What problem does this PR solve?

Issue Number: close apache#67117

Related PR: apache#67553

Problem Summary: The Lance fixture comment said that only the first vector index on a column was reachable. Metric-compatible selection now groups physical segments by logical index name and considers later compatible groups, so that explanation was stale. Describe the fixture matrix as deliberately using one index per column for independent compatibility cells and point same-column coverage to the FE metadata test.

### Release note

None

### Check List (For Author)

- Test: git diff --check; python3 -m py_compile docker/thirdparties/docker-compose/iceberg/scripts/lance_build_preinstalled_catalog.py
- Behavior changed: No
- Does this need documentation: Yes (separate website documentation follow-up needed)
@FANNG1

FANNG1 commented Sep 10, 2026

Copy link
Copy Markdown
Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 100.00% (17/17) 🎉
Increment coverage report
Complete coverage report

@FANNG1

FANNG1 commented Sep 11, 2026

Copy link
Copy Markdown
Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 100.00% (17/17) 🎉
Increment coverage report
Complete coverage report

@FANNG1

FANNG1 commented Sep 11, 2026

Copy link
Copy Markdown
Author

The current CI failures (FE UT and check_coverage_fe) look unrelated to this PR. Both are caused by the build environment image, which now ships glibc 2.17.

Image change

apache/doris:build-env-ldb-toolchain-latest was re-pushed on Docker Hub at 2026-09-10 16:10 UTC:

Run Build Image digest Result
FE UT, before 1041974 sha256:84a9b554fecd8dc2998879a71f2d641e2da8dab45dc5b0cef93f2707b5776e01 passed (9160 tests)
FE UT, after 1043001 sha256:4b35f2346ceeb072ae842bfbd3484d52ecc63a1ee19953a194b062dae775f893 17 failures

Both runs tested the same commit 829c628de9e177fc44bff1f5830bcf8f87413c5c.

FE UT (build 1043001)

All 17 non-muted failures are in LanceIndexMetadataLoaderTest (13) and LanceRestCatalogTest (4). Neither class is touched by this PR. The Lance JNI library fails to load:

java.lang.UnsatisfiedLinkError: /tmp/liblance_jni11342793688463938227.so: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /tmp/liblance_jni11342793688463938227.so)

After that, the remaining Lance tests fail with java.lang.NoClassDefFoundError: Could not initialize class org.lance.Dataset / org.lance.namespace.RestNamespace. LanceScanNodeTest, the test changed by this PR, passes 21/21 in the same run.

check_coverage_fe (build 1042299)

The container prints glibc 2.17, and then Node 24.19.0 installed via nvm cannot start, so the script exits before build.sh --fe runs:

node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)

Other PRs are hitting the same check_coverage_fe failure right now (for example #67648, #67820, #67627, #67784, #67810).

Could someone with CI access take a look? Rolling the tag back to the 84a9b5... image, or pinning the CI to an image digest, should fix this.

@zhangstar333

Copy link
Copy Markdown
Contributor

The current CI failures (FE UT and check_coverage_fe) look unrelated to this PR. Both are caused by the build environment image, which now ships glibc 2.17.

Image change

apache/doris:build-env-ldb-toolchain-latest was re-pushed on Docker Hub at 2026-09-10 16:10 UTC:

Run Build Image digest Result
FE UT, before 1041974 sha256:84a9b554fecd8dc2998879a71f2d641e2da8dab45dc5b0cef93f2707b5776e01 passed (9160 tests)
FE UT, after 1043001 sha256:4b35f2346ceeb072ae842bfbd3484d52ecc63a1ee19953a194b062dae775f893 17 failures
Both runs tested the same commit 829c628de9e177fc44bff1f5830bcf8f87413c5c.

FE UT (build 1043001)

All 17 non-muted failures are in LanceIndexMetadataLoaderTest (13) and LanceRestCatalogTest (4). Neither class is touched by this PR. The Lance JNI library fails to load:

java.lang.UnsatisfiedLinkError: /tmp/liblance_jni11342793688463938227.so: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /tmp/liblance_jni11342793688463938227.so)

After that, the remaining Lance tests fail with java.lang.NoClassDefFoundError: Could not initialize class org.lance.Dataset / org.lance.namespace.RestNamespace. LanceScanNodeTest, the test changed by this PR, passes 21/21 in the same run.

check_coverage_fe (build 1042299)

The container prints glibc 2.17, and then Node 24.19.0 installed via nvm cannot start, so the script exits before build.sh --fe runs:

node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)

Other PRs are hitting the same check_coverage_fe failure right now (for example #67648, #67820, #67627, #67784, #67810).

Could someone with CI access take a look? Rolling the tag back to the 84a9b5... image, or pinning the CI to an image digest, should fix this.

@FANNG1
thanks, we are deal with it

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 100.00% (17/17) 🎉
Increment coverage report
Complete coverage report

@zhangstar333

Copy link
Copy Markdown
Contributor

@FANNG1 the code conflicts, could rebase upstream for merge

Issue Number: close apache#67117

Related PR: apache#67039

Problem Summary: LanceScanNode previously committed to the first logical index returned for a vector field before checking its metric. A query whose requested metric matched a later same-column index therefore fell back to Flat Search. Group segments by logical index name, inspect groups in stable lexical name order, and select the first metric-compatible group that can safely produce indexed splits. Legacy or invisible groups no longer prevent a later safe candidate from being used.

Vector searches can use a later same-column Lance index when it matches the requested metric instead of unnecessarily falling back to Flat Search.

- Test: Maven validate -pl fe-core -am -DskipTests (passed); LanceScanNodeTest added. Targeted ./run-fe-ut.sh --run org.apache.doris.datasource.lance.source.LanceScanNodeTest was blocked before fe-core by generated Thrift source incompatibility from the local prebuilt thirdparty package.

- Behavior changed: Yes (metric-compatible same-column indexes are now selected deterministically)

- Does this need documentation: Yes (follow up in apache/doris-website#4082)
### What problem does this PR solve?

Issue Number: close apache#67117

Related PR: None

Problem Summary: The same-metric selection test previously covered one physical segment per logical index only. It could not prove that selecting the lexicographically first logical index preserves every one of its physical segments without mixing UUIDs from another same-metric index. Model the selected index with two segments and a later index covering all fragments, then assert the selected group\x27s UUIDs and the remaining flat fragment split.

### Release note

None

### Check List (For Author)

- Test: FE Checkstyle validation; targeted FE unit test blocked before fe-core by historical macOS thirdparty Thrift generation incompatibility
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: close apache#67117

Related PR: apache#67039

Problem Summary: The same-column vector index selection tests used the pre-full-text-search LanceIndexSegmentInfo constructor and no longer compiled after IndexType became required. They also exercised only injected FE metadata, leaving the real fixture, metadata loader, scan-range serialization, and backend index path untested. Supply IndexType.VECTOR to every affected fixture and add a two-index same-column Lance dataset with L2 created before cosine. The regression verifies that a cosine query plans indexed segments and that nprobes changes the result relative to Flat Search.

### Release note

None

### Check List (For Author)

- Test: Python syntax check passed for lance_build_preinstalled_catalog.py; git diff --check passed; targeted ./run-fe-ut.sh --run org.apache.doris.datasource.lance.source.LanceScanNodeTest blocked before fe-core because thirdparty/installed/bin/protoc is missing
- Behavior changed: No
- Does this need documentation: Yes (follow-up website documentation update required)
### What problem does this PR solve?

Issue Number: close apache#67117

Related PR: apache#67039

Problem Summary: External Regression provisions its Lance warehouse from a prebuilt fixture rather than rebuilding lance_build_preinstalled_catalog.py from the PR checkout. The newly added same-column multi-index table was therefore absent in CI, causing test_lance_vector_search_metrics to fail before it could exercise index selection. Remove the unavailable external fixture and its dependent assertions. Keep the same-column selection coverage in LanceScanNodeTest, whose metadata fixtures are built in the FE test process, and clarify that the external matrix intentionally uses one index per column.

### Release note

None

### Check List (For Author)

- Test: git diff --check; python3 -m py_compile docker/thirdparties/docker-compose/iceberg/scripts/lance_build_preinstalled_catalog.py
- Behavior changed: No
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: close apache#67117

Related PR: apache#67553

Problem Summary: The Lance fixture comment said that only the first vector index on a column was reachable. Metric-compatible selection now groups physical segments by logical index name and considers later compatible groups, so that explanation was stale. Describe the fixture matrix as deliberately using one index per column for independent compatibility cells and point same-column coverage to the FE metadata test.

### Release note

None

### Check List (For Author)

- Test: git diff --check; python3 -m py_compile docker/thirdparties/docker-compose/iceberg/scripts/lance_build_preinstalled_catalog.py
- Behavior changed: No
- Does this need documentation: Yes (separate website documentation follow-up needed)
@FANNG1
FANNG1 force-pushed the fix/lance-metric-index-selection branch from 829c628 to eb80283 Compare September 15, 2026 03:18
@FANNG1

FANNG1 commented Sep 15, 2026

Copy link
Copy Markdown
Author

run buildall

@yiguolei
yiguolei merged commit 089fa51 into apache:branch-4.1 Sep 16, 2026
33 of 36 checks passed
@FANNG1
FANNG1 deleted the fix/lance-metric-index-selection branch September 16, 2026 06:26
yiguolei pushed a commit that referenced this pull request Sep 17, 2026
### What problem does this PR solve?

Issue Number: close #67117

Related PR: None

Problem Summary: When multiple Lance vector indexes exist on the same
column, Doris previously selected the first physical index segment
before checking its metric. If that logical index used a different
metric, Doris fell back to flat search without trying a later compatible
index.

Group physical index segments by logical index name, visit logical
indexes in lexicographic name order, filter each complete group by the
requested metric, and select the first group that can be planned safely.
If no compatible usable group exists, preserve the existing flat-search
fallback. This keeps every physical segment of one logical index
together and never mixes segment UUIDs from different logical indexes.

### Release note

Fix Lance vector index selection when multiple indexes with different
metrics exist on the same column.

### Check List (For Author)

- Test: Unit Test / FE validation
- `mvn validate -pl fe-core -am -DskipTests` passed, including
Checkstyle.
- Added `LanceScanNodeTest` cases for metric matching, metadata-order
independence, lexicographic logical-index selection, DEFAULT-to-L2
behavior, unsafe-group skipping, and multi-segment UUID grouping.
- `./run-fe-ut.sh --run
org.apache.doris.datasource.lance.source.LanceScanNodeTest` was
attempted but blocked before `fe-core`: the macOS prebuilt thirdparty
Thrift compiler generates Java incompatible with this historical branch,
causing `fe-common` compilation errors.
- Behavior changed: Yes. Doris now tries metric-compatible logical Lance
indexes in lexicographic index-name order before falling back to flat
search.
- Does this need documentation: No
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.

4 participants