influxdb/query/functions/percentile_test.go

333 lines
7.8 KiB
Go

package functions_test
import (
"math"
"testing"
"github.com/influxdata/platform/query"
"github.com/influxdata/platform/query/execute"
"github.com/influxdata/platform/query/execute/executetest"
"github.com/influxdata/platform/query/functions"
"github.com/influxdata/platform/query/querytest"
)
func TestPercentileOperation_Marshaling(t *testing.T) {
data := []byte(`{"id":"percentile","kind":"percentile","spec":{"percentile":0.9}}`)
op := &query.Operation{
ID: "percentile",
Spec: &functions.PercentileOpSpec{
Percentile: 0.9,
},
}
querytest.OperationMarshalingTestHelper(t, data, op)
}
func TestPercentile_Process(t *testing.T) {
testCases := []struct {
name string
data []float64
percentile float64
exact bool
want float64
}{
{
name: "zero",
data: []float64{0, 0, 0},
percentile: 0.5,
want: 0.0,
},
{
name: "50th",
data: []float64{1, 2, 3, 4, 5, 5, 4, 3, 2, 1},
percentile: 0.5,
want: 3,
},
{
name: "75th",
data: []float64{1, 2, 3, 4, 5, 5, 4, 3, 2, 1},
percentile: 0.75,
want: 4,
},
{
name: "90th",
data: []float64{1, 2, 3, 4, 5, 5, 4, 3, 2, 1},
percentile: 0.9,
want: 5,
},
{
name: "99th",
data: []float64{1, 2, 3, 4, 5, 5, 4, 3, 2, 1},
percentile: 0.99,
want: 5,
},
{
name: "exact 50th",
data: []float64{1, 2, 3, 4, 5},
percentile: 0.5,
exact: true,
want: 3,
},
{
name: "exact 75th",
data: []float64{1, 2, 3, 4, 5},
percentile: 0.75,
exact: true,
want: 4,
},
{
name: "exact 90th",
data: []float64{1, 2, 3, 4, 5},
percentile: 0.9,
exact: true,
want: 4.6,
},
{
name: "exact 99th",
data: []float64{1, 2, 3, 4, 5},
percentile: 0.99,
exact: true,
want: 4.96,
},
{
name: "exact 100th",
data: []float64{1, 2, 3, 4, 5},
percentile: 1,
exact: true,
want: 5,
},
{
name: "exact 50th normal",
data: NormalData,
percentile: 0.5,
exact: true,
want: 9.997645059676595,
},
{
name: "normal",
data: NormalData,
percentile: 0.9,
want: 13.843815760607427,
},
{
name: "NaN",
data: []float64{},
want: math.NaN(),
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
var agg execute.Aggregate
if tc.exact {
agg = &functions.ExactPercentileAgg{Quantile: tc.percentile}
} else {
agg = &functions.PercentileAgg{
Quantile: tc.percentile,
Compression: 1000,
}
}
executetest.AggFuncTestHelper(
t,
agg,
tc.data,
tc.want,
)
})
}
}
func TestPercentileSelector_Process(t *testing.T) {
testCases := []struct {
name string
quantile float64
data *executetest.Table
want []execute.Row
}{
{
name: "select_10",
quantile: 0.1,
data: &executetest.Table{
KeyCols: []string{"t1"},
ColMeta: []query.ColMeta{
{Label: "_time", Type: query.TTime},
{Label: "_value", Type: query.TFloat},
{Label: "t1", Type: query.TString},
{Label: "t2", Type: query.TString},
},
Data: [][]interface{}{
{execute.Time(0), 1.0, "a", "y"},
{execute.Time(10), 2.0, "a", "x"},
{execute.Time(20), 3.0, "a", "y"},
{execute.Time(30), 4.0, "a", "x"},
{execute.Time(40), 5.0, "a", "y"},
},
},
want: []execute.Row{{
Values: []interface{}{execute.Time(0), 1.0, "a", "y"},
}},
},
{
name: "select_20",
quantile: 0.2,
data: &executetest.Table{
KeyCols: []string{"t1"},
ColMeta: []query.ColMeta{
{Label: "_time", Type: query.TTime},
{Label: "_value", Type: query.TFloat},
{Label: "t1", Type: query.TString},
{Label: "t2", Type: query.TString},
},
Data: [][]interface{}{
{execute.Time(0), 1.0, "a", "y"},
{execute.Time(10), 2.0, "a", "x"},
{execute.Time(20), 3.0, "a", "y"},
{execute.Time(30), 4.0, "a", "x"},
{execute.Time(40), 5.0, "a", "y"},
},
},
want: []execute.Row{{
Values: []interface{}{execute.Time(0), 1.0, "a", "y"},
}},
},
{
name: "select_40",
quantile: 0.4,
data: &executetest.Table{
KeyCols: []string{"t1"},
ColMeta: []query.ColMeta{
{Label: "_time", Type: query.TTime},
{Label: "_value", Type: query.TFloat},
{Label: "t1", Type: query.TString},
{Label: "t2", Type: query.TString},
},
Data: [][]interface{}{
{execute.Time(0), 1.0, "a", "y"},
{execute.Time(10), 2.0, "a", "x"},
{execute.Time(20), 3.0, "a", "y"},
{execute.Time(30), 4.0, "a", "x"},
{execute.Time(40), 5.0, "a", "y"},
},
},
want: []execute.Row{{
Values: []interface{}{execute.Time(10), 2.0, "a", "x"},
}},
},
{
name: "select_50",
quantile: 0.5,
data: &executetest.Table{
KeyCols: []string{"t1"},
ColMeta: []query.ColMeta{
{Label: "_time", Type: query.TTime},
{Label: "_value", Type: query.TFloat},
{Label: "t1", Type: query.TString},
{Label: "t2", Type: query.TString},
},
Data: [][]interface{}{
{execute.Time(0), 1.0, "a", "y"},
{execute.Time(10), 2.0, "a", "x"},
{execute.Time(20), 3.0, "a", "y"},
{execute.Time(30), 4.0, "a", "x"},
{execute.Time(40), 5.0, "a", "y"},
},
},
want: []execute.Row{{
Values: []interface{}{execute.Time(20), 3.0, "a", "y"},
}},
},
{
name: "select_80",
quantile: 0.8,
data: &executetest.Table{
KeyCols: []string{"t1"},
ColMeta: []query.ColMeta{
{Label: "_time", Type: query.TTime},
{Label: "_value", Type: query.TFloat},
{Label: "t1", Type: query.TString},
{Label: "t2", Type: query.TString},
},
Data: [][]interface{}{
{execute.Time(0), 1.0, "a", "y"},
{execute.Time(10), 2.0, "a", "x"},
{execute.Time(20), 3.0, "a", "y"},
{execute.Time(30), 4.0, "a", "x"},
{execute.Time(40), 5.0, "a", "y"},
},
},
want: []execute.Row{{
Values: []interface{}{execute.Time(30), 4.0, "a", "x"},
}},
},
{
name: "select_90",
quantile: 0.9,
data: &executetest.Table{
KeyCols: []string{"t1"},
ColMeta: []query.ColMeta{
{Label: "_time", Type: query.TTime},
{Label: "_value", Type: query.TFloat},
{Label: "t1", Type: query.TString},
{Label: "t2", Type: query.TString},
},
Data: [][]interface{}{
{execute.Time(0), 1.0, "a", "y"},
{execute.Time(10), 2.0, "a", "x"},
{execute.Time(20), 3.0, "a", "y"},
{execute.Time(30), 4.0, "a", "x"},
{execute.Time(40), 5.0, "a", "y"},
},
},
want: []execute.Row{{
Values: []interface{}{execute.Time(40), 5.0, "a", "y"},
}},
},
{
name: "select_100",
quantile: 1.0,
data: &executetest.Table{
KeyCols: []string{"t1"},
ColMeta: []query.ColMeta{
{Label: "_time", Type: query.TTime},
{Label: "_value", Type: query.TFloat},
{Label: "t1", Type: query.TString},
{Label: "t2", Type: query.TString},
},
Data: [][]interface{}{
{execute.Time(0), 1.0, "a", "y"},
{execute.Time(10), 2.0, "a", "x"},
{execute.Time(20), 3.0, "a", "y"},
{execute.Time(30), 4.0, "a", "x"},
{execute.Time(40), 5.0, "a", "y"},
},
},
want: []execute.Row{{
Values: []interface{}{execute.Time(40), 5.0, "a", "y"},
}},
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
executetest.RowSelectorFuncTestHelper(
t,
&functions.ExactPercentileSelector{Quantile: tc.quantile},
tc.data,
tc.want,
)
})
}
}
func BenchmarkPercentile(b *testing.B) {
executetest.AggFuncBenchmarkHelper(
b,
&functions.PercentileAgg{
Quantile: 0.9,
Compression: 1000,
},
NormalData,
13.843815760607427,
)
}