lance-format / lance-format/lance

Error with TakeExec and highly nested data

Open
#3,578 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Rust
Stars
7.1k
Forks
852
Avg merge
3d 18h
Merged PRs (30d)
272

Description

There seems to be an issue with nested data, when retrieving with a filter. This was originally reported upstream: https://github.com/lancedb/lancedb/issues/2217

import lance
import pyarrow as pa

data = pa.Table.from_pylist([
    {
            "item": "test",
            "sub_obj": {
                "second_sub_obj": [
                    {
                        "third_sub_obj": {"int_val": 1},
                        "str_val": "test",
                    }
                ]
            },
        }
])

ds = lance.write_dataset(data, "memory://" )

ds.to_table() # works fine

ds.to_table(filter="item == 'test'") # errors
OSError: Io error: Arrow error: Invalid argument error: column types must match schema types, expected Struct([Field { name: "second_sub_obj", data_type: List(Field { name: "item", data_type: Struct([Field { name: "str_val", data_type: Utf8, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: "third_sub_obj", data_type: Struct([Field { name: "int_val", data_type: Int64, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) but found Struct([Field { name: "second_sub_obj", data_type: List(Field { name: "item", data_type: Struct([Field { name: "third_sub_obj", data_type: Struct([Field { name: "int_val", data_type: Int64, nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }]) at column index 1

basically the difference is:

expected:

struct
  "second_sub_obj": List
    item: struct
      "str_val": string
      "third_sub_obj": struct
        "int_val": int64


found:

struct
  "second_sub_obj": List
    item: struct
      "third_sub_obj": struct
        "int_val": int64

So it's missing "str_val" in there. Which is confusing, because without the filter we find that field in the output.

I think this has to do with V2 storage, since this works fine if we do legacy storage though:

ds = lance.write_dataset(data, "memory://", data_storage_version="legacy" )
ds.to_table(filter="item == 'test'") # fine
pyarrow.Table
item: string
sub_obj: struct<second_sub_obj: list<item: struct<str_val: string, third_sub_obj: struct<int_val: int64>>>>
  child 0, second_sub_obj: list<item: struct<str_val: string, third_sub_obj: struct<int_val: int64>>>
      child 0, item: struct<str_val: string, third_sub_obj: struct<int_val: int64>>
          child 0, str_val: string
          child 1, third_sub_obj: struct<int_val: int64>
              child 0, int_val: int64
----
item: [["test"]]
sub_obj: [
  -- is_valid: all not null
  -- child 0 type: list<item: struct<str_val: string, third_sub_obj: struct<int_val: int64>>>
[      -- is_valid: all not null
      -- child 0 type: string
["test"]
      -- child 1 type: struct<int_val: int64>
        -- is_valid: all not null
        -- child 0 type: int64

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the nested PyArrow dataset case with lance.write_dataset using default V2 storage, then compare ds.to_table() with and without filter="item == 'test'" and with the legacy storage variant. Trace the filtered read path and nested schema handling; done means the filtered result preserves str_val and matches the unfiltered schema without the reported Arrow error.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
data-engineering, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.