diff --git a/cmd/influxd/server_integration_test.go b/cmd/influxd/server_integration_test.go index 7e0bbb8898..26b79f0ddf 100644 --- a/cmd/influxd/server_integration_test.go +++ b/cmd/influxd/server_integration_test.go @@ -581,14 +581,41 @@ func runTestsData(t *testing.T, testName string, nodes Cluster, database, retent // Aggregations { reset: true, - name: "large mean", + name: "stddev with just one point", + write: `{"database" : "%DB%", "retentionPolicy" : "%RP%", "points": [ + {"name": "cpu", "timestamp": "2015-04-20T14:27:41Z", "fields": {"value": 45}} + ]}`, + query: `SELECT stddev(value) FROM cpu`, + queryDb: "%DB%", + expected: `{"results":[{"series":[{"name":"cpu","columns":["time","stddev"],"values":[["1970-01-01T00:00:00Z",null]]}]}]}`, + }, + { + reset: true, + name: "large mean and stddev", write: `{"database" : "%DB%", "retentionPolicy" : "%RP%", "points": [ {"name": "cpu", "timestamp": "2015-04-20T14:27:40Z", "fields": {"value": ` + string(maxFloat64) + `}}, {"name": "cpu", "timestamp": "2015-04-20T14:27:41Z", "fields": {"value": ` + string(maxFloat64) + `}} ]}`, - query: `SELECT mean(value) FROM cpu`, + query: `SELECT mean(value), stddev(value) FROM cpu`, queryDb: "%DB%", - expected: `{"results":[{"series":[{"name":"cpu","columns":["time","mean"],"values":[["1970-01-01T00:00:00Z",` + string(maxFloat64) + `]]}]}]}`, + expected: `{"results":[{"series":[{"name":"cpu","columns":["time","mean","stddev"],"values":[["1970-01-01T00:00:00Z",` + string(maxFloat64) + `,0]]}]}]}`, + }, + { + reset: true, + name: "mean and stddev", + write: `{"database" : "%DB%", "retentionPolicy" : "%RP%", "points": [ + {"name": "cpu", "timestamp": "2000-01-01T00:00:00Z", "fields": {"value": 2}}, + {"name": "cpu", "timestamp": "2000-01-01T00:00:10Z", "fields": {"value": 4}}, + {"name": "cpu", "timestamp": "2000-01-01T00:00:20Z", "fields": {"value": 4}}, + {"name": "cpu", "timestamp": "2000-01-01T00:00:30Z", "fields": {"value": 4}}, + {"name": "cpu", "timestamp": "2000-01-01T00:00:40Z", "fields": {"value": 5}}, + {"name": "cpu", "timestamp": "2000-01-01T00:00:50Z", "fields": {"value": 5}}, + {"name": "cpu", "timestamp": "2000-01-01T00:01:00Z", "fields": {"value": 7}}, + {"name": "cpu", "timestamp": "2000-01-01T00:01:10Z", "fields": {"value": 9}} + ]}`, + query: `SELECT mean(value), stddev(value) FROM cpu WHERE time >= '2000-01-01' AND time < '2000-01-01T00:02:00Z' GROUP BY time(10m)`, + queryDb: "%DB%", + expected: `{"results":[{"series":[{"name":"cpu","columns":["time","mean","stddev"],"values":[["2000-01-01T00:00:00Z",5,2.138089935299395]]}]}]}`, }, { reset: true, diff --git a/influxql/functions.go b/influxql/functions.go index e4cae8508d..f81dde4594 100644 --- a/influxql/functions.go +++ b/influxql/functions.go @@ -157,6 +157,12 @@ func InitializeUnmarshaller(c *Call) (UnmarshalFunc, error) { err := json.Unmarshal(b, &o) return &o, err }, nil + case "stddev": + return func(b []byte) (interface{}, error) { + val := make([]float64, 0) + err := json.Unmarshal(b, &val) + return val, err + }, nil default: return func(b []byte) (interface{}, error) { var val interface{} @@ -395,7 +401,7 @@ func MapStddev(itr Iterator) interface{} { values = append(values, v.(float64)) } - return nil + return values } // ReduceStddev computes the stddev of values. @@ -414,13 +420,13 @@ func ReduceStddev(values []interface{}) interface{} { return nil } - // Get the sum - var sum float64 - for _, v := range data { - sum += v - } // Get the mean - mean := sum / float64(len(data)) + var mean float64 + var count int + for _, v := range data { + count++ + mean += (v - mean) / float64(count) + } // Get the variance var variance float64 for _, v := range data { @@ -428,7 +434,7 @@ func ReduceStddev(values []interface{}) interface{} { sq := math.Pow(dif, 2) variance += sq } - variance = variance / float64(len(data)-1) + variance = variance / float64(count-1) stddev := math.Sqrt(variance) return stddev