Add group() aggregator (#7480)

* Add group() aggregator

Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
This commit is contained in:
Julien Pivotto 2020-06-30 16:51:18 +02:00 committed by GitHub
parent 27b1009acd
commit 72425d4e3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 454 additions and 411 deletions

View file

@ -187,6 +187,7 @@ vector of fewer elements with aggregated values:
* `min` (select minimum over dimensions) * `min` (select minimum over dimensions)
* `max` (select maximum over dimensions) * `max` (select maximum over dimensions)
* `avg` (calculate the average over dimensions) * `avg` (calculate the average over dimensions)
* `group` (all values in the resulting vector are 1)
* `stddev` (calculate population standard deviation over dimensions) * `stddev` (calculate population standard deviation over dimensions)
* `stdvar` (calculate population standard variance over dimensions) * `stdvar` (calculate population standard variance over dimensions)
* `count` (count number of elements in the vector) * `count` (count number of elements in the vector)

View file

@ -1978,20 +1978,23 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
if k > inputVecLen { if k > inputVecLen {
resultSize = inputVecLen resultSize = inputVecLen
} }
if op == parser.STDVAR || op == parser.STDDEV { switch op {
result[groupingKey].value = 0.0 case parser.STDVAR, parser.STDDEV:
} else if op == parser.TOPK || op == parser.QUANTILE { result[groupingKey].value = 0
case parser.TOPK, parser.QUANTILE:
result[groupingKey].heap = make(vectorByValueHeap, 0, resultSize) result[groupingKey].heap = make(vectorByValueHeap, 0, resultSize)
heap.Push(&result[groupingKey].heap, &Sample{ heap.Push(&result[groupingKey].heap, &Sample{
Point: Point{V: s.V}, Point: Point{V: s.V},
Metric: s.Metric, Metric: s.Metric,
}) })
} else if op == parser.BOTTOMK { case parser.BOTTOMK:
result[groupingKey].reverseHeap = make(vectorByReverseValueHeap, 0, resultSize) result[groupingKey].reverseHeap = make(vectorByReverseValueHeap, 0, resultSize)
heap.Push(&result[groupingKey].reverseHeap, &Sample{ heap.Push(&result[groupingKey].reverseHeap, &Sample{
Point: Point{V: s.V}, Point: Point{V: s.V},
Metric: s.Metric, Metric: s.Metric,
}) })
case parser.GROUP:
result[groupingKey].value = 1
} }
continue continue
} }
@ -2004,6 +2007,9 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
group.groupCount++ group.groupCount++
group.mean += (s.V - group.mean) / float64(group.groupCount) group.mean += (s.V - group.mean) / float64(group.groupCount)
case parser.GROUP:
// Do nothing. Required to avoid the panic in `default:` below.
case parser.MAX: case parser.MAX:
if group.value < s.V || math.IsNaN(group.value) { if group.value < s.V || math.IsNaN(group.value) {
group.value = s.V group.value = s.V

View file

@ -92,6 +92,7 @@ AVG
BOTTOMK BOTTOMK
COUNT COUNT
COUNT_VALUES COUNT_VALUES
GROUP
MAX MAX
MIN MIN
QUANTILE QUANTILE
@ -535,7 +536,7 @@ metric : metric_identifier label_set
; ;
metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK; metric_identifier: AVG | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | IDENTIFIER | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | QUANTILE | STDDEV | STDVAR | SUM | TOPK;
label_set : LEFT_BRACE label_set_list RIGHT_BRACE label_set : LEFT_BRACE label_set_list RIGHT_BRACE
{ $$ = labels.New($2...) } { $$ = labels.New($2...) }
@ -635,10 +636,10 @@ series_value : IDENTIFIER
* Keyword lists. * Keyword lists.
*/ */
aggregate_op : AVG | BOTTOMK | COUNT | COUNT_VALUES | MAX | MIN | QUANTILE | STDDEV | STDVAR | SUM | TOPK ; aggregate_op : AVG | BOTTOMK | COUNT | COUNT_VALUES | GROUP | MAX | MIN | QUANTILE | STDDEV | STDVAR | SUM | TOPK ;
// inside of grouping options label names can be recognized as keywords by the lexer. This is a list of keywords that could also be a label name. // inside of grouping options label names can be recognized as keywords by the lexer. This is a list of keywords that could also be a label name.
maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP_LEFT | GROUP_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK; maybe_label : AVG | BOOL | BOTTOMK | BY | COUNT | COUNT_VALUES | GROUP | GROUP_LEFT | GROUP_RIGHT | IDENTIFIER | IGNORING | LAND | LOR | LUNLESS | MAX | METRIC_IDENTIFIER | MIN | OFFSET | ON | QUANTILE | STDDEV | STDVAR | SUM | TOPK;
unary_op : ADD | SUB; unary_op : ADD | SUB;

File diff suppressed because it is too large Load diff

View file

@ -104,6 +104,7 @@ var key = map[string]ItemType{
"count": COUNT, "count": COUNT,
"min": MIN, "min": MIN,
"max": MAX, "max": MAX,
"group": GROUP,
"stddev": STDDEV, "stddev": STDDEV,
"stdvar": STDVAR, "stdvar": STDVAR,
"topk": TOPK, "topk": TOPK,

View file

@ -287,6 +287,9 @@ var tests = []struct {
}, { }, {
input: `AVG`, input: `AVG`,
expected: []Item{{AVG, 0, `AVG`}}, expected: []Item{{AVG, 0, `AVG`}},
}, {
input: `GROUP`,
expected: []Item{{GROUP, 0, `GROUP`}},
}, { }, {
input: `MAX`, input: `MAX`,
expected: []Item{{MAX, 0, `MAX`}}, expected: []Item{{MAX, 0, `MAX`}},

View file

@ -298,3 +298,25 @@ eval instant at 1m quantile without(point)((scalar(foo)), data)
{test="two samples"} 0.8 {test="two samples"} 0.8
{test="three samples"} 1.6 {test="three samples"} 1.6
{test="uneven samples"} 2.8 {test="uneven samples"} 2.8
# Tests for group.
clear
load 10s
data{test="two samples",point="a"} 0
data{test="two samples",point="b"} 1
data{test="three samples",point="a"} 0
data{test="three samples",point="b"} 1
data{test="three samples",point="c"} 2
data{test="uneven samples",point="a"} 0
data{test="uneven samples",point="b"} 1
data{test="uneven samples",point="c"} 4
foo .8
eval instant at 1m group without(point)(data)
{test="two samples"} 1
{test="three samples"} 1
{test="uneven samples"} 1
eval instant at 1m group(foo)
{} 1