adriangb commented on issue #11083:
URL: https://github.com/apache/arrow-rs/issues/11083#issuecomment-5689869638

   A note on an adjacent cost in the same module, in case it is useful context 
for this work. It is not a request to widen the scope of this issue.
   
   The scalar path avoids the per-row work described here, but it compiles the 
pattern once **per call**. A caller that applies one literal pattern to a long 
scan calls the kernel once per batch, so the same pattern is compiled again for 
every batch.
   
   I measured the `regex` crate directly (release build, arm64 macOS, 8192 rows 
of ~60 characters, 2000 compiles per pattern), to compare compilation with 
matching for one batch:
   
   | pattern | compile | match 8192 rows | compile share |
   |---|---:|---:|---:|
   | `abc` | 1.55 µs | 90.6 µs | 1.7% |
   | `^[a-z]+@[a-z]+\.[a-z]{2,}$` | 6.58 µs | 98.9 µs | 6.2% |
   | `(?i)error\|warn(ing)?` | 62.0 µs | 232.5 µs | 21.1% |
   | `\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?` | 249.5 µs | 103.7 µs | 
70.7% |
   
   For the last pattern, compilation is more expensive than the matching it 
enables.
   
   The interesting part is that `arrow-string` already contains the object that 
solves this. `Predicate` in `predicate.rs` analyses a pattern once, holds the 
compiled `Regex`, and evaluates a whole array (`evaluate_array`). The LIKE 
family uses it. The `regexp` module has no equivalent, and `Predicate` is 
`pub(crate)`.
   
   A public prepared type for the regexp kernels would let a caller compile 
once and reuse across batches:
   
   ```rust
   pub struct RegexPredicate { /* opaque */ }
   
   impl RegexPredicate {
       pub fn try_new(pattern: &str, flags: Option<&str>) -> Result<Self, 
ArrowError>;
       pub fn is_match(&self, array: &dyn Array) -> Result<BooleanArray, 
ArrowError>;
       pub fn matches(&self, array: &dyn Array) -> Result<ArrayRef, ArrowError>;
   }
   ```
   
   `regexp_is_match_scalar` and `regexp_match` then become thin wrappers, so 
existing callers do not change. `regex` stays a private dependency, because the 
compiled value is hidden inside an arrow type. `RowConverter` is a precedent 
for a public, reusable object of this kind.
   
   It also improves error reporting: the compile failure occurs in `try_new`, 
at a time the caller chooses, so a caller with a literal pattern can report an 
invalid pattern before execution starts instead of during it.
   
   Happy to open a separate issue for that if it is wanted, and to keep it out 
of the way of this one.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to