SSE: Support time series frames with non-nullable float64 values (#32608)

* SSE: fix reduce to handle non-null
* add type for data.Field that is float64 or *float64
* resample fix for non-null input case, add couple non-null tests
This commit is contained in:
Kyle Brandt
2021-04-01 14:33:35 -04:00
committed by GitHub
parent d42a5b2561
commit 512faa7c9c
7 changed files with 167 additions and 115 deletions
+1
View File
@@ -86,6 +86,7 @@ func (ccc *ConditionsCmd) Execute(ctx context.Context, vars mathexp.Vars) (mathe
}
reducedNum := c.Reducer.Reduce(series)
// TODO handle error / no data signals
thisCondNoDataFound := reducedNum.GetFloat64Value() == nil
+65 -74
View File
@@ -4,7 +4,6 @@ import (
"math"
"sort"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/expr/mathexp"
)
@@ -35,44 +34,42 @@ func (cr classicReducer) Reduce(series mathexp.Series) mathexp.Number {
allNull := true
vF := series.Frame.Fields[series.ValueIdx]
ff := mathexp.Float64Field(*vF)
switch cr {
case "avg":
validPointsCount := 0
for i := 0; i < vF.Len(); i++ {
if f, ok := vF.At(i).(*float64); ok {
if nilOrNaN(f) {
continue
}
value += *f
validPointsCount++
allNull = false
for i := 0; i < ff.Len(); i++ {
f := ff.GetValue(i)
if nilOrNaN(f) {
continue
}
value += *f
validPointsCount++
allNull = false
}
if validPointsCount > 0 {
value /= float64(validPointsCount)
}
case "sum":
for i := 0; i < vF.Len(); i++ {
if f, ok := vF.At(i).(*float64); ok {
if nilOrNaN(f) {
continue
}
value += *f
allNull = false
for i := 0; i < ff.Len(); i++ {
f := ff.GetValue(i)
if nilOrNaN(f) {
continue
}
value += *f
allNull = false
}
case "min":
value = math.MaxFloat64
for i := 0; i < vF.Len(); i++ {
if f, ok := vF.At(i).(*float64); ok {
if nilOrNaN(f) {
continue
}
allNull = false
if value > *f {
value = *f
}
for i := 0; i < ff.Len(); i++ {
f := ff.GetValue(i)
if nilOrNaN(f) {
continue
}
allNull = false
if value > *f {
value = *f
}
}
if allNull {
@@ -80,43 +77,40 @@ func (cr classicReducer) Reduce(series mathexp.Series) mathexp.Number {
}
case "max":
value = -math.MaxFloat64
for i := 0; i < vF.Len(); i++ {
if f, ok := vF.At(i).(*float64); ok {
if nilOrNaN(f) {
continue
}
allNull = false
if value < *f {
value = *f
}
for i := 0; i < ff.Len(); i++ {
f := ff.GetValue(i)
if nilOrNaN(f) {
continue
}
allNull = false
if value < *f {
value = *f
}
}
if allNull {
value = 0
}
case "count":
value = float64(vF.Len())
value = float64(ff.Len())
allNull = false
case "last":
for i := vF.Len() - 1; i >= 0; i-- {
if f, ok := vF.At(i).(*float64); ok {
if !nilOrNaN(f) {
value = *f
allNull = false
break
}
for i := ff.Len() - 1; i >= 0; i-- {
f := ff.GetValue(i)
if !nilOrNaN(f) {
value = *f
allNull = false
break
}
}
case "median":
var values []float64
for i := 0; i < vF.Len(); i++ {
if f, ok := vF.At(i).(*float64); ok {
if nilOrNaN(f) {
continue
}
allNull = false
values = append(values, *f)
for i := 0; i < ff.Len(); i++ {
f := ff.GetValue(i)
if nilOrNaN(f) {
continue
}
allNull = false
values = append(values, *f)
}
if len(values) >= 1 {
sort.Float64s(values)
@@ -128,21 +122,20 @@ func (cr classicReducer) Reduce(series mathexp.Series) mathexp.Number {
}
}
case "diff":
allNull, value = calculateDiff(vF, allNull, value, diff)
allNull, value = calculateDiff(ff, allNull, value, diff)
case "diff_abs":
allNull, value = calculateDiff(vF, allNull, value, diffAbs)
allNull, value = calculateDiff(ff, allNull, value, diffAbs)
case "percent_diff":
allNull, value = calculateDiff(vF, allNull, value, percentDiff)
allNull, value = calculateDiff(ff, allNull, value, percentDiff)
case "percent_diff_abs":
allNull, value = calculateDiff(vF, allNull, value, percentDiffAbs)
allNull, value = calculateDiff(ff, allNull, value, percentDiffAbs)
case "count_non_null":
for i := 0; i < vF.Len(); i++ {
if f, ok := vF.At(i).(*float64); ok {
if nilOrNaN(f) {
continue
}
value++
for i := 0; i < ff.Len(); i++ {
f := ff.GetValue(i)
if nilOrNaN(f) {
continue
}
value++
}
if value > 0 {
@@ -158,30 +151,28 @@ func (cr classicReducer) Reduce(series mathexp.Series) mathexp.Number {
return num
}
func calculateDiff(vF *data.Field, allNull bool, value float64, fn func(float64, float64) float64) (bool, float64) {
func calculateDiff(ff mathexp.Float64Field, allNull bool, value float64, fn func(float64, float64) float64) (bool, float64) {
var (
first float64
i int
)
// get the newest point
for i = vF.Len() - 1; i >= 0; i-- {
if f, ok := vF.At(i).(*float64); ok {
if !nilOrNaN(f) {
first = *f
allNull = false
break
}
for i = ff.Len() - 1; i >= 0; i-- {
f := ff.GetValue(i)
if !nilOrNaN(f) {
first = *f
allNull = false
break
}
}
if i >= 1 {
// get the oldest point
for i := 0; i < vF.Len(); i++ {
if f, ok := vF.At(i).(*float64); ok {
if !nilOrNaN(f) {
value = fn(first, *f)
allNull = false
break
}
for i := 0; i < ff.Len(); i++ {
f := ff.GetValue(i)
if !nilOrNaN(f) {
value = fn(first, *f)
allNull = false
break
}
}
}