Skip to content

Core: Update Expressions to match Expressions spec - #17343

Open
singhpk234 wants to merge 8 commits into
apache:mainfrom
singhpk234:feature/expression-parser-update
Open

singhpk234 wants to merge 8 commits into
apache:mainfrom
singhpk234:feature/expression-parser-update

Conversation

@singhpk234

@singhpk234 singhpk234 commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Updates ExpressionParser to the JSON serialization in the expressions spec (#16652). This is the Java side of #17138.

Changes

API

  • Adds FunctionReference and UnboundApply for function calls in expressions.
  • Adds Expressions.function(...) and Expressions.apply(...).

Core

  • The writer emits the spec form: left/right/child operands, {"type":"reference","name"|"id"}, and transforms as apply, e.g. bucket(16, id).
  • The reader accepts both the spec form and the deprecated term-based form.
  • Transform calls (identity, year, month, day, hour, bucket, truncate) are read back as UnboundTransform. Other functions stay UnboundApply and cannot be bound yet.
  • Field ID references are resolved against the schema passed to fromJson.
  • Supports typed literals (data-type) and the literals set form.

Compatibility

The writer always emits the new form. Readers from before this change cannot parse it.

@singhpk234 singhpk234 changed the title Core: Update ExpressionParser to match new expressions spec Core: Update ExpressionParser to match new expressions spec Jul 23, 2026
@sfc-gh-prsingh
sfc-gh-prsingh force-pushed the feature/expression-parser-update branch 3 times, most recently from e681062 to 134e03b Compare July 28, 2026 17:54
@github-actions github-actions Bot removed the OPENAPI label Jul 28, 2026
@singhpk234
singhpk234 marked this pull request as ready for review August 7, 2026 22:16

@amogh-jahagirdar amogh-jahagirdar left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @singhpk234, I'm still going through the change in more depth but I think the main question I have is around compatibility in terms of older readers. Currently, the change will serialize in the new spec compliant representation but older readers wouldn't be able to understand it. Do we need to have a separate serialization mode that produces older compatible expressions in the APIs? cc @rdblue @danielcweeks

I know there's also been discussion around loadTableV2 which we'd need for other use cases like V4 etc, so one path is that those APIs are bound to using the newer expression format, and clients would anyways need to handle the new format for those newer APIs etc. But from a core expression library perspective we may need to expose some way to not just always produce the newer expression representation. Use cases that need to produce older-compatible expressions, can use that API, use cases that can produce newer metadata can just do that.

this.gen = gen;
}

/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this needed to be removed?

Comment thread api/src/main/java/org/apache/iceberg/expressions/Expressions.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/FunctionReference.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/FunctionReference.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/FunctionReference.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/FunctionReference.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/FunctionReference.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/UnboundApply.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/UnboundApply.java Outdated
Comment thread api/src/main/java/org/apache/iceberg/expressions/UnboundApply.java Outdated
@singhpk234 singhpk234 added this to the Iceberg 1.13.0 milestone Sep 22, 2026
@danielcweeks
danielcweeks self-requested a review September 28, 2026 15:27
@sfc-gh-prsingh
sfc-gh-prsingh force-pushed the feature/expression-parser-update branch 4 times, most recently from 6f42396 to 6037638 Compare September 29, 2026 05:00
* @param <T> the Java type of this term
* @return an unbound apply expression
*/
public static <T> UnboundApply<T> apply(FunctionReference function, List<Object> arguments) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other methods look good, but I think List<Object> is too broad here. This helper may need to be omitted until we have the type hierarchy built out with a type for ValueExpression + Predicate, which I think is called FUNC_ARG in the spec (maybe FunctionArg here?).

I think @danielcweeks has been working on the hierarchy changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper may need to be omitted until we have the type hierarchy built out with a type for ValueExpression + Predicate, which I think is called FUNC_ARG in the spec (maybe FunctionArg here?).

precisely, hence i couldn't find some thing better than Object, should i make this package private (so its not a public api ? ) and meanwhile when we have the hierarchy changes we could remove this ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe FunctionArg here
Function Arg would be nice abstraction !

will let Dan chime in too, for now for the completeness of impl i just marked them as private, this can come as follow up as well and i am fine to remove this completely as well

Comment thread api/src/main/java/org/apache/iceberg/expressions/UnboundApply.java Outdated
*
* @param <T> the Java type of values produced by this expression
*/
public class UnboundApply<T> implements UnboundTerm<T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this should be a ValueExpression type that it not a Term. Term is used for expressions that return a value based on a reference, but ValueExpression will be more broad. It will include literals (not Term) and these Apply expressions.

Comment thread api/src/main/java/org/apache/iceberg/expressions/UnboundApply.java Outdated
Comment thread core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java Outdated
Comment thread core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java Outdated
Comment thread core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java Outdated
@singhpk234 singhpk234 changed the title Core: Update ExpressionParser to match new expressions spec Core: Update Expressions to match Expressions spec Oct 5, 2026
@sfc-gh-prsingh
sfc-gh-prsingh force-pushed the feature/expression-parser-update branch from 1da0c08 to ef35503 Compare October 6, 2026 20:53
Adds FunctionReference and UnboundApply, and Expressions factory methods
to build function application terms from the expressions spec.
Serializes predicates in the form defined in format/expressions-spec.md,
including apply terms and field-id references, while continuing to accept
the deprecated term-based form.
Keeps the original structure of the unbound predicate writer, stores
apply arguments in an array so the class is Kryo serializable, and splits
the null-catalog function reference check into its own test.

Generated-by: Claude Code
Adds BoundApply so that an UnboundApply with a known result type can be
bound by binding each of its arguments. Bound applies can be written to
JSON and unbound. Applies without a result type, such as those read from
JSON, still cannot be bound.

Generated-by: Claude Code
The expressions spec defines partition transforms as functions in the
iceberg_functions catalog, and a function reference without a catalog
refers to the catalog of the referencing object. Only read applies as
transforms when they use the iceberg_functions catalog, and write
transforms with it.

Generated-by: Claude Code
The expressions spec defines partition transforms as functions in the
iceberg_functions catalog. UnboundTransform and BoundTransform now extend
UnboundApply and BoundApply, so the parser writes them through the same
path as other function applications.

Generated-by: Claude Code
Removes Expressions.apply and makes UnboundApply.arguments package-private
so function arguments typed as Object are not public API until a function
argument type exists. Stores function reference identifiers in an array
for Kryo, and trims redundant comments and code.

Generated-by: Claude Code

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

4 participants