Skip to content

Fix post-aggregator computation when used with subtotals#10653

Merged
jon-wei merged 4 commits intoapache:masterfrom
abhishekagarwal87:post_aggregator
Dec 18, 2020
Merged

Fix post-aggregator computation when used with subtotals#10653
jon-wei merged 4 commits intoapache:masterfrom
abhishekagarwal87:post_aggregator

Conversation

@abhishekagarwal87
Copy link
Copy Markdown
Contributor

Description

Post-aggregators, when used with subtotals, errors if the post-aggregator depends on a dimension that is absent in one of the subtotal. An example query is as follows

SELECT dim2, SUM(cnt), GROUPING(dim2), 
CASE WHEN GROUPING(dim2) = 1 THEN 'ALL' ELSE dim2 END
FROM druid.foo
GROUP BY GROUPING SETS ( (dim2), () )

The exception is

java.lang.IllegalArgumentException: Missing fields [[d0]] for postAggregator [p0]

	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:148)
	at org.apache.druid.query.Queries.prepareAggregations(Queries.java:118)
	at org.apache.druid.query.groupby.GroupByQuery.<init>(GroupByQuery.java:210)
	at org.apache.druid.query.groupby.GroupByQuery.<init>(GroupByQuery.java:88)
	at org.apache.druid.query.groupby.GroupByQuery$Builder.build(GroupByQuery.java:1175)
	at org.apache.druid.query.groupby.GroupByQuery.withDimensionSpecs(GroupByQuery.java:804)
	at org.apache.druid.query.groupby.strategy.GroupByStrategyV2.processSubtotalsSpec(GroupByStrategyV2.java:446)
	at org.apache.druid.query.groupby.GroupByQueryQueryToolChest.mergeGroupByResultsWithoutPushDown(GroupByQueryQueryToolChest.java:250)
	at org.apache.druid.query.groupby.GroupByQueryQueryToolChest.mergeGroupByResults(GroupByQueryQueryToolChest.java:177)
	at org.apache.druid.query.groupby.GroupByQueryQueryToolChest.initAndMergeGroupByResults(GroupByQueryQueryToolChest.java:149)
	at org.apache.druid.query.groupby.GroupByQueryQueryToolChest.lambda$mergeResults$0(GroupByQueryQueryToolChest.java:122)
	at org.apache.druid.query.FinalizeResultsQueryRunner.run(FinalizeResultsQueryRunner.java:110)

I have removed the dimension renaming. We only carry over the dimensions included in the subtotal spec while generating results for any subtotal.


This PR has:

  • been self-reviewed.
  • added unit tests or modified existing tests to cover new code paths, ensuring the threshold for code coverage is met.
  • been tested in a test Druid cluster.

Key changed/added classes in this PR
  • GroupyByStrategyV2

testQuery(
"SELECT dim2, SUM(cnt), GROUPING(dim2), \n"
+ "CASE WHEN GROUPING(dim2) = 1 THEN 'ALL' ELSE 'INDIVIDUAL' END\n"
+ "CASE WHEN GROUPING(dim2) = 1 THEN 'ALL' ELSE dim2 END\n"
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.

Why did you change this test case? (As opposed to introducing a new test case.)

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.

I wrote this test when I submitted the patch for the grouping function. I had wanted to write it this way (as is in PR) but couldn't because of the post-aggregation bug. Now changing it as I am fixing the bug. BTW There are two more tests for the grouping function.

.withLimitSpec(subtotalQueryLimitSpec)
.withDimensionSpecs(newDimensions);
.withLimitSpec(subtotalQueryLimitSpec);
//.withDimensionSpecs(newDimensions);
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.

Please don't include commented-out code.

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.

Yup. I had removed it on my local but forgot to push.

);
subTotalDimensionSpec.add(dimensionSpec);
} else {
// Insert dummy dimension so all subtotals queries have ResultRows with the same shape.
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.

Is this concern no longer valid?

IIRC, it was necessary because otherwise the ResultRows would be different lengths and so the final results wouldn't be correct.

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.

https://github.com/apache/druid/blob/master/processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/RowBasedGrouperHelper.java#L581

We are still keeping all the original dimensions in the query. So result row size should be the same. I think you were concerned that the result should be null for dimensions not part of the subtotal. We are not carrying over the result for those dimensions so it should work out.
https://github.com/apache/druid/blob/master/processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/RowBasedGrouperHelper.java#L593

@gianm
Copy link
Copy Markdown
Contributor

gianm commented Dec 11, 2020

@abhishekagarwal87 Could you check the errors in https://travis-ci.com/github/apache/druid/jobs/456420636, including the one in GroupByQueryRunnerTest.testGroupByWithSubtotalsSpecWithLongDimensionColumn?

@abhishekagarwal87
Copy link
Copy Markdown
Contributor Author

@abhishekagarwal87 Could you check the errors in https://travis-ci.com/github/apache/druid/jobs/456420636, including the one in GroupByQueryRunnerTest.testGroupByWithSubtotalsSpecWithLongDimensionColumn?

It seems to be an existing bug. It can be reproduced in master by writing a subquery that generates null values for numeric dimensions. RowBasedGrouperHelper#getValueSuppliersForDimensions should handle the scenario when input can be a numeric null.

The bug occurs only when there is a subtotal or subquery used. It was caught here as when I removed the renaming of dimensions, I also removed the type change that was happening earlier (the dummy dimensions were string).

@abhishekagarwal87
Copy link
Copy Markdown
Contributor Author

Added the test for a nested groupBy query which fails in the current master.

case LONG:
return (InputRawSupplierColumnSelectorStrategy<BaseLongColumnValueSelector>)
columnSelector -> columnSelector::getLong;
columnSelector -> () -> columnSelector.isNull() ? null : columnSelector.getLong();
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.

FYI, this change could cause a dip in performance when columns are actually strings and being read as a number. Since the parsing first happens in isNull function and then again in getLong

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.

IMO, the selectors themselves should ideally cache this computation, similar to the changes being made in #10614. Therefore, I think this change is OK, and if there are any issues it should be fixed at the selector level.

@jon-wei jon-wei merged commit 796c255 into apache:master Dec 18, 2020
@jihoonson jihoonson added this to the 0.21.0 milestone Jan 4, 2021
JulianJaffePinterest pushed a commit to JulianJaffePinterest/druid that referenced this pull request Jan 22, 2021
* Fix post-aggregator computation

* remove commented code

* Fix numeric null handling

* Add test when subquery returns null long
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants