Files
opencloud/services/search/pkg/aggregation/aggregation.go
T
Dominik Schmidt b2d8a13c24 feat(search): add range aggregations
Numeric and date ranges on both engines: bleve folds them from doc values, OpenSearch uses range and date_range aggregations. The proto gains BucketRange and bucketDefinition.ranges, the aggregation package the range parser (bounds are numbers or RFC3339 dates, one kind per aggregation, anything else is rejected), the kind of an option and the validation of ranges against the field type. Every requested range is answered in request order, an empty one with a count of zero, with no space answering too; size does not cut ranges, keyAsNumber sorts them by their lower bound. Range keys read from..to. AGG-04, 05 and 07 to 09 in the parity suite.
2026-10-06 10:50:28 +02:00

64 lines
1.6 KiB
Go

// Package aggregation holds what the engines and the service layer share
// about aggregations: the kind of an option, range bounds and the cross-space
// merge.
package aggregation
import (
"fmt"
"math"
"strconv"
searchsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/search/v0"
)
// Kind is what an aggregation option asks for.
type Kind int
const (
KindTerms Kind = iota
KindRange
)
// KindOf tells the kind from the definitions an option carries.
func KindOf(opt *searchsvc.AggregationOption) Kind {
if len(opt.GetBucketDefinition().GetRanges()) > 0 {
return KindRange
}
return KindTerms
}
// MaxBuckets is how many buckets the aggregations of one request may have in
// one space: the search.max_buckets default of OpenSearch, held on every
// engine.
const MaxBuckets = math.MaxUint16
// ErrTooManyBuckets is what an engine answers beyond MaxBuckets; the service
// layer turns it into a bad request.
var ErrTooManyBuckets = fmt.Errorf("the aggregations have more than %d buckets, narrow the query or the aggregations", MaxBuckets)
// CheckBuckets holds the results of one space to MaxBuckets.
func CheckBuckets(results []*searchsvc.AggregationResult) error {
if countBuckets(results) > MaxBuckets {
return ErrTooManyBuckets
}
return nil
}
func countBuckets(results []*searchsvc.AggregationResult) int {
n := 0
for _, r := range results {
n += len(r.GetBuckets())
}
return n
}
// NumberKey and BoolKey spell the bucket key of a numeric and a bool value,
// the same on every engine.
func NumberKey(v float64) string {
return strconv.FormatFloat(v, 'f', -1, 64)
}
func BoolKey(v bool) string {
return strconv.FormatBool(v)
}