Skip to content

[opt](scan) dict-filter value-derived string predicates on ORC/Parquet - #66184

Open
Baymine wants to merge 1 commit into
apache:masterfrom
Baymine:improvement/dict-filter-value-derived-predicates
Open

[opt](scan) dict-filter value-derived string predicates on ORC/Parquet#66184
Baymine wants to merge 1 commit into
apache:masterfrom
Baymine:improvement/dict-filter-value-derived-predicates

Conversation

@Baymine

@Baymine Baymine commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close #66183

Related PR: N/A

Problem Summary:

Today ORC/Parquet dictionary filtering only applies when a filter conjunct is a bare column reference compared to constants. A predicate whose value side is a deterministic single-slot string expression — e.g. split_by_string(col, sep)[n] = 'x', element_at(...), substring_index(...) — is evaluated once per row even though it depends only on the column value.

This lets such predicates be evaluated once per distinct dictionary value instead of once per row. The FE (Nereids) is the authoritative admission check: it stamps a conjunct root with can_dict_filter when the predicate is an equality/IN over a single slot, is deterministic, and preserves NULL semantics (null-in implies null-out — the dictionary carries no NULL entry, so a NULL source must map to a NULL result to match per-row semantics). The verdict is carried to BE via TExprNode.can_dict_filter; when unset (older FE) BE falls back to a conservative allowlist. A new session variable enable_dict_filter_for_expr (default true, forwarded as the enable_dict_filter_for_expr query option) gates the expression case.

Release note

Introduce dictionary-based evaluation of deterministic single-slot string expression predicates (e.g. split_by_string(col,sep)[n]='x') on ORC/Parquet scans, controlled by the new session variable enable_dict_filter_for_expr (default true). Speeds up scans that filter on a heavy string expression of a low-cardinality dictionary-encoded column.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Please explain why:
  • Behavior changed:

  • Does this need documentation?

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

What problem does this PR solve?

Issue Number: close apache#66183

Problem Summary:
Today ORC/Parquet dictionary filtering only applies when a filter conjunct
is a bare column reference compared to constants. A predicate whose value
side is a deterministic single-slot string expression -- e.g.
split_by_string(col, sep)[n] = 'x', element_at(...), substring_index(...) --
is evaluated once per row even though it depends only on the column value.

This lets such predicates be evaluated once per distinct dictionary value
instead of once per row. The FE (Nereids) is the authoritative admission
check: it stamps a conjunct root with can_dict_filter when the predicate is
an equality/IN over a single slot, is deterministic, and preserves NULL
semantics (null-in implies null-out -- the dictionary carries no NULL entry,
so a NULL source must map to a NULL result to match per-row semantics). The
verdict is carried to BE via TExprNode.can_dict_filter; when unset (older FE)
BE falls back to a conservative allowlist. A new session variable
enable_dict_filter_for_expr (default true, forwarded as the
enable_dict_filter_for_expr query option) gates the expression case.

Release note:
Introduce dictionary-based evaluation of deterministic single-slot string
expression predicates (e.g. split_by_string(col,sep)[n]='x') on ORC/Parquet
scans, controlled by the new session variable enable_dict_filter_for_expr
(default true). Speeds up scans that filter on a heavy string expression of a
low-cardinality dictionary-encoded column.

Check List (For author)
- [x] Test <!-- At least one of them must be included. -->
    - [ ] Regression test
    - [x] Unit Test
    - [ ] Manual test (add detailed scripts or steps below)

- [ ] No need for documentation
@Baymine

Baymine commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 73.47% (36/49) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 68.48% (63/92) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 58.19% (24683/42417)
Line Coverage 42.25% (246736/583961)
Region Coverage 38.14% (196047/514071)
Branch Coverage 39.26% (88550/225531)

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29878 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit dfedfeb0f9c52cce7745f7b9f014a9f95802878f, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17647	4115	4117	4115
q2	2048	330	205	205
q3	10526	1476	855	855
q4	4785	475	338	338
q5	8236	887	572	572
q6	343	172	137	137
q7	860	823	617	617
q8	10687	1573	1694	1573
q9	6197	4405	4353	4353
q10	6807	1721	1466	1466
q11	509	351	324	324
q12	741	577	457	457
q13	18117	3412	2804	2804
q14	275	265	234	234
q15	q16	793	771	712	712
q17	1066	1026	1039	1026
q18	6965	5819	5524	5524
q19	1174	1255	1133	1133
q20	843	684	563	563
q21	5653	2566	2566	2566
q22	425	350	304	304
Total cold run time: 104697 ms
Total hot run time: 29878 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4465	4357	4425	4357
q2	286	321	218	218
q3	4594	4991	4407	4407
q4	2077	2137	1357	1357
q5	4420	4272	4357	4272
q6	361	213	165	165
q7	2181	1803	1640	1640
q8	2484	2194	2191	2191
q9	8131	7810	7758	7758
q10	4650	4680	4207	4207
q11	589	441	388	388
q12	760	760	536	536
q13	3289	3556	2989	2989
q14	295	317	298	298
q15	q16	693	763	654	654
q17	1392	1313	1492	1313
q18	8020	7261	7327	7261
q19	1190	1119	1088	1088
q20	2218	2228	1942	1942
q21	5209	4576	4323	4323
q22	514	446	403	403
Total cold run time: 57818 ms
Total hot run time: 51767 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 177734 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit dfedfeb0f9c52cce7745f7b9f014a9f95802878f, data reload: false

query5	4336	630	499	499
query6	472	224	216	216
query7	4852	570	340	340
query8	346	192	173	173
query9	8788	4052	4055	4052
query10	507	365	317	317
query11	5902	2314	2171	2171
query12	156	100	98	98
query13	1247	620	421	421
query14	6232	5167	4844	4844
query14_1	4228	4237	4212	4212
query15	208	203	173	173
query16	1051	480	436	436
query17	1137	712	563	563
query18	2472	472	335	335
query19	202	210	147	147
query20	116	108	108	108
query21	236	158	133	133
query22	13567	13671	13464	13464
query23	17413	16586	16073	16073
query23_1	16280	16322	16302	16302
query24	7781	1739	1297	1297
query24_1	1289	1324	1294	1294
query25	559	479	403	403
query26	1334	339	213	213
query27	2634	591	362	362
query28	4478	1974	2003	1974
query29	1075	635	501	501
query30	347	270	227	227
query31	1114	1100	988	988
query32	109	65	63	63
query33	552	334	259	259
query34	1183	1169	650	650
query35	766	793	656	656
query36	1059	1047	912	912
query37	158	118	106	106
query38	1870	1717	1668	1668
query39	893	867	853	853
query39_1	836	843	837	837
query40	254	176	148	148
query41	73	72	70	70
query42	97	94	93	93
query43	324	334	283	283
query44	1457	779	764	764
query45	194	188	178	178
query46	1056	1215	701	701
query47	2123	2105	2057	2057
query48	412	425	295	295
query49	588	421	314	314
query50	1122	456	325	325
query51	10967	10824	10565	10565
query52	89	92	78	78
query53	267	290	207	207
query54	303	265	241	241
query55	77	76	71	71
query56	311	317	298	298
query57	1352	1321	1213	1213
query58	295	279	268	268
query59	1610	1609	1440	1440
query60	318	271	263	263
query61	206	149	153	149
query62	540	498	432	432
query63	245	205	203	203
query64	2830	1030	859	859
query65	4694	4566	4574	4566
query66	1834	503	388	388
query67	29590	29245	29110	29110
query68	3131	1517	940	940
query69	408	299	277	277
query70	938	832	821	821
query71	345	335	319	319
query72	3097	2773	2395	2395
query73	799	736	447	447
query74	5068	4919	4733	4733
query75	2547	2481	2120	2120
query76	2355	1200	776	776
query77	356	379	281	281
query78	11785	11801	11416	11416
query79	1415	1167	771	771
query80	1308	573	530	530
query81	519	332	290	290
query82	649	159	121	121
query83	371	324	304	304
query84	288	167	134	134
query85	972	608	530	530
query86	404	248	215	215
query87	1839	1811	1754	1754
query88	3758	2812	2786	2786
query89	443	379	333	333
query90	1909	208	201	201
query91	206	197	167	167
query92	63	59	53	53
query93	1660	1650	976	976
query94	715	366	293	293
query95	790	518	504	504
query96	1103	811	327	327
query97	2638	2662	2482	2482
query98	212	210	202	202
query99	1090	1132	978	978
Total cold run time: 264566 ms
Total hot run time: 177734 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 25 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit dfedfeb0f9c52cce7745f7b9f014a9f95802878f, data reload: false

query1	0.01	0.02	0.01
query2	0.10	0.05	0.05
query3	0.27	0.14	0.14
query4	1.61	0.15	0.15
query5	0.24	0.22	0.23
query6	1.24	1.03	1.10
query7	0.04	0.01	0.00
query8	0.06	0.04	0.03
query9	0.38	0.32	0.31
query10	0.56	0.58	0.57
query11	0.20	0.14	0.14
query12	0.18	0.14	0.14
query13	0.48	0.46	0.47
query14	1.03	1.02	1.01
query15	0.62	0.60	0.59
query16	0.33	0.34	0.33
query17	1.08	1.15	1.14
query18	0.22	0.21	0.20
query19	2.06	1.92	1.96
query20	0.02	0.01	0.01
query21	15.43	0.24	0.14
query22	4.78	0.05	0.05
query23	16.11	0.31	0.12
query24	2.94	0.42	0.32
query25	0.12	0.05	0.04
query26	0.73	0.21	0.14
query27	0.06	0.04	0.03
query28	3.48	0.99	0.53
query29	12.53	4.07	3.27
query30	0.27	0.19	0.16
query31	2.77	0.60	0.31
query32	3.23	0.60	0.48
query33	3.11	3.16	3.19
query34	15.58	4.22	3.49
query35	3.48	3.52	3.55
query36	0.55	0.43	0.43
query37	0.09	0.07	0.07
query38	0.06	0.04	0.04
query39	0.04	0.02	0.02
query40	0.18	0.16	0.15
query41	0.08	0.03	0.02
query42	0.03	0.03	0.03
query43	0.04	0.03	0.03
Total cold run time: 96.42 s
Total hot run time: 25 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 79.35% (73/92) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.38% (31181/41364)
Line Coverage 59.91% (347535/580130)
Region Coverage 56.47% (291327/515862)
Branch Coverage 57.82% (130436/225599)

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement] Evaluate deterministic single-slot string expression predicates on the ORC/Parquet column dictionary

2 participants