|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: Apache DataFusion Comet 0.17.0 Release |
| 4 | +date: 2026-06-20 |
| 5 | +author: pmc |
| 6 | +categories: [subprojects] |
| 7 | +--- |
| 8 | + |
| 9 | +<!-- |
| 10 | +{% comment %} |
| 11 | +Licensed to the Apache Software Foundation (ASF) under one or more |
| 12 | +contributor license agreements. See the NOTICE file distributed with |
| 13 | +this work for additional information regarding copyright ownership. |
| 14 | +The ASF licenses this file to you under the Apache License, Version 2.0 |
| 15 | +(the "License"); you may not use this file except in compliance with |
| 16 | +the License. You may obtain a copy of the License at |
| 17 | +
|
| 18 | +http://www.apache.org/licenses/LICENSE-2.0 |
| 19 | +
|
| 20 | +Unless required by applicable law or agreed to in writing, software |
| 21 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 22 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 23 | +See the License for the specific language governing permissions and |
| 24 | +limitations under the License. |
| 25 | +{% endcomment %} |
| 26 | +--> |
| 27 | + |
| 28 | +[TOC] |
| 29 | + |
| 30 | +The Apache DataFusion PMC is pleased to announce version 0.17.0 of the [Comet](https://datafusion.apache.org/comet/) subproject. |
| 31 | + |
| 32 | +This release covers approximately five weeks of development work and is the result of merging 192 PRs from 19 |
| 33 | +contributors. See the [change log] for more information. |
| 34 | + |
| 35 | +[change log]: https://github.com/apache/datafusion-comet/blob/main/dev/changelog/0.17.0.md |
| 36 | + |
| 37 | +## Fewer Fallbacks to Spark |
| 38 | + |
| 39 | +The headline feature of 0.17.0 is a new mechanism that keeps more of your query running inside Comet instead |
| 40 | +of falling back to Spark: the **JVM codegen dispatcher**. |
| 41 | + |
| 42 | +Comet has always fallen back to Spark row-based execution whenever an expression had no native Rust implementation, or where the |
| 43 | +Rust implementation could diverge from Spark on edge cases. A fallback is correct, but a columnar-to-row |
| 44 | +conversion is needed to feed the data into Spark's row-based operators, which adds overhead when processing billions of rows of data. |
| 45 | + |
| 46 | +The codegen dispatcher avoids the fallback to row-based processing by running Spark's own |
| 47 | +generated code (`doGenCode`) inside the Comet pipeline, operating directly on Arrow batches. The result is a |
| 48 | +JVM-implemented Arrow-native expression: the data stays in Arrow format, and because the expression is |
| 49 | +evaluated by Spark's own code, the result is guaranteed to match Spark exactly across every supported Spark |
| 50 | +version. When the dispatcher is disabled, Comet falls back as before. |
| 51 | + |
| 52 | +A dispatched expression is no faster than it would be in Spark, since it runs the same generated code. The |
| 53 | +benefit is that a single unsupported expression no longer forces an entire |
| 54 | +query stage back to row-based execution. The surrounding operators stay Arrow-native, and the |
| 55 | +stage avoids the columnar-to-row conversion and row-based Spark execution that a fallback would otherwise |
| 56 | +impose. |
| 57 | + |
| 58 | +This release puts the dispatcher to work across a wide surface: |
| 59 | + |
| 60 | +- **100% Spark-compatible regular expressions.** Regex expressions now dispatch to Spark's own |
| 61 | + implementation, eliminating the long-standing compatibility gaps of a separate native regex engine. |
| 62 | +- **100% Spark-compatible JSON functions.** JSON expression handling follows the same approach, matching |
| 63 | + Spark's behavior precisely. |
| 64 | +- **More scalar and structured-text functions**, including a batch of math and string functions, AES |
| 65 | + encryption and decryption (`aes_encrypt` / `aes_decrypt` / `try_aes_decrypt`), `Upper` / `Lower` / |
| 66 | + `InitCap`, `GetTimestamp`, `mask`, `try_to_number`, and an expanded set of date, time, and |
| 67 | + timezone expressions. |
| 68 | +- **Collection and higher-order expressions**, including `array_intersect`, `array_except`, `array_join`, |
| 69 | + `create_map`, and lambda-based higher-order functions such as `filter`. |
| 70 | + |
| 71 | + 0.17.0 also changes how Comet treats expressions whose native Rust path is known to diverge |
| 72 | + from Spark (marked `Incompatible`). Previously such an expression forced the entire projection back to Spark |
| 73 | + unless the user opted into the divergent native behavior with the per-expression |
| 74 | + `spark.comet.expression.<name>.allowIncompatible` flag. By default, that flag is unset, and the expression is |
| 75 | + now routed through the codegen dispatcher and evaluated correctly inside Comet rather than triggering a |
| 76 | + fallback. Setting it to `true` becomes a performance knob for users who accept the faster native path's |
| 77 | + divergence. Expressions such as `from_unixtime`, and the `TimestampNTZ` branches of `hour`, `minute`, and |
| 78 | + `second`, now stay in the pipeline by default. |
| 79 | + |
| 80 | +## User-Defined Functions in Java and Scala |
| 81 | + |
| 82 | +Building on the codegen dispatcher, 0.17.0 adds support for arbitrary user-defined functions written in Java |
| 83 | +and Scala, enabled by default. Eligible Spark `ScalaUDF` expressions are routed through the dispatcher and |
| 84 | +executed inside the Comet pipeline, so a project around a UDF no longer forces a fallback and a |
| 85 | +columnar-to-row conversion. |
| 86 | + |
| 87 | +The path has broad type coverage — scalars, arbitrarily nested complex types, and higher-order functions — and |
| 88 | +is backed by end-to-end, fuzz, and Iceberg test coverage. It can be disabled with |
| 89 | +`spark.comet.exec.scalaUDF.codegen.enabled=false`. |
| 90 | + |
| 91 | +## Arrow-Native, End to End |
| 92 | + |
| 93 | +The codegen dispatcher works because of a property that runs through all of Comet: queries stay **Arrow-native |
| 94 | +end to end**. Operators, expressions, shuffle, and broadcast all remain in Apache Arrow columnar format, |
| 95 | +avoiding the per-row overhead that Spark's row-based engine incurs from materializing and transitioning data |
| 96 | +one row at a time. |
| 97 | + |
| 98 | +Within that Arrow-native pipeline, the work of an operator or expression runs in one of two ways: |
| 99 | + |
| 100 | +- **Rust-implemented**: native Rust code, executed through Apache DataFusion. This is what most people picture |
| 101 | + when they think of Comet. |
| 102 | +- **JVM-implemented**: Scala or Java code that operates directly on Arrow batches, including the |
| 103 | + codegen-dispatched expressions and UDFs described above. |
| 104 | + |
| 105 | +Because the data never leaves Arrow columnar format, there is no per-row materialization cost at the boundary |
| 106 | +between a Rust-implemented and a JVM-implemented step. A dispatched expression sits in the pipeline alongside |
| 107 | +Rust-implemented operators with no columnar-to-row transition between them. Expanding the JVM-implemented path |
| 108 | +in 0.17.0 lets Comet keep more work Arrow-native instead of handing it back to Spark. |
| 109 | + |
| 110 | +## Expanded Expression Coverage |
| 111 | + |
| 112 | +Partly through the codegen dispatcher and partly through new Rust implementations, Comet's expression coverage |
| 113 | +grew substantially in this release. More than 120 Spark expressions have gained support since 0.16.0, across |
| 114 | +most function families: |
| 115 | + |
| 116 | +- **Date and time** (~25): `convert_timezone`, `make_date`, `months_between`, `next_day`, |
| 117 | + `from_utc_timestamp` / `to_utc_timestamp`, `date_from_unix_date`, the `timestamp_*` and `unix_*` second / |
| 118 | + milli / micro conversions, and the current date/time/timezone functions. |
| 119 | +- **Math** (~24): `acosh`, `asinh`, `atanh`, `cbrt`, `csc`, `sec`, `hypot`, `log1p`, `bin`, `conv`, |
| 120 | + `factorial`, `pmod`, `width_bucket`, `rint`, and more. |
| 121 | +- **String** (~16): `elt`, `find_in_set`, `format_number`, `format_string`, `levenshtein`, `locate`, |
| 122 | + `overlay`, `soundex`, `split`, `substring_index`, `unbase64`, `to_char`, and `to_number`. |
| 123 | +- **XPath** (9): the full `xpath`, `xpath_boolean`, `xpath_double`, `xpath_int`, `xpath_long`, `xpath_string` |
| 124 | + family. |
| 125 | +- **JSON, CSV, and XML** (9): `from_csv`, `to_csv`, `schema_of_csv`, `schema_of_json`, `json_object_keys`, |
| 126 | + `json_array_length`, `from_xml`, `to_xml`, and `schema_of_xml`. |
| 127 | +- **Array and map** (11): `array_position`, `array_size`, `arrays_zip`, `slice`, `sort_array`, `sequence`, |
| 128 | + `map_concat`, `map_contains_key`, and `map_from_entries`. |
| 129 | +- **Aggregate and window** (7): `any_value`, `count_if`, the `regr_*` regression aggregates, plus `lag` and |
| 130 | + `lead`. |
| 131 | +- **Conditional and null handling** (7): `greatest`, `least`, `nullif`, `ifnull` / `nvl`, `nvl2`, and |
| 132 | + `equal_null`. |
| 133 | + |
| 134 | +For the full list of supported expressions in this release, see the |
| 135 | +[Spark Expression Support](https://datafusion.apache.org/comet/user-guide/0.17/expressions.html) reference. |
| 136 | + |
| 137 | +Operator coverage grew too: 0.17.0 adds a native **broadcast nested loop join**, so queries with non-equi or |
| 138 | +cross join conditions can now stay in the Comet pipeline rather than falling back to Spark. |
| 139 | + |
| 140 | +## Performance |
| 141 | + |
| 142 | +### Removing an FFI Round Trip from Native Shuffle |
| 143 | + |
| 144 | +The most significant performance change in 0.17.0 targets the shuffle write path. When a native subtree feeds |
| 145 | +a Comet shuffle, Comet previously ran two separate native iterators per partition: one for the upstream |
| 146 | +subtree, and a second rooted at a synthetic `Scan("ShuffleWriterInput") -> ShuffleWriter` that consumed the |
| 147 | +batches back. The JVM never actually read this data, so the native-to-JVM-and-back hop was pure overhead. |
| 148 | + |
| 149 | +Although the Arrow C Data Interface is zero-copy, this particular round trip was not. The synthetic scan left |
| 150 | +its batches marked as not FFI-safe, so on import every batch was deep-copied into freshly allocated buffers. |
| 151 | +0.17.0 collapses the two iterators into a single native plan rooted at the shuffle writer, with the upstream |
| 152 | +subtree as a direct child. That removes the Arrow FFI export and import, the per-batch deep copy, and one |
| 153 | +`createPlan` / `releasePlan` pair per partition, while preserving all of the existing per-partition setup |
| 154 | +(broadcast alignment, subqueries, encryption) and input metrics reporting. The gain comes from removing the |
| 155 | +round trip, not from copying its data more efficiently. |
| 156 | + |
| 157 | +### A Single Arrow Stream on the Input Path |
| 158 | + |
| 159 | +0.17.0 also reworks the other side of the JVM/native boundary — the path that feeds JVM-sourced data _into_ |
| 160 | +native execution. Previously each batch crossed via a bespoke `CometBatchIterator`, with a `hasNext` / `next` |
| 161 | +JNI pair per batch and every column imported through its own Arrow FFI array and schema. This release replaces |
| 162 | +that path with the **Arrow C Stream Interface**: the JVM exports each per-partition iterator once, and native |
| 163 | +imports the schema once and pulls each batch through a single C callback, taking ownership by reference count. |
| 164 | +This removes the per-batch, per-column FFI export and JNI round trips for all JVM-sourced inputs, lets the |
| 165 | +old `CometBatchIterator` and a now-unnecessary deep copy be deleted, and is the input-side counterpart to the |
| 166 | +shuffle-write change above. TPC-DS at 1TB is about 9% faster in 0.17.0 than in 0.16.0, and these two FFI |
| 167 | +changes are the largest contributor to that gain. |
| 168 | + |
| 169 | +### Lower Per-Batch Overhead in Arrow Vectors |
| 170 | + |
| 171 | +Two changes reduce repeated work when reading Arrow columns across the JNI boundary. Comet now caches the |
| 172 | +validity buffer address on `CometDecodedVector` and the offset buffer address for variable-width vectors on |
| 173 | +`CometPlainVector`, so these addresses are resolved once per vector rather than on every access. |
| 174 | + |
| 175 | +### Faster Statistical Aggregates |
| 176 | + |
| 177 | +The variance, standard deviation, covariance, and correlation aggregates now use DataFusion's |
| 178 | +`GroupsAccumulator` interface, which is substantially more efficient for grouped aggregation than the |
| 179 | +row-accumulator path they used previously. |
| 180 | + |
| 181 | +Additional smaller improvements include bulk-NULL handling in `split` and `substring` (skipping a per-row |
| 182 | +allocation), and a new `interleave_time` shuffle metric with tuned output buffer sizing to make shuffle cost |
| 183 | +easier to attribute. |
| 184 | + |
| 185 | +## Preparing for the 1.0.0 Release |
| 186 | + |
| 187 | +Much of the correctness work in this release is part of an ongoing push toward a **1.0.0 release**. |
| 188 | +Planning for 1.0.0 is being tracked in [issue #4082], where the community is discussing what the milestone |
| 189 | +should mean. The criteria under consideration go well beyond correctness and include: |
| 190 | + |
| 191 | +- Demonstrated cost savings for TPC-H and TPC-DS at SF1000 (1TB) |
| 192 | +- Thorough documentation of compatibility status |
| 193 | +- A review of all configuration options, renaming some for consistency |
| 194 | +- Consistent logging |
| 195 | +- A documented policy for how long each Spark version will be supported |
| 196 | +- A documented process for preventing major performance regressions |
| 197 | +- A documented semantic-versioning policy and what it means for Comet going forward |
| 198 | + |
| 199 | +[issue #4082]: https://github.com/apache/datafusion-comet/issues/4082 |
| 200 | + |
| 201 | +Correctness is central to that list: reaching 1.0.0 means being able to state precisely which Spark |
| 202 | +expressions Comet accelerates, and how faithfully it matches Spark on each one. Two efforts in 0.17.0 move |
| 203 | +toward that goal. |
| 204 | + |
| 205 | +First, the codegen dispatcher guarantees an exact match for every dispatched expression, since Spark's own |
| 206 | +generated code does the evaluation. That raises our confidence that Comet matches Spark across the supported |
| 207 | +versions, and it makes the Spark Expression Support reference something the project can stand behind as it |
| 208 | +approaches 1.0.0. |
| 209 | + |
| 210 | +Second, this release included a systematic audit of Comet's existing expression implementations against Spark, |
| 211 | +detailed below. |
| 212 | + |
| 213 | +### Expression Audit |
| 214 | + |
| 215 | +The audit compared Comet's expression implementations against Apache Spark 3.4.3, 3.5.8, 4.0.1, and 4.1.1, |
| 216 | +covering the hash, JSON, collection, map, predicate, bitwise, conditional, array, struct, math, and cast |
| 217 | +expression families, along with cast behavior. Each audit compared Comet's behavior to Spark across all four |
| 218 | +versions and expanded test coverage where gaps were found. |
| 219 | + |
| 220 | +This edge-case-by-edge-case comparison surfaced most of the behavior differences fixed in this |
| 221 | +release. By working through each expression's corner cases and writing targeted Comet SQL tests for them, the |
| 222 | +audit caught divergences that broader testing does not reliably exercise. Comet also runs the full Apache |
| 223 | +Spark SQL test suite against each supported Spark version as part of CI, which continues to catch some |
| 224 | +cross-version differences, but the audit's focused approach found considerably more. |
| 225 | + |
| 226 | +## Compatibility |
| 227 | + |
| 228 | +Supported platforms include: |
| 229 | + |
| 230 | +- **Spark 3.4.3** with Java 11/17 and Scala 2.12/2.13 |
| 231 | +- **Spark 3.5.8** with Java 11/17 and Scala 2.12/2.13 |
| 232 | +- **Spark 4.0.2** with Java 17 and Scala 2.13 |
| 233 | +- **Spark 4.1.2** with Java 17 and Scala 2.13 |
| 234 | + |
| 235 | +See the [Spark Version Compatibility] page for known limitations specific to each version. |
| 236 | + |
| 237 | +[Spark Version Compatibility]: https://datafusion.apache.org/comet/user-guide/latest/compatibility/spark-versions.html |
| 238 | + |
| 239 | +This release builds on **DataFusion 53.1** and **Arrow 58.3**. |
| 240 | + |
| 241 | +## Get Started with Comet 0.17.0 |
| 242 | + |
| 243 | +Ready to try it out? Follow the [Comet 0.17.0 Installation Guide](https://datafusion.apache.org/comet/user-guide/0.17/installation.html) |
| 244 | +to get up and running, then point Comet at your existing Spark workloads, including Scala and Java UDFs and |
| 245 | +Spark 4 with ANSI mode enabled, and see the speedup for yourself. |
0 commit comments