Skip to content

parquet: decoder-level dictionary filter pushdown for Parquet reader#9464

Open
lyang24 wants to merge 1 commit intoapache:mainfrom
lyang24:dict_decoder_predict_pushdown
Open

parquet: decoder-level dictionary filter pushdown for Parquet reader#9464
lyang24 wants to merge 1 commit intoapache:mainfrom
lyang24:dict_decoder_predict_pushdown

Conversation

@lyang24
Copy link
Contributor

@lyang24 lyang24 commented Feb 23, 2026

Which issue does this PR close?

Rationale for this change

For dictionary-encoded columns, we previously converted the dictionary data into a StringViewArray and then applied the filter. This approach materialized every row in the column before filtering, which introduced overhead.

What changes are included in this PR?

We introduced DictFilterDecoder for columns that are 100% dictionary encoded.
The decoder first processes the dictionary keys, then applies the filter.
After that, it expands null values.
Finally, it filters the dictionary values and materializes only the rows that pass the filter.

Are these changes tested?

existing test should pass added additional tests

Are there any user-facing changes?

yes added an new api with_dict_pushdown to opt in to enable the predicate pushdown on predicates

@github-actions github-actions bot added the parquet Changes to the parquet crate label Feb 23, 2026
@lyang24 lyang24 changed the title perf: decoder-level dictionary filter pushdown for Parquet reader parquet: decoder-level dictionary filter pushdown for Parquet reader Feb 23, 2026
@lyang24 lyang24 force-pushed the dict_decoder_predict_pushdown branch 4 times, most recently from a4545dd to 644295d Compare February 26, 2026 00:47
Push predicate evaluation into the decoder for dictionary-encoded
BYTE_ARRAY columns. Instead of decoding all rows into StringViewArray
and then filtering, this evaluates the predicate once on the small
dictionary (~N unique values), then maps integer keys to booleans
via a simple lookup — no intermediate arrays are created for data rows.

Two-phase approach:
- Phase 1: decode dictionary page, evaluate predicate, produce
  matching_keys: Vec<bool> per row group
- Phase 2: DictFilterDecoder reads RLE-encoded integer keys and
  maps each key to matching_keys[key], producing a BooleanArray
  that feeds directly into RowSelection

Adds ArrowPredicate::use_dictionary_encoding() opt-in flag and
falls back to the normal path for multi-column predicates,
non-BYTE_ARRAY types, nested columns, or PLAIN-encoded pages.
@lyang24 lyang24 force-pushed the dict_decoder_predict_pushdown branch from 644295d to 53bd848 Compare February 26, 2026 05:37
@lyang24
Copy link
Contributor Author

lyang24 commented Feb 26, 2026

Hi @Dandandan, can you please help me summon the gh bots for clickbenches.

@lyang24 lyang24 marked this pull request as ready for review February 27, 2026 02:48
@Dandandan
Copy link
Contributor

run benchmark arrow_reader_clickbench

@Dandandan
Copy link
Contributor

Hi @Dandandan, can you please help me summon the gh bots for clickbenches.

Sorry, missed your message. Started now!

@alamb-ghbot
Copy link

🤖 ./gh_compare_arrow.sh gh_compare_arrow.sh Running
Linux aal-dev 6.14.0-1018-gcp #19~24.04.1-Ubuntu SMP Wed Sep 24 23:23:09 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
Comparing dict_decoder_predict_pushdown (53bd848) to 442e1b8 diff
BENCH_NAME=arrow_reader_clickbench
BENCH_COMMAND=cargo bench --features=arrow,async,test_common,experimental,object_store --bench arrow_reader_clickbench
BENCH_FILTER=
BENCH_BRANCH_NAME=dict_decoder_predict_pushdown
Results will be posted here when complete

@alamb-ghbot
Copy link

🤖: Benchmark completed

Details

