lance-format / lance-format/lance
`optimize_indices` cannot extend a scalar index created over a nested field of an empty dataset
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 7.1k
- Forks
- 852
- Avg merge
- 3d 18h
- Merged PRs (30d)
- 272
Description
Description
create_scalar_index("st.child", index_type="BTREE") succeeds whether or not the dataset has rows. But if it ran while the dataset was empty, the optimize_indices() that should later extend the index over newly appended fragments fails:
OSError: Invalid user input: No column with name child,
/rust/lance/src/index/scalar.rs:364:20
The same index built once rows exist optimizes fine, then and on every later pass.
Output of the repro script:
index built while empty: optimize_indices() -> OSError: Invalid user input: No column with name child, .../rust/lance/src/index/scalar.rs:364:20
index built over 8 rows: optimize_indices() -> OK
Steps to reproduce
import tempfile
from pathlib import Path
import lance
import pyarrow as pa
STRUCT = pa.struct([pa.field("child", pa.int64())])
SCHEMA = pa.schema([pa.field("uid", pa.string()), pa.field("st", STRUCT)])
def rows(n: int, start: int = 0) -> pa.Table:
return pa.table(
{
"uid": pa.array([f"u{i}" for i in range(start, start + n)]),
"st": pa.array([{"child": i} for i in range(start, start + n)], type=STRUCT),
},
schema=SCHEMA,
)
def run(label: str, rows_before_index: int) -> None:
uri = str(Path(tempfile.mkdtemp()) / "ds.lance")
initial = SCHEMA.empty_table() if rows_before_index == 0 else rows(rows_before_index)
lance.write_dataset(initial, uri, schema=SCHEMA, mode="create", data_storage_version="2.2")
lance.dataset(uri).create_scalar_index("st.child", index_type="BTREE")
lance.write_dataset(rows(4, start=100), uri, mode="append") # a fragment the index misses
try:
lance.dataset(uri).optimize.optimize_indices()
except Exception as exc:
print(f"{label} optimize_indices() -> {type(exc).__name__}: {exc}")
else:
print(f"{label} optimize_indices() -> OK")
run("index built while empty:", rows_before_index=0)
run("index built over 8 rows:", rows_before_index=8)
Expected behavior
Both cases reach full coverage: an index over a nested field should be extendable regardless of whether the dataset held rows when the index was created.
Lance version
11.0.0
Language binding
Python
Environment
macOS 26.6.2, arm64, local
Logs / traceback
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the failing nested-field lookup near rust/lance/src/index/scalar.rs:364 and reproduce the issue using the Python script in the report. Compare index extension for an empty dataset with extension after initial rows exist. Done means optimize_indices() succeeds and the index reaches full coverage in both cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, rust
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100