generated from amazon-archives/__template_Custom
-
Notifications
You must be signed in to change notification settings - Fork 181
Support nested aggregation when calcite enabled #4979
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
Merged
qianheng-aws
merged 9 commits into
opensearch-project:main
from
LantaoJin:pr/issues/2739_new
Jan 5, 2026
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
e4d086a
refactor: throw exception if pushdown cannot be applied
LantaoJin 8a3ead0
fix tests
LantaoJin 7f98cc9
fix IT
LantaoJin dfee375
Merge remote-tracking branch 'upstream/main' into issues/2739_new
LantaoJin 9fa0f38
Support top/dedup/aggregate by nested sub-fields
LantaoJin 7d05d10
Merge remote-tracking branch 'upstream/main' into issues/2739_new
LantaoJin 95ddffb
fix typo
LantaoJin 085a584
address comments
LantaoJin ed94f0a
minor fixing
LantaoJin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -52,7 +52,6 @@ | |
| import org.apache.calcite.jdbc.CalcitePrepare; | ||
| import org.apache.calcite.jdbc.CalciteSchema; | ||
| import org.apache.calcite.jdbc.Driver; | ||
| import org.apache.calcite.linq4j.function.Function0; | ||
| import org.apache.calcite.plan.Context; | ||
| import org.apache.calcite.plan.Contexts; | ||
| import org.apache.calcite.plan.Convention; | ||
|
|
@@ -175,8 +174,11 @@ public Connection connect( | |
| } | ||
|
|
||
| @Override | ||
| protected Function0<CalcitePrepare> createPrepareFactory() { | ||
| return OpenSearchPrepareImpl::new; | ||
| public CalcitePrepare createPrepare() { | ||
| if (prepareFactory != null) { | ||
| return prepareFactory.get(); | ||
| } | ||
| return new OpenSearchPrepareImpl(); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -298,10 +300,10 @@ public OpenSearchCalcitePreparingStmt( | |
|
|
||
| @Override | ||
| protected PreparedResult implement(RelRoot root) { | ||
| Hook.PLAN_BEFORE_IMPLEMENTATION.run(root); | ||
|
Member
Author
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. This hook was called twice for non-full-scannable plan |
||
| RelDataType resultType = root.rel.getRowType(); | ||
| boolean isDml = root.kind.belongsTo(SqlKind.DML); | ||
| if (root.rel instanceof Scannable scannable) { | ||
| Hook.PLAN_BEFORE_IMPLEMENTATION.run(root); | ||
| RelDataType resultType = root.rel.getRowType(); | ||
| boolean isDml = root.kind.belongsTo(SqlKind.DML); | ||
| final Bindable bindable = dataContext -> scannable.scan(); | ||
|
|
||
| return new PreparedResultImpl( | ||
|
|
||
33 changes: 0 additions & 33 deletions
33
core/src/main/java/org/opensearch/sql/calcite/utils/PPLHintStrategyTable.java
This file was deleted.
Oops, something went wrong.
84 changes: 84 additions & 0 deletions
84
core/src/main/java/org/opensearch/sql/calcite/utils/PPLHintUtils.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.sql.calcite.utils; | ||
|
|
||
| import com.google.common.base.Suppliers; | ||
| import java.util.function.Supplier; | ||
| import lombok.experimental.UtilityClass; | ||
| import org.apache.calcite.rel.core.Aggregate; | ||
| import org.apache.calcite.rel.hint.HintStrategyTable; | ||
| import org.apache.calcite.rel.hint.RelHint; | ||
| import org.apache.calcite.rel.logical.LogicalAggregate; | ||
| import org.apache.calcite.tools.RelBuilder; | ||
|
|
||
| @UtilityClass | ||
| public class PPLHintUtils { | ||
| private static final String HINT_AGG_ARGUMENTS = "AGG_ARGS"; | ||
| private static final String KEY_IGNORE_NULL_BUCKET = "ignoreNullBucket"; | ||
| private static final String KEY_HAS_NESTED_AGG_CALL = "hasNestedAggCall"; | ||
|
|
||
| private static final Supplier<HintStrategyTable> HINT_STRATEGY_TABLE = | ||
| Suppliers.memoize( | ||
| () -> | ||
| HintStrategyTable.builder() | ||
| .hintStrategy( | ||
| HINT_AGG_ARGUMENTS, | ||
| (hint, rel) -> { | ||
| return rel instanceof LogicalAggregate; | ||
| }) | ||
| // add more here | ||
| .build()); | ||
|
|
||
| /** | ||
| * Add hint to aggregate to indicate that the aggregate will ignore null value bucket. Notice, the | ||
| * current peek of relBuilder is expected to be LogicalAggregate. | ||
| */ | ||
| public static void addIgnoreNullBucketHintToAggregate(RelBuilder relBuilder) { | ||
| assert relBuilder.peek() instanceof LogicalAggregate | ||
| : "Hint HINT_AGG_ARGUMENTS can be added to LogicalAggregate only"; | ||
| final RelHint statHint = | ||
| RelHint.builder(HINT_AGG_ARGUMENTS).hintOption(KEY_IGNORE_NULL_BUCKET, "true").build(); | ||
| relBuilder.hints(statHint); | ||
| if (relBuilder.getCluster().getHintStrategies() == HintStrategyTable.EMPTY) { | ||
| relBuilder.getCluster().setHintStrategies(HINT_STRATEGY_TABLE.get()); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Add hint to aggregate to indicate that the aggregate has nested agg call. Notice, the current | ||
| * peek of relBuilder is expected to be LogicalAggregate. | ||
| */ | ||
| public static void addNestedAggCallHintToAggregate(RelBuilder relBuilder) { | ||
| assert relBuilder.peek() instanceof LogicalAggregate | ||
| : "Hint HINT_AGG_ARGUMENTS can be added to LogicalAggregate only"; | ||
| final RelHint statHint = | ||
| RelHint.builder(HINT_AGG_ARGUMENTS).hintOption(KEY_HAS_NESTED_AGG_CALL, "true").build(); | ||
| relBuilder.hints(statHint); | ||
| if (relBuilder.getCluster().getHintStrategies() == HintStrategyTable.EMPTY) { | ||
| relBuilder.getCluster().setHintStrategies(HINT_STRATEGY_TABLE.get()); | ||
| } | ||
| } | ||
|
|
||
| /** Return true if the aggregate will ignore null value bucket. */ | ||
| public static boolean ignoreNullBucket(Aggregate aggregate) { | ||
| return aggregate.getHints().stream() | ||
| .anyMatch( | ||
| hint -> | ||
| hint.hintName.equals(PPLHintUtils.HINT_AGG_ARGUMENTS) | ||
| && hint.kvOptions.getOrDefault(KEY_IGNORE_NULL_BUCKET, "false").equals("true")); | ||
| } | ||
|
|
||
| /** Return true if the aggregate has any nested agg call. */ | ||
| public static boolean hasNestedAggCall(Aggregate aggregate) { | ||
| return aggregate.getHints().stream() | ||
| .anyMatch( | ||
| hint -> | ||
| hint.hintName.equals(PPLHintUtils.HINT_AGG_ARGUMENTS) | ||
| && hint.kvOptions | ||
| .getOrDefault(KEY_HAS_NESTED_AGG_CALL, "false") | ||
| .equals("true")); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.sql.utils; | ||
|
|
||
| import java.util.Iterator; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import javax.annotation.Nullable; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.apache.commons.lang3.tuple.Pair; | ||
| import org.opensearch.sql.data.type.ExprCoreType; | ||
| import org.opensearch.sql.data.type.ExprType; | ||
|
|
||
| public interface Utils { | ||
| static <I> List<Pair<I, Integer>> zipWithIndex(List<I> input) { | ||
| LinkedList<Pair<I, Integer>> result = new LinkedList<>(); | ||
| Iterator<I> iter = input.iterator(); | ||
| int index = 0; | ||
| while (iter.hasNext()) { | ||
| result.add(Pair.of(iter.next(), index++)); | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| /** | ||
| * Resolve the nested path from the field name. | ||
| * | ||
| * @param path the field name | ||
| * @param fieldTypes the field types | ||
| * @return the nested path if exists, otherwise null | ||
| */ | ||
| static @Nullable String resolveNestedPath(String path, Map<String, ExprType> fieldTypes) { | ||
| if (path == null || fieldTypes == null || fieldTypes.isEmpty()) { | ||
| return null; | ||
| } | ||
| boolean found = false; | ||
| String current = path; | ||
| String parent = StringUtils.substringBeforeLast(current, "."); | ||
| while (parent != null && !parent.equals(current)) { | ||
| ExprType pathType = fieldTypes.get(parent); | ||
| // Nested is mapped to ExprCoreType.ARRAY | ||
| if (pathType == ExprCoreType.ARRAY) { | ||
| found = true; | ||
| break; | ||
| } | ||
| current = parent; | ||
| parent = StringUtils.substringBeforeLast(current, "."); | ||
| } | ||
| if (found) { | ||
| return parent; | ||
| } else { | ||
| return null; | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After upgraded to 1.41. this method was not called any more, change it to
createPrepare()