Merge pull request #641 from prometheus/stddev

Add stddev and stdvar aggregation functions.
pull/642/head
Julius Volz 10 years ago
commit e681a57d73

@ -68,6 +68,7 @@ type Matrix []SampleStream
type groupedAggregation struct { type groupedAggregation struct {
labels clientmodel.COWMetric labels clientmodel.COWMetric
value clientmodel.SampleValue value clientmodel.SampleValue
valuesSquaredSum clientmodel.SampleValue
groupCount int groupCount int
} }
@ -128,6 +129,8 @@ const (
Min Min
Max Max
Count Count
Stdvar
Stddev
) )
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -468,6 +471,12 @@ func (node *VectorAggregation) groupedAggregationsToVector(aggregations map[uint
aggregation.value = aggregation.value / clientmodel.SampleValue(aggregation.groupCount) aggregation.value = aggregation.value / clientmodel.SampleValue(aggregation.groupCount)
case Count: case Count:
aggregation.value = clientmodel.SampleValue(aggregation.groupCount) aggregation.value = clientmodel.SampleValue(aggregation.groupCount)
case Stdvar:
avg := float64(aggregation.value) / float64(aggregation.groupCount)
aggregation.value = clientmodel.SampleValue(float64(aggregation.valuesSquaredSum)/float64(aggregation.groupCount) - avg*avg)
case Stddev:
avg := float64(aggregation.value) / float64(aggregation.groupCount)
aggregation.value = clientmodel.SampleValue(math.Sqrt(float64(aggregation.valuesSquaredSum)/float64(aggregation.groupCount) - avg*avg))
default: default:
// For other aggregations, we already have the right value. // For other aggregations, we already have the right value.
} }
@ -509,6 +518,10 @@ func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp) Vector {
} }
case Count: case Count:
groupedResult.groupCount++ groupedResult.groupCount++
case Stdvar, Stddev:
groupedResult.value += sample.Value
groupedResult.valuesSquaredSum += sample.Value * sample.Value
groupedResult.groupCount++
default: default:
panic("Unknown aggregation type") panic("Unknown aggregation type")
} }
@ -531,6 +544,7 @@ func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp) Vector {
result[groupingKey] = &groupedAggregation{ result[groupingKey] = &groupedAggregation{
labels: m, labels: m,
value: sample.Value, value: sample.Value,
valuesSquaredSum: sample.Value * sample.Value,
groupCount: 1, groupCount: 1,
} }
} }

@ -65,6 +65,8 @@ func (aggrType AggrType) String() string {
Min: "MIN", Min: "MIN",
Max: "MAX", Max: "MAX",
Count: "COUNT", Count: "COUNT",
Stdvar: "STDVAR",
Stddev: "STDDEV",
} }
return aggrTypeMap[aggrType] return aggrTypeMap[aggrType]
} }

@ -83,6 +83,8 @@ func NewVectorAggregation(aggrTypeStr string, vector ast.Node, groupBy clientmod
"MIN": ast.Min, "MIN": ast.Min,
"AVG": ast.Avg, "AVG": ast.Avg,
"COUNT": ast.Count, "COUNT": ast.Count,
"STDVAR": ast.Stdvar,
"STDDEV": ast.Stddev,
} }
aggrType, ok := aggrTypes[aggrTypeStr] aggrType, ok := aggrTypes[aggrTypeStr]
if !ok { if !ok {

@ -89,8 +89,8 @@ GROUP_LEFT|GROUP_RIGHT lval.str = lexer.token(); return MATCH_MOD
group_left|group_right lval.str = strings.ToUpper(lexer.token()); return MATCH_MOD group_left|group_right lval.str = strings.ToUpper(lexer.token()); return MATCH_MOD
KEEPING_EXTRA|keeping_extra return KEEPING_EXTRA KEEPING_EXTRA|keeping_extra return KEEPING_EXTRA
OFFSET|offset return OFFSET OFFSET|offset return OFFSET
AVG|SUM|MAX|MIN|COUNT lval.str = lexer.token(); return AGGR_OP AVG|SUM|MAX|MIN|COUNT|STDVAR|STDDEV lval.str = lexer.token(); return AGGR_OP
avg|sum|max|min|count lval.str = strings.ToUpper(lexer.token()); return AGGR_OP avg|sum|max|min|count|stdvar|stddev lval.str = strings.ToUpper(lexer.token()); return AGGR_OP
\<|>|AND|OR|and|or lval.str = strings.ToUpper(lexer.token()); return CMP_OP \<|>|AND|OR|and|or lval.str = strings.ToUpper(lexer.token()); return CMP_OP
==|!=|>=|<=|=~|!~ lval.str = lexer.token(); return CMP_OP ==|!=|>=|<=|=~|!~ lval.str = lexer.token(); return CMP_OP
[+\-] lval.str = lexer.token(); return ADDITIVE_OP [+\-] lval.str = lexer.token(); return ADDITIVE_OP

File diff suppressed because it is too large Load Diff

@ -1295,6 +1295,32 @@ func TestExpressions(t *testing.T) {
`{l="y"} => -Inf @[%v]`, `{l="y"} => -Inf @[%v]`,
}, },
}, },
{
expr: `stddev(http_requests)`,
output: []string{
`{} => 229.12878474779 @[%v]`,
},
},
{
expr: `stddev by (instance)(http_requests)`,
output: []string{
`{instance="0"} => 223.60679774998 @[%v]`,
`{instance="1"} => 223.60679774998 @[%v]`,
},
},
{
expr: `stdvar(http_requests)`,
output: []string{
`{} => 52500 @[%v]`,
},
},
{
expr: `stdvar by (instance)(http_requests)`,
output: []string{
`{instance="0"} => 50000 @[%v]`,
`{instance="1"} => 50000 @[%v]`,
},
},
} }
storage, closer := newTestStorage(t) storage, closer := newTestStorage(t)

@ -219,7 +219,7 @@ func NewTemplateExpander(text string, name string, data interface{}, timestamp c
return fmt.Sprintf("%.4g%ss", v, prefix) return fmt.Sprintf("%.4g%ss", v, prefix)
}, },
"pathPrefix": func() string { "pathPrefix": func() string {
return pathPrefix; return pathPrefix
}, },
}, },
} }

Loading…
Cancel
Save