Repository navigation
Bench: Cover Boolean filtering and oversized dictionaries - #12054
Conversation
|
run benchmark filter_kernels |
|
run benchmark row_format |
|
🤖 Benchmark starting (GKE) | trigger Target: row_format Sharding factor: 1 (1 workers). Comparing rich-T-kid/dictionary-concat-ratio-bench (37da834) to b231cf1 (merge-base) diff Run configurationrun benchmark row_format
env:
BENCH_FILTER: convert_columns_prepared 8192 string_dictionary
shards: 1
Results will be posted when all workers finish. File an issue against this benchmark runner |
|
🤖 Benchmark starting (GKE) | trigger Target: filter_kernels Sharding factor: 1 (1 workers). Comparing rich-T-kid/dictionary-concat-ratio-bench (37da834) to b231cf1 (merge-base) diff Run configurationrun benchmark filter_kernels
env:
BENCH_FILTER: filter boolean
shards: 1
Results will be posted when all workers finish. File an issue against this benchmark runner |
|
run benchmark concatenate_kernel |
|
🤖 Benchmark starting (GKE) | trigger Target: concatenate_kernel Sharding factor: 1 (1 workers). Comparing rich-T-kid/dictionary-concat-ratio-bench (37da834) to b231cf1 (merge-base) diff Run configurationrun benchmark concatenate_kernel
env:
BENCH_FILTER: concat str_dict_slice
shards: 1
Results will be posted when all workers finish. File an issue against this benchmark runner |
|
🤖 Benchmark completed (GKE) | trigger Target: row_format Comparing rich-T-kid/dictionary-concat-ratio-bench (37da834) to b231cf1 (merge-base) diff Run configurationrun benchmark row_format
env:
BENCH_FILTER: convert_columns_prepared 8192 string_dictionary
shards: 1
DetailsPer-runner informationrow_format — shard 1/1Node: gk3-benchmark-cluster-nap-1q2slmnr-b33373f7-5pzx Instance: c4a-highmem-16 (12 vCPU / 65 GiB) uname: BENCH_COMMAND: cargo bench --features=arrow,async,test_common,experimental,object_store --bench row_formatCPU Details (lscpu)Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
|
🤖 Benchmark completed (GKE) | trigger Target: concatenate_kernel Comparing rich-T-kid/dictionary-concat-ratio-bench (37da834) to b231cf1 (merge-base) diff Run configurationrun benchmark concatenate_kernel
env:
BENCH_FILTER: concat str_dict_slice
shards: 1
DetailsPer-runner informationconcatenate_kernel — shard 1/1Node: gk3-benchmark-cluster-nap-35k6403m-e6737b58-4fjg Instance: c4a-highmem-16 (12 vCPU / 65 GiB) uname: BENCH_COMMAND: cargo bench --features=arrow,async,test_common,experimental,object_store --bench concatenate_kernelCPU Details (lscpu)Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
|
🤖 Benchmark completed (GKE) | trigger Target: filter_kernels Comparing rich-T-kid/dictionary-concat-ratio-bench (37da834) to b231cf1 (merge-base) diff Run configurationrun benchmark filter_kernels
env:
BENCH_FILTER: filter boolean
shards: 1
DetailsPer-runner informationfilter_kernels — shard 1/1Node: gk3-benchmark-cluster-nap-1q2slmnr-f9d718d9-5nfz Instance: c4a-highmem-16 (12 vCPU / 65 GiB) uname: BENCH_COMMAND: cargo bench --features=arrow,async,test_common,experimental,object_store --bench filter_kernelsCPU Details (lscpu)Resource Usagebase (merge-base)
branch
File an issue against this benchmark runner |
|
@etseidl could you take a look, just benchmarks and I double checked that they run |
|
Sure, but it will be later this evening. |
etseidl
left a comment
There was a problem hiding this comment.
Nvm, it was smaller than I thought. 😅
|
thanks @etseidl |
…2043) ## Why Closes apache#11901. The benchmark coverage for this change is in the consolidated benchmark PR apache#12054. `RowConverter` currently encodes every value in a dictionary before converting a batch. For an 8,192-row slice backed by a large dictionary, the work therefore scales with the retained values array rather than the rows being converted. ```text DictionaryArray keys: 8,192 rows --------+ +--> RowConverter --> 8,192 encoded rows values: 1,000,000 strings ---+ before: encode all 1,000,000 values --> look up 8,192 keys after: gather 8,192 row values --> encode the row-aligned values ``` This is a smaller follow-up to apache#11904. It avoids the hash map and per-row remap used there, and uses the benchmark crossover requested in [review](apache#11904 (comment)) to keep small and dense dictionaries on the existing path. ## What changed When a dictionary has at least 32K values and its values array is at least four times longer than the input, gather one value per row and encode that row-aligned array. All other dictionaries keep the existing dictionary-key lookup path. The benchmark sweep put the crossover between 20K and 24.6K values. The 32K / 4x guard is deliberately conservative. ## Results The [hosted exact-ref run](apache#12043 (comment)) is flat at 10K, 1.3x faster at 32K, 3.45x at 100K, and about 33x at 1M. Row decoding is unchanged, and peak memory drops from 56.8 MiB to 29.5 MiB. ## Test coverage One test checks row equality and round-trip decoding for a sliced dictionary with repeated high keys and nulls.
# Which issue does this PR close? Closes apache#11885 # Why is this change needed? Slicing a dictionary array only slices its keys; it still retains the full values array. When concat or interleave merges short slices from large dictionaries, the current code builds a mask and key mapping for every dictionary value, including values that no selected row references. The work therefore scales with the full dictionary instead of the number of output rows. ```text Example: one 682-row slice backed by 1,000,000 dictionary values slice keys: [900_000, 17, 900_000, ...] 682 entries | | v v retained values: [v0, ... v17, ... v900_000, ...] 1,000,000 entries old new | | allocate and scan by values.len() scan the selected keys | | 1,000,000-slot referenced mask sort + deduplicate 1,000,000-slot key mapping {17, 900_000, ...} | | +---------------+----------------+ v same merged dictionary for concat / interleave ``` # What changes are included in this PR? When a dictionary has more than 256 values per key lookup, collect only the referenced keys and store the old-to-new key mappings sparsely. The gate uses the number of remaps performed by concat or interleave, rather than the number of distinct selected rows, so mostly-null and repeatedly selected inputs stay on the dense path when hashing would be slower. Let `r` be the number of selected rows, `l` the number of key lookups, `u` the number of unique referenced keys, and `v` the number of retained dictionary values. The sparse path collects keys in `O(r)`, sorts them in `O(r log r)`, deduplicates them in `O(r)`, builds the hash mapping in `O(u)` expected time, and remaps the output in `O(l)` expected time. This replaces the dense path's `O(v)` mask and mapping work. Sorting also makes repeated keys adjacent and preserves the ascending dictionary-key order produced by the dense mask path, so both paths build the merged dictionary in the same order. Both concat and interleave use this shared dictionary merge path. BatchCoalescer has a separate dictionary merge path and is intentionally left for a follow-up. # Are these changes tested? Tests cover concat and interleave of short slices backed by large dictionaries, the key-lookup gate, sparse primitive dictionaries, null dictionary values, null keys, `UInt8` key overflow, and the existing dense path. The benchmark now covers ratios of 12, 16, 24, 128, 256, 400, and 1024 values per key with both contiguous and scattered keys. [Review measurements](apache#12008 (comment)) placed the scattered-key crossover near 256:1: at 400:1 the measured head/base ratios were 0.57-0.84, and at 1024:1 they were 0.35-0.56. The earlier [hosted run](apache#12008 (comment)) improved the 12:1, 16:1, and 24:1 dense-path cases by 10.0%, 8.5%, and 8.7%. The benchmark harness was introduced in apache#12054. # Are there any significant user-facing changes? No. This only changes how dictionary values are merged internally.
Which issue does this PR close?
Part of #11885. Adds benchmark coverage for #11901 and #12008, and follows up on the Boolean filter coverage requested in #11918.
This consolidates and supersedes #11980 and #12041.
Why is this change needed?
The existing suites do not cover Boolean arrays as filter data or the cost of operating on small key ranges backed by oversized dictionaries. They also do not exercise the 16-values-per-selected-key boundary between dense and sparse dictionary mappings.
What changes are included in this PR?
RowConvertercases for rotating 8,192-key ranges backed by unique string dictionaries with 1M and 4M values.RowConverterconstruction.Are these changes tested?
Built and ran each filtered benchmark locally.
Benchmark bot runs:
filter_kernelsrow_formatconcatenate_kernelAre there any significant user-facing changes?
No. This only adds benchmark coverage.