Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

Commit 2e78116

Browse files
authored
Improve (date)_range just like filters (#970)
Don't get dissuaded by the nr of changed lines, there's almost nothing happening here. `(Date)_range` and `filters` are basically the same aggregation. I recently improved `filters` a bit, but didn't do anything to `(date)_range`. This PR makes all those combinators work in the same way, so there are two issues left - #971 (easier) and #944 (a bit harder). Afterwards they will all fully work.
1 parent 8e18e9e commit 2e78116

File tree

4 files changed

+621
-271
lines changed

4 files changed

+621
-271
lines changed

quesma/queryparser/pancake_sql_query_generation_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ func TestPancakeQueryGeneration(t *testing.T) {
5353
if filters(test.TestName) {
5454
t.Skip("Fix filters")
5555
}
56-
if test.TestName == "complex sum_bucket. Reproduce: Visualize -> Vertical Bar: Metrics: Sum Bucket (Bucket: Date Histogram, Metric: Average), Buckets: X-Asis: Histogram(file:opensearch-visualize/pipeline_agg_req,nr:22)" {
57-
t.Skip("error: filter(s)/range/dataRange aggregation must be the last bucket aggregation")
56+
57+
if test.TestName == "Line, Y-axis: Min, Buckets: Date Range, X-Axis: Terms, Split Chart: Date Histogram(file:kibana-visualize/agg_req,nr:9)" {
58+
t.Skip("Date range is broken, fix in progress (PR #971)")
5859
}
5960

6061
if test.TestName == "Terms with order by top metrics(file:kibana-visualize/agg_req,nr:8)" {
@@ -66,10 +67,6 @@ func TestPancakeQueryGeneration(t *testing.T) {
6667
t.Skip("Was skipped before. Wrong key in max_bucket, should be an easy fix")
6768
}
6869

69-
if test.TestName == "complex sum_bucket. Reproduce: Visualize -> Vertical Bar: Metrics: Sum Bucket (Bucket: Date Histogram, Metric: Average), Buckets: X-Asis: Histogram(file:opensearch-visualize/pipeline_agg_req,nr:24)" {
70-
t.Skip("Was skipped before, no expected results")
71-
}
72-
7370
// TODO: add test for filter(s) both at the beginning and end of aggregation tree
7471

7572
fmt.Println("i:", i, "test:", test.TestName)

quesma/queryparser/pancake_transformer.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -408,48 +408,61 @@ func (a *pancakeTransformer) aggregationTreeToPancakes(topLevel pancakeAggregati
408408
// TODO: if both top_hits/top_metrics, and filters, it probably won't work...
409409
// Care: order of these two functions is unfortunately important.
410410
// Should be fixed after this TODO
411-
newFiltersPancakes := a.createFiltersPancakes(&newPancake)
411+
newCombinatorPancakes := a.createCombinatorPancakes(&newPancake)
412412
additionalTopHitPancakes, err := a.createTopHitAndTopMetricsPancakes(&newPancake)
413413
if err != nil {
414414
return nil, err
415415
}
416416

417417
pancakeResults = append(pancakeResults, additionalTopHitPancakes...)
418-
pancakeResults = append(pancakeResults, newFiltersPancakes...)
418+
pancakeResults = append(pancakeResults, newCombinatorPancakes...)
419419
}
420420

421421
return
422422
}
423423

424424
// createFiltersPancakes only does something, if first layer aggregation is Filters.
425425
// It creates new pancakes for each filter in that aggregation, and updates `pancake` to have only first filter.
426-
func (a *pancakeTransformer) createFiltersPancakes(pancake *pancakeModel) (newPancakes []*pancakeModel) {
426+
func (a *pancakeTransformer) createCombinatorPancakes(pancake *pancakeModel) (newPancakes []*pancakeModel) {
427427
if len(pancake.layers) == 0 || pancake.layers[0].nextBucketAggregation == nil {
428428
return
429429
}
430430

431431
firstLayer := pancake.layers[0]
432-
filters, isFilters := firstLayer.nextBucketAggregation.queryType.(bucket_aggregations.Filters)
433-
canSimplyAddFilterToWhereClause := len(firstLayer.currentMetricAggregations) == 0 && len(firstLayer.currentPipelineAggregations) == 0
434-
areNewPancakesReallyNeeded := len(pancake.layers) > 1 // if there is only one layer, it's better to get it done with combinators.
432+
combinator, isCombinator := firstLayer.nextBucketAggregation.queryType.(bucket_aggregations.CombinatorAggregationInterface)
433+
if !isCombinator {
434+
return
435+
}
436+
437+
noMoreBucket := len(pancake.layers) <= 1 || (len(pancake.layers) == 2 && pancake.layers[1].nextBucketAggregation == nil)
438+
noMetricOnFirstLayer := len(firstLayer.currentMetricAggregations) == 0 && len(firstLayer.currentPipelineAggregations) == 0
439+
canSimplyAddCombinatorToWhereClause := noMoreBucket && noMetricOnFirstLayer
440+
if canSimplyAddCombinatorToWhereClause {
441+
return
442+
}
435443

436-
if !isFilters || !canSimplyAddFilterToWhereClause || !areNewPancakesReallyNeeded || len(filters.Filters) == 0 {
444+
areNewPancakesReallyNeeded := len(pancake.layers) > 1 // if there is only one layer above combinator, it easily can be done with 1 pancake, no need for more
445+
groups := combinator.CombinatorGroups()
446+
if !areNewPancakesReallyNeeded || len(groups) == 0 {
437447
return
438448
}
439449

440-
// First create N-1 new pancakes, each with different filter
441-
for i := 1; i < len(filters.Filters); i++ {
450+
combinatorSplit := combinator.CombinatorSplit()
451+
combinatorGroups := combinator.CombinatorGroups()
452+
// First create N-1 new pancakes [1...N), each with different filter
453+
// (important to update the first (0th) pancake at the end)
454+
for i := 1; i < len(groups); i++ {
442455
newPancake := pancake.Clone()
443456
bucketAggr := newPancake.layers[0].nextBucketAggregation.ShallowClone()
444-
bucketAggr.queryType = filters.NewFiltersSingleFilter(i)
457+
bucketAggr.queryType = combinatorSplit[i]
445458
newPancake.layers[0] = newPancakeModelLayer(&bucketAggr)
446-
newPancake.whereClause = model.And([]model.Expr{newPancake.whereClause, filters.Filters[i].Sql.WhereClause})
459+
newPancake.whereClause = model.And([]model.Expr{newPancake.whereClause, combinatorGroups[i].WhereClause})
447460
newPancakes = append(newPancakes, newPancake)
448461
}
449462

450-
// Then update original to have 1 filter as well
451-
pancake.layers[0].nextBucketAggregation.queryType = filters.NewFiltersSingleFilter(0)
452-
pancake.whereClause = model.And([]model.Expr{pancake.whereClause, filters.Filters[0].Sql.WhereClause})
463+
// Update original
464+
pancake.layers[0].nextBucketAggregation.queryType = combinatorSplit[0]
465+
pancake.whereClause = model.And([]model.Expr{pancake.whereClause, combinatorGroups[0].WhereClause})
453466

454467
return
455468
}

0 commit comments

Comments
 (0)