Elasticsearch: Add generic support for template variables (#32762)

* Elasticsearch: Add generic support for template variables

* format MovingAverage settings as numbers

* Move formatting logic to query builder & forma serial_diff settings as numbers

* modify presence check

* add todo

* minor fixes

* transform string values to numbers

* Move casting logic

* Slightly cleaner implementation

* Add BE tests

* Leverage elastic validation when string doesn't resolve to a numeric value

* move newly introduced test to testify

* add FE query_builder tests

* check error

* Parse values to float instead of int

* Fix tests & ParseFloat bit size
This commit is contained in:
Giordano Ricci
2021-04-26 16:54:23 +01:00
committed by GitHub
parent fffa8ad8de
commit c88af6e221
9 changed files with 318 additions and 152 deletions

View File

@@ -164,7 +164,7 @@ func (e *timeSeriesQuery) processQuery(q *Query, ms *es.MultiSearchRequestBuilde
}
aggBuilder.Pipeline(m.ID, m.Type, bucketPath, func(a *es.PipelineAggregation) {
a.Settings = m.Settings.MustMap()
a.Settings = m.generateSettingsForDSL()
})
}
} else {
@@ -181,6 +181,31 @@ func (e *timeSeriesQuery) processQuery(q *Query, ms *es.MultiSearchRequestBuilde
return nil
}
// Casts values to int when required by Elastic's query DSL
func (metricAggregation MetricAgg) generateSettingsForDSL() map[string]interface{} {
setFloatPath := func(path ...string) {
if stringValue, err := metricAggregation.Settings.GetPath(path...).String(); err == nil {
if value, err := strconv.ParseFloat(stringValue, 64); err == nil {
metricAggregation.Settings.SetPath(path, value)
}
}
}
switch metricAggregation.Type {
case "moving_avg":
setFloatPath("window")
setFloatPath("predict")
setFloatPath("settings", "alpha")
setFloatPath("settings", "beta")
setFloatPath("settings", "gamma")
setFloatPath("settings", "period")
case "serial_diff":
setFloatPath("lag")
}
return metricAggregation.Settings.MustMap()
}
func addDateHistogramAgg(aggBuilder es.AggBuilder, bucketAgg *BucketAgg, timeFrom, timeTo string) es.AggBuilder {
aggBuilder.DateHistogram(bucketAgg.ID, bucketAgg.Field, func(a *es.DateHistogramAgg, b es.AggBuilder) {
a.Interval = bucketAgg.Settings.Get("interval").MustString("auto")

View File

@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/plugins"
es "github.com/grafana/grafana/pkg/tsdb/elasticsearch/client"
"github.com/grafana/grafana/pkg/tsdb/interval"
"github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/components/simplejson"
. "github.com/smartystreets/goconvey/convey"
@@ -856,6 +857,83 @@ func TestExecuteTimeSeriesQuery(t *testing.T) {
})
}
func TestSettingsCasting(t *testing.T) {
from := time.Date(2018, 5, 15, 17, 50, 0, 0, time.UTC)
to := time.Date(2018, 5, 15, 17, 55, 0, 0, time.UTC)
t.Run("Correctly transforms moving_average settings", func(t *testing.T) {
c := newFakeClient(5)
_, err := executeTsdbQuery(c, `{
"timeField": "@timestamp",
"bucketAggs": [
{ "type": "date_histogram", "field": "@timestamp", "id": "2" }
],
"metrics": [
{ "id": "1", "type": "average", "field": "@value" },
{
"id": "3",
"type": "moving_avg",
"field": "1",
"pipelineAgg": "1",
"settings": {
"model": "holt_winters",
"window": "10",
"predict": "5",
"settings": {
"alpha": "0.5",
"beta": "0.7",
"gamma": "SHOULD NOT CHANGE",
"period": "4"
}
}
}
]
}`, from, to, 15*time.Second)
assert.Nil(t, err)
sr := c.multisearchRequests[0].Requests[0]
movingAvgSettings := sr.Aggs[0].Aggregation.Aggs[1].Aggregation.Aggregation.(*es.PipelineAggregation).Settings
assert.Equal(t, 10., movingAvgSettings["window"])
assert.Equal(t, 5., movingAvgSettings["predict"])
modelSettings := movingAvgSettings["settings"].(map[string]interface{})
assert.Equal(t, .5, modelSettings["alpha"])
assert.Equal(t, .7, modelSettings["beta"])
assert.Equal(t, "SHOULD NOT CHANGE", modelSettings["gamma"])
assert.Equal(t, 4., modelSettings["period"])
})
t.Run("Correctly transforms serial_diff settings", func(t *testing.T) {
c := newFakeClient(5)
_, err := executeTsdbQuery(c, `{
"timeField": "@timestamp",
"bucketAggs": [
{ "type": "date_histogram", "field": "@timestamp", "id": "2" }
],
"metrics": [
{ "id": "1", "type": "average", "field": "@value" },
{
"id": "3",
"type": "serial_diff",
"field": "1",
"pipelineAgg": "1",
"settings": {
"lag": "1"
}
}
]
}`, from, to, 15*time.Second)
assert.Nil(t, err)
sr := c.multisearchRequests[0].Requests[0]
serialDiffSettings := sr.Aggs[0].Aggregation.Aggs[1].Aggregation.Aggregation.(*es.PipelineAggregation).Settings
assert.Equal(t, 1., serialDiffSettings["lag"])
})
}
type fakeClient struct {
version int
timeField string