andygrove commented on code in PR #5215:
URL: https://github.com/apache/datafusion-comet/pull/5215#discussion_r3699497586


##########
native/spark-expr/src/predicate_funcs/rlike.rs:
##########
@@ -111,29 +135,19 @@ impl PhysicalExpr for RLike {
 
     fn evaluate(&self, batch: &RecordBatch) -> Result<ColumnarValue> {
         match self.child.evaluate(batch)? {
-            ColumnarValue::Array(array) if 
array.as_any().is::<DictionaryArray<Int32Type>>() => {
-                let dict_array = array
-                    .as_any()
-                    .downcast_ref::<DictionaryArray<Int32Type>>()
-                    .expect("dict array");
-                let dict_values = dict_array
-                    .values()
-                    .as_any()
-                    .downcast_ref::<StringArray>()
-                    .expect("strings");
+            ColumnarValue::Array(array)
+                if matches!(array.data_type(), DataType::Dictionary(_, _)) =>
+            {
+                let dict_array = as_dictionary_array::<Int32Type>(&array)?;

Review Comment:
   The guard above now matches `DataType::Dictionary(_, _)` for any key type, 
but the body still calls `as_dictionary_array::<Int32Type>`, so a 
non-`Int32`-keyed dictionary trades the old panic for an `Internal` error 
rather than actually being handled. I checked this on your branch and a 
`Dictionary(Int8, Utf8)` input gives:
   
   ```
   Err(Internal("could not cast array of type Dictionary(Int8, Utf8) to ... 
DictionaryArray<Int32Type>"))
   ```
   
   I tried `array.as_any_dictionary()` instead and it handles every key type. 
`arrow::compute::take` already accepts `indices: &dyn Array` in arrow 58, so 
`take(&new_values, dict_array.keys(), None)` works unchanged, and the 
`Int32Type` and `as_dictionary_array` imports become unnecessary. With that 
swap the `Int8`-keyed case returns the correct `[true, null, false]`. Would 
that work for you here?
   
   Worth noting the good news too: `Dictionary(Int32, Utf8View)` and 
`Dictionary(Int32, LargeUtf8)` do work correctly with your change.



##########
native/spark-expr/src/predicate_funcs/rlike.rs:
##########
@@ -88,6 +103,15 @@ impl RLike {
         }
         builder.finish()
     }
+
+    fn is_match_array(&self, array: &ArrayRef) -> Result<BooleanArray> {
+        match array.data_type() {
+            DataType::Utf8 => Ok(self.is_match(as_string_array(array)?)),
+            DataType::LargeUtf8 => 
Ok(self.is_match(as_large_string_array(array)?)),
+            DataType::Utf8View => 
Ok(self.is_match(as_string_view_array(array)?)),
+            other => exec_err!("RLike requires string type for input, got 
{other:?}"),

Review Comment:
   Small consistency question. This uses `exec_err!` while the scalar branch 
below uses `internal_err!` for the same "not a string" condition. Since a 
non-string child on `RLike` means the planner produced something invalid rather 
than the user doing something wrong, would `internal_err!` be the better fit 
for both?



##########
native/spark-expr/src/predicate_funcs/rlike.rs:
##########
@@ -37,6 +40,11 @@ use std::sync::Arc;
 /// regular expression engine, which are documented at:
 ///
 /// https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
+///
+/// Array matching keeps the plan-time compiled [`Regex`] and loops over Utf8 /

Review Comment:
   This mentions criterion benches showing regressions on patterns like 
character classes and points to #5102, but the issue only says per-batch 
compilation "is a measurable regression" without any numbers, and I do not see 
a bench added under `native/spark-expr/benches/`. Do you have the numbers 
handy? Posting them in the PR description, or adding the bench alongside the 
existing ones like `regexp_extract.rs`, would make this a much stronger 
reference for the next person who wonders why the kernel was not used.
   
   The same rationale also appears twice, here and again on `is_match`. This 
struct-level rustdoc is where the Spark-compatibility caveat lives, so an 
explanation of a rejected implementation alternative reads a little out of 
place. Keeping the single copy on `is_match` would be cleaner.



##########
native/spark-expr/src/predicate_funcs/rlike.rs:
##########
@@ -225,4 +254,60 @@ mod tests {
         let result = 
expr.evaluate(&RecordBatch::new_empty(Arc::new(Schema::empty())));
         assert!(result.is_err());
     }
+
+    #[test]
+    fn test_rlike_utf8_array() {

Review Comment:
   Thanks for adding these. A few gaps worth closing.
   
   The dictionary path is the biggest change in the diff and it does not have a 
test yet. Could you add coverage there? A `Dictionary(Int32, Utf8)` case plus a 
`Dictionary(Int32, Utf8View)` case would exercise both the layout dispatch and 
the `take`, and a non-`Int32` key case would pin down whatever behavior you 
settle on for the comment above.
   
   `Array::is_nullable()` is `logical_null_count() != 0` in arrow 58, so the 
`else` branch of `is_match` only runs when the array has no nulls. All three of 
these tests include a null, so that branch never gets hit. Adding one 
all-non-null array would close it.
   
   These three tests are also near-identical. 
`test_rlike_scalar_string_variants` right above loops over the layouts, so it 
might be nice to follow that shape here too.



-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to