comphead commented on code in PR #6968:
URL: https://github.com/apache/datafusion-comet/pull/6968#discussion_r4274439443


##########
spark/src/test/scala/org/apache/comet/CometExpressionSuite.scala:
##########
@@ -195,6 +195,44 @@ class CometExpressionSuite extends CometTestBase with 
AdaptiveSparkPlanHelper {
     }
   }
 
+  test("nested sort keys keep root and interior null ordering separate in 
native") {

Review Comment:
   `nested sort keys keep root and interior null ordering separate in native` 
repeats `sort_nested_null_order.sql`, which already runs `ORDER BY ... ASC 
NULLS LAST`, a TopK and a `DENSE_RANK` window over nested null keys, and 
`query` mode already asserts the plan is native. Could it go?
   
   The `default array_sort` test below it (line 221) fits an SQL file with `-- 
Config: spark.comet.exec.scalaUDF.codegen.enabled=false`, next to 
`array_sort_comparator.sql`. It only covers `ARRAY<ARRAY<INT>>` today, so a 
fixture could add string, binary, decimal, date and timestamp elements, struct 
elements with null fields, empty and all-null arrays, and a `containsNull = 
false` input such as `array_sort(array(coalesce(i, 0), 1))`. I could not find a 
test that reaches the `noNulls` branch of `usesDefaultComparator`. The 
collation test in `CometArrayExpressionSuite` could move the same way with `-- 
MinSparkVersion: 4.0` and `expect_fallback`.



##########
native/spark-expr/src/array_funcs/sort_array.rs:
##########
@@ -109,6 +109,62 @@ fn constant(value: &ColumnarValue) -> Option<bool> {
     }
 }
 
+/// Spark's default `array_sort` comparator. It puts null elements last, but 
compares nulls
+/// inside arrays and structs below non-null values.
+#[derive(Debug, Hash, Eq, PartialEq)]
+pub struct SparkArraySort {
+    signature: Signature,
+}
+
+impl Default for SparkArraySort {
+    fn default() -> Self {
+        Self {
+            signature: Signature::any(1, Volatility::Immutable),
+        }
+    }
+}
+
+impl ScalarUDFImpl for SparkArraySort {
+    fn name(&self) -> &str {
+        "spark_array_sort"
+    }
+
+    fn signature(&self) -> &Signature {
+        &self.signature
+    }
+
+    fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
+        Ok(arg_types[0].clone())
+    }
+
+    fn invoke_with_args(&self, args: ScalarFunctionArgs) -> 
Result<ColumnarValue> {
+        let [array] = take_function_args(self.name(), &args.args)?;
+        let is_scalar = matches!(array, ColumnarValue::Scalar(_));
+        let rows = if is_scalar { 1 } else { args.number_rows };
+        let array = array.to_array(rows)?;
+        let Some(list) = array.as_list_opt::<i32>() else {
+            return exec_err!("spark_array_sort takes a list, got {}", 
array.data_type());
+        };
+        let values = list.values();
+        let compare = spark_comparator(values.as_ref(), values.as_ref())?;
+        let result = sort_by(list, true, |a, b| {
+            match (values.is_null(a), values.is_null(b)) {

Review Comment:
   The closure already orders null elements itself, but `spark_comparator` 
tests the same top-level nulls again inside every comparison, and 
`values.is_null(a)` and `values.is_null(b)` are two further null-buffer lookups 
per call. `spark_comparator_ignoring_nulls` exists for callers that apply 
top-level nulls themselves and `nested_comparison.rs` already uses it. Would it 
work here? Taking `values.nulls().filter(|n| n.null_count() > 0)` once would 
also let an array without null elements pass `compare` straight to `sort_by`. 
The speedup is an expectation and I did not benchmark it.



##########
spark/src/main/scala/org/apache/comet/serde/arrays.scala:
##########
@@ -1172,7 +1172,39 @@ object CometArrayForAll extends 
CometCodegenDispatch[ArrayForAll]
 
 object CometArrayAggregate extends CometCodegenDispatch[ArrayAggregate]
 
-object CometArraySort extends CometCodegenDispatch[ArraySort]
+object CometArraySort extends CometCodegenDispatch[ArraySort] with 
CometTypeShim {

Review Comment:
   `GenerateDocs` labels every plain `CometCodegenDispatch` as `Codegen 
dispatch`, so `docs/source/user-guide/latest/expressions.md` keeps `| 
array_sort | ✅ | Codegen dispatch |  |` although the default comparator now 
runs natively. `CometArrayFilter` has the same shape, a native fast path for 
one lambda form and the codegen dispatcher for the rest. It extends 
`CometExpressionSerde` and its row reads `Native` with a note about the general 
lambda going through the dispatcher. Could `CometArraySort` follow that pattern 
and the `array_sort` row get a matching note for custom comparators and 
non-default collations?



##########
spark/src/test/resources/sql-tests/operators/sort_nested_null_order.sql:
##########
@@ -17,13 +17,8 @@
 
 -- Spark orders a null element of an array key, or a null field of a struct 
key, below every
 -- other value, whatever the key's NULLS FIRST or NULLS LAST, which places 
only a null key itself.
--- Comet's native sort places a nested null by the key's null order instead, 
so under ASC NULLS
--- LAST and DESC NULLS FIRST a key whose type can hold one falls back to 
Spark, in a Sort, a TopK
--- or a window order key 
(https://github.com/apache/datafusion-comet/issues/6476). The default
--- null orders, ASC NULLS FIRST and DESC NULLS LAST, put it where Spark does 
and stay native.
---
--- The test harness admits incompatible sort orders by default, so turn that 
off to check the
--- shipped policy.
+-- For nondefault root NULL placement, Comet wraps the key so only root NULLs 
use that placement;
+-- nested NULLs keep Spark's direction-dependent order in Sort, TopK and 
window keys.
 -- Config: spark.comet.expression.SortOrder.allowIncompatible=false

Review Comment:
   After this change `CometSortOrder.getSupportLevel` returns only 
`Unsupported` or `Compatible`. On main the only `Incompatible` result was the 
nested null order case, so I could not find any remaining consumer of 
`spark.comet.expression.SortOrder.allowIncompatible`. If that is right, this 
`Config` line, the same line and its comment in 
`nested_float_order_keys_strict.sql`, and the 
`getExprAllowIncompatConfigKey("SortOrder") -> "false"` settings the PR adds in 
`CometExpressionSuite` and `CometWindowExecSuite` have no effect. The override 
in `CometTestBase` and its comment about mixed zero and negative zero are stale 
for the same reason.



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