feat(optimize): surface vector index layout so coverage answers can-it-prune - #532
feat(optimize): surface vector index layout so coverage answers can-it-prune#532memmmmike wants to merge 2 commits into
Conversation
…t-prune A mono-partition IVF index over a large table reports complete coverage while every nearest() reads the full index payload; delta optimize_indices folds never re-partition, so the state is invisible to anyone watching coverage (issue ModernRelay#486, from the ModernRelay#432 production incident). optimize stats now carry a VectorIndexLayout per built vector index: index name, partition summary, indexed rows, worst rows-per-partition across delta segments, and a degenerate flag. The flag is computed PER SEGMENT (Lance searches delta segments independently, so a well-partitioned later segment cannot repair a bad earlier one) from rows-per-partition, which catches both the mono-partition case and the incident's own 8-partitions-over-852k-rows shape. The CLI prints layouts under each table and marks degenerate ones loudly; --json carries the full struct. Statistics missing the expected fields are a loud error, not a silent skip, and lance_surface_guards now pins num_indexed_rows and num_indexed_rows_per_delta alongside num_partitions. Reporting only: the repair itself remains ModernRelay#485. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E4S9Xpe9G7pLEv9JaoXUAb
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
| "vector_index_layouts": s.vector_index_layouts.iter().map(|v| serde_json::json!({ | ||
| "column": v.column, | ||
| "index_name": v.index_name, | ||
| "partitions": v.partitions, | ||
| "indexed_rows": v.indexed_rows, | ||
| "max_rows_per_partition": v.max_rows_per_partition, | ||
| "degenerate": v.degenerate, | ||
| })).collect::<Vec<_>>(), |
There was a problem hiding this comment.
optimize --json now emits vector_index_layouts, and the human output reports healthy and degenerate layouts, but the maintenance documentation still enumerates the old field set. Update docs/user/operations/maintenance.md in this PR so operators and JSON consumers can discover the new layout, partition, and degeneracy fields.
Context Used: CLAUDE.md (source)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
CI has never run on this branch (action_required), so neither gate had reported yet. Both would have failed on first approval: - cargo fmt --all: three files this PR touched were unformatted. - cargo clippy -D warnings: manual_contains on the degenerate-partition check (segment_partitions.iter().any(|p| *p == 0) -> .contains(&0)). No behavior change. fmt, clippy --workspace --all-targets -D warnings, and the lib / maintenance / lance_surface_guards suites are green on 1.97.1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E4S9Xpe9G7pLEv9JaoXUAb
|
Heads-up while this waits for a CI approval: both gates would have failed on the first run, so I've fixed them in 9a44f04 (no behavior change).
Since CI on this branch is |
Resolves #486.
Coverage currently answers "does an index exist over these rows" but not "can it prune" — the exact blindspot from the #432 incident, where
pending_indexes: []reported a healthy index while everynearest()flat-read ~10 GB.What this adds (reporting only; the repair remains #485):
TableOptimizeStats.vector_index_layouts: per built vector index — name, partition summary, indexed rows, worst rows-per-partition across delta segments, and adegenerateflag.--jsoncarries the full struct.lance_surface_guardsnow pinsnum_indexed_rowsandnum_indexed_rows_per_delta(aligned withindices[]) beside the existingnum_partitionspin, so a Lance upgrade that changes the shape fails the guard instead of degrading the stats.Scope checked:
skipped_for_driftintentionally reports no layout (that HEAD is not manifest-accepted);TableOptimizeStatsis not serialized by the server, so no OpenAPI drift.Tests: classifier unit tests including the incident shape and the bad-segment-behind-good-segment case; an end-to-end maintenance test asserting layouts surface through
optimize()on a real vector index; the guard pins. Maintenance suite 34/34. CLI smoke on a local graph verified both text and--jsonoutput, and a no-vector-column graph stays clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01E4S9Xpe9G7pLEv9JaoXUAb
Greptile Summary
The PR extends optimize statistics with physical vector-index layouts so callers can distinguish index coverage from actual pruning capability.
Confidence Score: 5/5
The PR appears safe to merge because no blocking failure remains.
No blocking failure remains.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR Lance[Lance index statistics] --> Store[TableStore layout parser] Store --> Classifier[Per-segment degeneracy classifier] Classifier --> Stats[TableOptimizeStats] Stats --> JSON[CLI JSON output] Stats --> Human[CLI human output]Reviews (2): Last reviewed commit: "chore: satisfy the fmt and clippy gates" | Re-trigger Greptile
Context used: