Skip to content

Commit 4c20fa7

Browse files
andygrovealamb
andauthored
perf: optimize regexp_instr (40% faster) (apache#23540)
## Which issue does this PR close? N/A ## Rationale for this change Optimize existing expression. ## What changes are included in this PR? Removed per-batch default-array/Vec allocations, memoized the compiled regex across rows to skip HashMap hashing for literal patterns, and skipped the O(n) chars() scan on the default start=1 path. ## Are these changes tested? Existing tests. Benchmark (criterion): - regexp_instr_with_start [size=1024, str_len=32]: 40.073% faster (base 41127ns -> cand 24646ns) - regexp_instr_with_start [size=1024, str_len=128]: 44.498% faster (base 48215ns -> cand 26760ns) - regexp_instr_no_start [size=1024, str_len=128]: 47.253% faster (base 49244ns -> cand 25974ns) - regexp_instr_no_start [size=1024, str_len=32]: 42.18% faster (base 40495ns -> cand 23414ns) Full criterion output: ```text regexp_instr_no_start [size=1024, str_len=32] time: [23.389 µs 23.479 µs 23.645 µs] change: [−42.300% −42.180% −42.004%] (p = 0.00 < 0.05) Performance has improved. Found 9 outliers among 100 measurements (9.00%) 7 (7.00%) low mild 2 (2.00%) high severe regexp_instr_with_start [size=1024, str_len=32] time: [24.617 µs 24.635 µs 24.659 µs] change: [−40.118% −40.073% −40.026%] (p = 0.00 < 0.05) Performance has improved. Found 1 outliers among 100 measurements (1.00%) 1 (1.00%) high severe regexp_instr_no_start [size=1024, str_len=128] time: [25.756 µs 25.791 µs 25.830 µs] change: [−47.394% −47.253% −47.076%] (p = 0.00 < 0.05) Performance has improved. Found 1 outliers among 100 measurements (1.00%) 1 (1.00%) high severe regexp_instr_with_start [size=1024, str_len=128] time: [26.645 µs 26.666 µs 26.693 µs] change: [−44.577% −44.498% −44.417%] (p = 0.00 < 0.05) Performance has improved. Found 1 outliers among 100 measurements (1.00%) 1 (1.00%) high mild ``` ## Are there any user-facing changes? No <!-- If there are user-facing changes then we may require documentation to be updated before approving the PR. --> <!-- If there are any breaking changes to public APIs, please add the `api change` label. --> --------- Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
1 parent 8a37a07 commit 4c20fa7

3 files changed

Lines changed: 215 additions & 124 deletions

File tree

datafusion/functions/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ harness = false
350350
name = "regexp_count"
351351
required-features = ["regex_expressions"]
352352

353+
[[bench]]
354+
harness = false
355+
name = "regexp_instr"
356+
required-features = ["regex_expressions"]
357+
353358
[[bench]]
354359
harness = false
355360
name = "get_field"
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
use arrow::array::Int64Array;
19+
use arrow::array::OffsetSizeTrait;
20+
use arrow::datatypes::{DataType, Field};
21+
use arrow::util::bench_util::create_string_array_with_len;
22+
use criterion::{Criterion, criterion_group, criterion_main};
23+
use datafusion_common::config::ConfigOptions;
24+
use datafusion_common::{DataFusionError, ScalarValue};
25+
use datafusion_expr::{ColumnarValue, ScalarFunctionArgs};
26+
use datafusion_functions::regex;
27+
use std::hint::black_box;
28+
use std::sync::Arc;
29+
30+
fn create_args<O: OffsetSizeTrait>(
31+
size: usize,
32+
str_len: usize,
33+
with_start: bool,
34+
) -> Vec<ColumnarValue> {
35+
let string_array = Arc::new(create_string_array_with_len::<O>(size, 0.1, str_len));
36+
let pattern = ColumnarValue::Scalar(ScalarValue::Utf8(Some("a".to_string())));
37+
38+
if with_start {
39+
let start_array = Arc::new(Int64Array::from(
40+
(0..size).map(|i| (i % 10 + 1) as i64).collect::<Vec<_>>(),
41+
));
42+
vec![
43+
ColumnarValue::Array(string_array),
44+
pattern,
45+
ColumnarValue::Array(start_array),
46+
]
47+
} else {
48+
vec![ColumnarValue::Array(string_array), pattern]
49+
}
50+
}
51+
52+
fn invoke_regexp_instr_with_args(
53+
args: Vec<ColumnarValue>,
54+
number_rows: usize,
55+
) -> Result<ColumnarValue, DataFusionError> {
56+
let arg_fields = args
57+
.iter()
58+
.enumerate()
59+
.map(|(idx, arg)| Field::new(format!("arg_{idx}"), arg.data_type(), true).into())
60+
.collect::<Vec<_>>();
61+
let config_options = Arc::new(ConfigOptions::default());
62+
63+
regex::regexp_instr().invoke_with_args(ScalarFunctionArgs {
64+
args,
65+
arg_fields,
66+
number_rows,
67+
return_field: Field::new("f", DataType::Int64, true).into(),
68+
config_options: Arc::clone(&config_options),
69+
})
70+
}
71+
72+
fn criterion_benchmark(c: &mut Criterion) {
73+
let size = 1024;
74+
75+
for str_len in [32, 128] {
76+
let args = create_args::<i32>(size, str_len, false);
77+
c.bench_function(
78+
&format!("regexp_instr_no_start [size={size}, str_len={str_len}]"),
79+
|b| {
80+
b.iter(|| {
81+
black_box(invoke_regexp_instr_with_args(args.clone(), size).unwrap())
82+
})
83+
},
84+
);
85+
86+
let args = create_args::<i32>(size, str_len, true);
87+
c.bench_function(
88+
&format!("regexp_instr_with_start [size={size}, str_len={str_len}]"),
89+
|b| {
90+
b.iter(|| {
91+
black_box(invoke_regexp_instr_with_args(args.clone(), size).unwrap())
92+
})
93+
},
94+
);
95+
}
96+
}
97+
98+
criterion_group!(benches, criterion_benchmark);
99+
criterion_main!(benches);

0 commit comments

Comments
 (0)