Repository navigation
refactor(array): make the list_contains haystack a lookup array - #10499
robert3005 wants to merge 3 commits into
Conversation
Merging this PR will regress 1 benchmark
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ |
Simulation | test_scan_scalar_at[int_str] |
1.2 ms | 1.3 ms | -13.02% |
| ⚡ | WallTime | filter_neon[64] |
3.4 µs | 2.8 µs | +23.2% |
| ⚡ | WallTime | filter_neon[80] |
3.6 µs | 2.9 µs | +20.67% |
| ⚡ | WallTime | threshold_neon[80] |
5.6 µs | 4.7 µs | +18.75% |
| ⚡ | WallTime | threshold_neon[8] |
3.5 µs | 3 µs | +18.14% |
| ⚡ |
Simulation | random_i128[0.01] |
7.6 µs | 6.5 µs | +17.34% |
| ⚡ | Simulation | test_scan_filter_to_arrow_array[int_float] |
4.2 ms | 3.6 ms | +15.22% |
| ⚡ | WallTime | bitpack_blocked_compress_avx2 |
7.7 µs | 6.7 µs | +14.23% |
| ⚡ | WallTime | filter_avx512[64] |
2.5 µs | 2.2 µs | +12.48% |
| ⚡ | Simulation | test_repeated_scan_filter[int_float] |
4 ms | 3.5 ms | +12.03% |
| ⚡ | Simulation | test_scan_filter_to_arrow_array[int] |
2.8 ms | 2.5 ms | +10.96% |
| ⚡ | WallTime | threshold_neon[64] |
4.8 µs | 4.4 µs | +10.22% |
| ⚡ | Simulation | test_scan_filter[int] |
3.1 ms | 2.8 ms | +10% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing rk/haystack-arrays (20e06e2) with develop (c1a2ca1)
e86b215 to
4bb2b50
Compare
1820269 to
aa67ee5
Compare
aa67ee5 to
ce966ee
Compare
An `ArrayHaystack` now holds its set as an array whose encoding is built for lookups and canonicalizes to the set's elements, so the lookup structures are ordinary arrays that kernels can read. Vortex builds four in-memory lookup encodings, none of which is ever serialized: - `SortedHaystack`: integers, floats by bit pattern and decimals by unscaled value, sorted without duplicates, found by binary search. - `BitmapHaystack`: such integers over a dense span, as a smallest value and a bitmap. - `BytesHaystack`: UTF-8 or binary elements, with their hash tables kept as the array's in-memory data. - `RowsHaystack`: any other elements, recursively canonical, with the indices of the distinct elements in sorted order. An encoding outside Vortex becomes a lookup array by implementing the public `HaystackVTable`, and `ArrayHaystack::new` wraps its array. `PreparedSetData::try_with_haystack` prepares a set that looks up needles through such a haystack, and `PreparedSetData::haystack` gives a needle kernel the lookup array. A set without its own haystack still builds one lazily on the first lookup and shares it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Robert Kruszewski <github@robertk.io>
A haystack no longer decodes its needles. `HaystackVTable::contains` takes canonical needles, and `PreparedSetData::contains` returns a lazy `ListContains` over needles that are not canonical. Execution steps the needles one decoding step at a time, so a `ListContainsElementKernel` of each encoding they pass through can take the lookup before they reach the haystack. The lookup arrays read their own children by downcasting, which validation now guarantees, and read a row through their children rather than executing to canonical: a bitmap selects its nth set bit, and a row haystack indexes its elements through its order. `PreparedSetData` keeps only the haystack. The elements it cached were read only to build the haystack, whose lookup array canonicalizes to the non-null elements. Signed-off-by: Robert Kruszewski <github@robertk.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TC7eug8jjTe1e1pbDreBo9
A needle kernel in another crate can now recognize the lookup array of a prepared set, `SortedHaystack`, `BitmapHaystack`, `BytesHaystack` or `RowsHaystack`, and read its children through their public slot indices, so that it can look up its own encoded needles against that encoding. `PreparedSet::new_array` is public, so that a set made by `PreparedSetData::try_with_haystack` can be the list of a `ListContains` and reach execution. Signed-off-by: Robert Kruszewski <github@robertk.io> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TC7eug8jjTe1e1pbDreBo9
4ed093b to
20e06e2
Compare
Stacked on #10052.
What
The set that
list_containslooks needles up in is now an array.ArrayHaystackholds a lookup array: an array whose encoding is built to find needles and which canonicalizes to the set's elements. Before this change it held a privateBox<dyn HaystackState>.This answers the review question on #10052, "how do I extend this to work for new custom kernels?":
HaystackVTable(contains(array, needles, ctx) -> (BitBuffer, Validity)) can be wrapped withArrayHaystack::new.PreparedSetData::try_with_haystack(list, haystack)prepares a set that uses it.PreparedSetData::haystack(ctx)?.array()gives the lookup array, so a kernel can downcast to an encoding it knows.Built-in lookup arrays
All four are crate-private and exist only in memory:
serialize/deserializefail, and they are not registered withArraySession.SortedHaystackBitmapHaystackBoolArraybitmapBytesHaystackVarBinViewelements; the hash tables are the array's in-memory dataRowsHaystacku64indices of the distinct elements in sorted orderArrayHaystack::try_newpicks the encoding with the same rules as before, and the lookup loops are unchanged. A set without its own haystack still builds one lazily on the first lookup, and it is shared across batches, chunks and slices.PreparedSetDatanow keeps its elements and its haystack in separate lazy cells.Notes for review
ArrayHaystack,HaystackVTable,PreparedSetData::try_with_haystackandPreparedSetData::haystackare new public API. The built-in encodings staypub(crate).BytesHaystackdoes).Checks
cargo +nightly-2026-09-10 fmt -p vortex-arraycargo clippy -p vortex-array -p vortex-sequence --all-targets --all-features -- -D warnings: cleancargo nextest run -p vortex-array -p vortex-sequence: 4282 passed, 1 skipped (10 new tests inarray/haystack/tests.rs, including a lookup array of a test-only encoding)RUSTDOCFLAGS="-D warnings" cargo doc -p vortex-array --no-deps: no new warnings (it fails only on the existingtrace_macros.rslinks)typos: cleanlist_contains_setbenchmarks, doctests, and workspace-wide checks.🤖 Generated with Claude Code