group                                             dict_decoder_predict_pushdown          main
-----                                             -----------------------------          ----
arrow_reader_clickbench/async/Q1                  1.00      2.3±0.02ms        ? ?/sec    1.00      2.3±0.01ms        ? ?/sec
arrow_reader_clickbench/async/Q10                 1.00     10.5±0.15ms        ? ?/sec    1.02     10.7±0.12ms        ? ?/sec
arrow_reader_clickbench/async/Q11                 1.00     12.1±0.14ms        ? ?/sec    1.03     12.4±0.17ms        ? ?/sec
arrow_reader_clickbench/async/Q12                 1.00     21.6±0.21ms        ? ?/sec    1.02     22.1±0.60ms        ? ?/sec
arrow_reader_clickbench/async/Q13                 1.00     27.1±0.16ms        ? ?/sec    1.00     27.2±0.20ms        ? ?/sec
arrow_reader_clickbench/async/Q14                 1.00     24.1±0.18ms        ? ?/sec    1.02     24.6±0.22ms        ? ?/sec
arrow_reader_clickbench/async/Q19                 1.00      5.4±0.04ms        ? ?/sec    1.00      5.4±0.06ms        ? ?/sec
arrow_reader_clickbench/async/Q20                 1.01    113.4±0.79ms        ? ?/sec    1.00    112.0±0.71ms        ? ?/sec
arrow_reader_clickbench/async/Q21                 1.01    126.2±0.58ms        ? ?/sec    1.00    124.6±0.44ms        ? ?/sec
arrow_reader_clickbench/async/Q22                 1.02    183.8±5.25ms        ? ?/sec    1.00    180.9±5.54ms        ? ?/sec
arrow_reader_clickbench/async/Q23                 1.01    401.7±2.02ms        ? ?/sec    1.00    398.7±2.11ms        ? ?/sec
arrow_reader_clickbench/async/Q24                 1.00     30.4±0.33ms        ? ?/sec    1.00     30.4±0.32ms        ? ?/sec
arrow_reader_clickbench/async/Q27                 1.02     99.0±0.66ms        ? ?/sec    1.00     97.1±0.61ms        ? ?/sec
arrow_reader_clickbench/async/Q28                 1.01     95.7±0.61ms        ? ?/sec    1.00     94.6±0.39ms        ? ?/sec
arrow_reader_clickbench/async/Q30                 1.00     26.5±0.20ms        ? ?/sec    1.01     26.9±0.38ms        ? ?/sec
arrow_reader_clickbench/async/Q36                 1.01     29.0±0.17ms        ? ?/sec    1.00     28.8±0.31ms        ? ?/sec
arrow_reader_clickbench/async/Q37                 1.00      9.4±0.06ms        ? ?/sec    1.01      9.5±0.08ms        ? ?/sec
arrow_reader_clickbench/async/Q38                 1.01     25.3±0.19ms        ? ?/sec    1.00     25.0±0.23ms        ? ?/sec
arrow_reader_clickbench/async/Q39                 1.00     42.6±0.29ms        ? ?/sec    1.00     42.5±0.32ms        ? ?/sec
arrow_reader_clickbench/async/Q40                 1.00     13.0±0.16ms        ? ?/sec    1.02     13.2±0.22ms        ? ?/sec
arrow_reader_clickbench/async/Q41                 1.00     10.2±0.05ms        ? ?/sec    1.00     10.2±0.11ms        ? ?/sec
arrow_reader_clickbench/async/Q42                 1.00      5.7±0.02ms        ? ?/sec    1.00      5.7±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q1     1.01      2.3±0.04ms        ? ?/sec    1.00      2.3±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q10    1.00     10.1±0.13ms        ? ?/sec    1.01     10.2±0.11ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q11    1.00     11.5±0.14ms        ? ?/sec    1.00     11.5±0.12ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q12    1.01     21.2±0.31ms        ? ?/sec    1.00     21.1±0.35ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q13    1.01     26.2±0.24ms        ? ?/sec    1.00     25.9±0.21ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q14    1.01     23.7±0.26ms        ? ?/sec    1.00     23.4±0.18ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q19    1.01      5.1±0.12ms        ? ?/sec    1.00      5.1±0.04ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q20    1.01    108.9±0.39ms        ? ?/sec    1.00    107.5±0.54ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q21    1.01    121.2±1.33ms        ? ?/sec    1.00    120.0±0.87ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q22    1.01    149.2±0.91ms        ? ?/sec    1.00    147.2±0.56ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q23    1.05   370.5±10.31ms        ? ?/sec    1.00   353.4±14.31ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q24    1.00     28.7±0.22ms        ? ?/sec    1.00     28.7±0.36ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q27    1.01     94.1±0.39ms        ? ?/sec    1.00     92.9±0.58ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q28    1.01     91.5±1.08ms        ? ?/sec    1.00     90.7±1.25ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q30    1.00     25.3±0.54ms        ? ?/sec    1.00     25.4±0.17ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q36    1.01     26.0±0.59ms        ? ?/sec    1.00     25.8±0.24ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q37    1.01      9.3±0.06ms        ? ?/sec    1.00      9.2±0.03ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q38    1.01     22.2±0.26ms        ? ?/sec    1.00     22.0±0.19ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q39    1.00     38.0±0.28ms        ? ?/sec    1.00     37.9±0.38ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q40    1.02     12.6±0.62ms        ? ?/sec    1.00     12.3±0.09ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q41    1.00      9.8±0.19ms        ? ?/sec    1.00      9.7±0.10ms        ? ?/sec
arrow_reader_clickbench/async_object_store/Q42    1.00      5.5±0.08ms        ? ?/sec    1.02      5.6±0.14ms        ? ?/sec
arrow_reader_clickbench/sync/Q1                   1.00  1982.5±12.38µs        ? ?/sec    1.01  1997.3±16.98µs        ? ?/sec
arrow_reader_clickbench/sync/Q10                  1.00      6.2±0.17ms        ? ?/sec    1.21      7.5±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q11                  1.00      7.6±0.13ms        ? ?/sec    1.17      8.8±0.11ms        ? ?/sec
arrow_reader_clickbench/sync/Q12                  1.00     28.1±0.79ms        ? ?/sec    1.01     28.4±1.36ms        ? ?/sec
arrow_reader_clickbench/sync/Q13                  1.30     42.1±0.57ms        ? ?/sec    1.00     32.3±0.30ms        ? ?/sec
arrow_reader_clickbench/sync/Q14                  1.01     30.4±0.77ms        ? ?/sec    1.00     30.2±0.37ms        ? ?/sec
arrow_reader_clickbench/sync/Q19                  1.01      4.3±0.08ms        ? ?/sec    1.00      4.2±0.05ms        ? ?/sec
arrow_reader_clickbench/sync/Q20                  1.02    176.6±1.90ms        ? ?/sec    1.00    172.7±0.77ms        ? ?/sec
arrow_reader_clickbench/sync/Q21                  1.02    131.5±0.75ms        ? ?/sec    1.00    128.9±0.69ms        ? ?/sec
arrow_reader_clickbench/sync/Q22                  1.02    207.9±1.52ms        ? ?/sec    1.00    204.4±1.88ms        ? ?/sec
arrow_reader_clickbench/sync/Q23                  1.04   428.1±15.78ms        ? ?/sec    1.00    412.6±3.28ms        ? ?/sec
arrow_reader_clickbench/sync/Q24                  1.04     39.7±0.43ms        ? ?/sec    1.00     38.1±0.36ms        ? ?/sec
arrow_reader_clickbench/sync/Q27                  1.02    152.4±1.67ms        ? ?/sec    1.00    148.7±1.12ms        ? ?/sec
arrow_reader_clickbench/sync/Q28                  1.02    144.8±0.74ms        ? ?/sec    1.00    142.2±0.83ms        ? ?/sec
arrow_reader_clickbench/sync/Q30                  1.00     26.9±0.35ms        ? ?/sec    1.00     26.8±0.29ms        ? ?/sec
arrow_reader_clickbench/sync/Q36                  1.03     32.8±0.81ms        ? ?/sec    1.00     31.9±0.46ms        ? ?/sec
arrow_reader_clickbench/sync/Q37                  1.01     10.3±0.13ms        ? ?/sec    1.00     10.3±0.08ms        ? ?/sec
arrow_reader_clickbench/sync/Q38                  1.00     18.2±0.27ms        ? ?/sec    1.01     18.3±0.26ms        ? ?/sec
arrow_reader_clickbench/sync/Q39                  1.01     30.8±0.67ms        ? ?/sec    1.00     30.6±0.37ms        ? ?/sec
arrow_reader_clickbench/sync/Q40                  1.00      8.8±0.10ms        ? ?/sec    1.00      8.8±0.11ms        ? ?/sec
arrow_reader_clickbench/sync/Q41                  1.01      9.1±0.17ms        ? ?/sec    1.00      9.0±0.12ms        ? ?/sec
arrow_reader_clickbench/sync/Q42                  1.00      6.7±0.04ms        ? ?/sec    1.00      6.6±0.03ms        ? ?/sec

@lyang24
Copy link
Contributor Author

lyang24 commented Mar 2, 2026

interetsing i have the opposite results on q13 locally

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parquet Changes to the parquet crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Push down (scalar) filters down to Parquet encoders

3 participants