Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 2.3k
Improve documentation for ScalarUDFImpl::preimage#20008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
a788644c6f175f82ab8639e63a96a417118d5b4f4358fa8f23f8a5815bc6801cdd49f0550fe419e2fff4File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -709,22 +709,101 @@ pub trait ScalarUDFImpl: Debug + DynEq + DynHash + Send + Sync { | ||
| Ok(ExprSimplifyResult::Original(args)) | ||
| } | ||
| /// Returns the [preimage] for this function and the specified scalar value, if any. | ||
| /// Returns a single contiguous preimage for this function and the specified | ||
| /// scalar expression, if any. | ||
| /// | ||
| /// Currently only applies to `=, !=, >, >=, <, <=, is distinct from, is not distinct from` predicates | ||
| /// # Return Value | ||
ContributorAuthor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved discussion of return value to its own section and clearly separated the background from the API details | ||
| /// | ||
| /// Implementations should return a half-open interval: inclusive lower | ||
| /// bound and exclusive upper bound. This is slightly different from normal | ||
| /// [`Interval`] semantics where the upper bound is closed (inclusive). | ||
| /// Typically this means the upper endpoint must be adjusted to the next | ||
| /// value not included in the preimage. See the Half-Open Intervals section | ||
| /// below for more details. | ||
| /// | ||
| /// # Background | ||
| /// | ||
| /// Inspired by the [ClickHouse Paper], a "preimage rewrite" transforms a | ||
| /// predicate containing a function call into a predicate containing an | ||
| /// equivalent set of input literal (constant) values. The resulting | ||
| /// predicate can often be further optimized by other rewrites (see | ||
| /// Examples). | ||
| /// | ||
| /// From the paper: | ||
| /// | ||
| /// > some functions can compute the preimage of a given function result. | ||
| /// > This is used to replace comparisons of constants with function calls | ||
| /// > on the key columns by comparing the key column value with the preimage. | ||
| /// > For example, `toYear(k) = 2024` can be replaced by | ||
| /// > `k >= 2024-01-01 && k < 2025-01-01` | ||
| /// | ||
| /// For example, given an expression like | ||
| /// ```sql | ||
| /// date_part('YEAR', k) = 2024 | ||
| /// ``` | ||
| /// | ||
| /// The interval `[2024-01-01, 2025-12-31`]` contains all possible input | ||
| /// values (preimage values) for which the function `date_part(YEAR, k)` | ||
| /// produces the output value `2024` (image value). Returning the interval | ||
| /// (note upper bound adjusted up) `[2024-01-01, 2025-01-01]` the expression | ||
| /// can be rewritten to | ||
| /// | ||
| /// ```sql | ||
| /// k >= '2024-01-01' AND k < '2025-01-01' | ||
| /// ``` | ||
| /// | ||
| /// which is a simpler and a more canonical form, making it easier for other | ||
| /// optimizer passes to recognize and apply further transformations. | ||
| /// | ||
| /// # Examples | ||
| /// | ||
| /// A preimage is a single contiguous [`Interval`] of values where the function | ||
| /// will always return `lit_value` | ||
| /// Case 1: | ||
| /// | ||
| /// Implementations should return intervals with an inclusive lower bound and | ||
| /// exclusive upper bound. | ||
| /// Original: | ||
| /// ```sql | ||
| /// date_part('YEAR', k) = 2024 AND k >= '2024-06-01' | ||
| /// ``` | ||
| /// | ||
| /// After preimage rewrite: | ||
| /// ```sql | ||
| /// k >= '2024-01-01' AND k < '2025-01-01' AND k >= '2024-06-01' | ||
| /// ``` | ||
| /// | ||
| /// This rewrite is described in the [ClickHouse Paper] and is particularly | ||
| /// useful for simplifying expressions `date_part` or equivalent functions. The | ||
| /// idea is that if you have an expression like `date_part(YEAR, k) = 2024` and you | ||
| /// can find a [preimage] for `date_part(YEAR, k)`, which is the range of dates | ||
| /// covering the entire year of 2024. Thus, you can rewrite the expression to `k | ||
| /// >= '2024-01-01' AND k < '2025-01-01' which is often more optimizable. | ||
| /// Since this form is much simpler, the optimizer can combine and simplify | ||
| /// sub-expressions further into: | ||
| /// ```sql | ||
| /// k >= '2024-06-01' AND k < '2025-01-01' | ||
| /// ``` | ||
| /// | ||
| /// Case 2: | ||
| /// | ||
| /// For min/max pruning, simpler predicates such as: | ||
| /// ```sql | ||
| /// k >= '2024-01-01' AND k < '2025-01-01' | ||
| /// ``` | ||
| /// are much easier for the pruner to reason about. See [PruningPredicate] | ||
| /// for the backgrounds of predicate pruning. | ||
| /// | ||
| /// The trade-off with the preimage rewrite is that evaluating the rewritten | ||
| /// form might be slightly more expensive than evaluating the original | ||
| /// expression. In practice, this cost is usually outweighed by the more | ||
| /// aggressive optimization opportunities it enables. | ||
| /// | ||
| /// # Half-Open Intervals | ||
| /// | ||
| /// The preimage API uses half-open intervals, which makes the rewrite | ||
| /// easier to implement by avoiding calculations to adjust the upper bound. | ||
| /// For example, if a function returns its input unchanged and the desired | ||
| /// output is the single value `5`, a closed interval could be represented | ||
| /// as `[5, 5]`, but then the rewrite would require adjusting the upper | ||
| /// bound to `6` to create a proper range predicate. With a half-open | ||
| /// interval, the same range is represented as `[5, 6)`, which already | ||
| /// forms a valid predicate. | ||
| /// | ||
| /// [PruningPredicate]: https://docs.rs/datafusion/latest/datafusion/physical_optimizer/pruning/struct.PruningPredicate.html | ||
| /// [ClickHouse Paper]: https://www.vldb.org/pvldb/vol17/p3731-schulze.pdf | ||
| /// [image]: https://en.wikipedia.org/wiki/Image_(mathematics)#Image_of_an_element | ||
| /// [preimage]: https://en.wikipedia.org/wiki/Image_(mathematics)#Inverse_image | ||
alamb marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| fn preimage( | ||
| &self, | ||
Uh oh!
There was an error while loading. Please reload this page.