未验证 提交 3e796496 编写于 作者: G Gayathri Venkatesh 提交者: GitHub

Hardcoded sorting of query results (#8116)

* Hardcoded sorting of query results
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Add tests for hardcoded sorting
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* More changes
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Modified tests
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Changed tests to descending order
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Changes regarding panic and hardcoded strings for datatypes
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Create ranking function interface
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Added more tests
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Modified the rank interface
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>

* Fixed failing test
Signed-off-by: NGayathriVenkatesh <gayaa2010@gmail.com>
上级 daf382e4
......@@ -196,6 +196,10 @@ type API struct {
gatherer prometheus.Gatherer
}
type Ranker interface {
rank(v promql.Series) float64
}
func init() {
jsoniter.RegisterTypeEncoderFunc("promql.Point", marshalPointJSON, marshalPointJSONIsEmpty)
prometheus.MustRegister(remoteReadQueries)
......@@ -372,6 +376,27 @@ func (api *API) query(r *http.Request) (result apiFuncResult) {
if res.Err != nil {
return apiFuncResult{nil, returnAPIError(res.Err), res.Warnings, qry.Close}
}
var ranker Ranker = avg{}
if res.Value.Type() == parser.ValueTypeVector {
vec, ok := res.Value.(promql.Vector)
if !ok {
err := errors.New("cannot convert to vector")
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
sort.Slice(vec, func(i, j int) bool {
return vec[i].V > vec[j].V
})
} else if res.Value.Type() == parser.ValueTypeMatrix {
mat, ok := res.Value.(promql.Matrix)
if !ok {
err := errors.New("cannot convert to matrix")
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
sort.Slice(mat, func(i, j int) bool {
return (ranker.rank(mat[i]) > ranker.rank(mat[j]))
})
}
// Optional stats field in response if parameter "stats" is not empty.
var qs *stats.QueryStats
......@@ -386,6 +411,23 @@ func (api *API) query(r *http.Request) (result apiFuncResult) {
}, nil, res.Warnings, qry.Close}
}
type sum struct{}
func (s sum) rank(v promql.Series) float64 {
ans := 0.0
for i := 0; i < len(v.Points); i++ {
ans += v.Points[i].V
}
return ans
}
type avg struct{}
func (a avg) rank(v promql.Series) float64 {
var ranker Ranker = sum{}
return ranker.rank(v) / float64(len(v.Points))
}
func (api *API) queryRange(r *http.Request) (result apiFuncResult) {
start, err := parseTime(r.FormValue("start"))
if err != nil {
......@@ -453,6 +495,18 @@ func (api *API) queryRange(r *http.Request) (result apiFuncResult) {
return apiFuncResult{nil, returnAPIError(res.Err), res.Warnings, qry.Close}
}
var ranker Ranker = sum{}
if res.Value.Type() == parser.ValueTypeMatrix {
mat, ok := res.Value.(promql.Matrix)
if !ok {
err := errors.New("Cannot convert to matrix")
return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil}
}
sort.Slice(mat, func(i, j int) bool {
return (ranker.rank(mat[i]) > ranker.rank(mat[j]))
})
}
// Optional stats field in response if parameter "stats" is not empty.
var qs *stats.QueryStats
if r.FormValue("stats") != "" {
......
......@@ -308,6 +308,9 @@ func TestEndpoints(t *testing.T) {
test_metric4{foo="bar", dup="1"} 1+0x100
test_metric4{foo="boo", dup="1"} 1+0x100
test_metric4{foo="boo"} 1+0x100
test_metric5{foo="bar"} 0+100x100
test_metric5{foo="boo"} 1+0x100
test_metric5{foo="boo", dup="1"} 100-1x100
`)
assert.NoError(t, err)
defer suite.Close()
......@@ -414,6 +417,9 @@ func TestLabelNames(t *testing.T) {
test_metric1{foo2="boo"} 1+0x100
test_metric2{foo="boo"} 1+0x100
test_metric2{foo="boo", xyz="qwerty"} 1+0x100
test_metric5{foo1="bar", baz="abc"} 0+100x100
test_metric5{foo2="boo"} 1+0x100
test_metric5{foo="boo"} 100-1x100
`)
assert.NoError(t, err)
defer suite.Close()
......@@ -613,10 +619,69 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, testLabelAPI
},
},
},
{
endpoint: api.query,
query: url.Values{
"query": []string{"test_metric1"},
"time": []string{"123.4"},
},
response: &queryData{
ResultType: parser.ValueTypeVector,
Result: promql.Vector{
{
Point: promql.Point{
V: 200,
T: timestamp.FromTime(start.Add(123*time.Second + 400*time.Millisecond)),
},
Metric: labels.FromStrings("__name__", "test_metric1", "foo", "bar"),
},
{
Point: promql.Point{
V: 1,
T: timestamp.FromTime(start.Add(123*time.Second + 400*time.Millisecond)),
},
Metric: labels.FromStrings("__name__", "test_metric1", "foo", "boo"),
},
},
},
},
{
endpoint: api.query,
query: url.Values{
"query": []string{"test_metric5"},
"time": []string{"123.4"},
},
response: &queryData{
ResultType: parser.ValueTypeVector,
Result: promql.Vector{
{
Point: promql.Point{
V: 200,
T: timestamp.FromTime(start.Add(123*time.Second + 400*time.Millisecond)),
},
Metric: labels.FromStrings("__name__", "test_metric5", "foo", "bar"),
},
{
Point: promql.Point{
V: 98,
T: timestamp.FromTime(start.Add(123*time.Second + 400*time.Millisecond)),
},
Metric: labels.FromStrings("__name__", "test_metric5", "dup", "1", "foo", "boo"),
},
{
Point: promql.Point{
V: 1,
T: timestamp.FromTime(start.Add(123*time.Second + 400*time.Millisecond)),
},
Metric: labels.FromStrings("__name__", "test_metric5", "foo", "boo"),
},
},
},
},
{
endpoint: api.queryRange,
query: url.Values{
"query": []string{"time()"},
"query": []string{"test_metric1"},
"start": []string{"0"},
"end": []string{"2"},
"step": []string{"1"},
......@@ -624,13 +689,59 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, testLabelAPI
response: &queryData{
ResultType: parser.ValueTypeMatrix,
Result: promql.Matrix{
promql.Series{
Points: []promql.Point{
{V: 1, T: timestamp.FromTime(start)},
{V: 1, T: timestamp.FromTime(start.Add(1 * time.Second))},
{V: 1, T: timestamp.FromTime(start.Add(2 * time.Second))},
},
Metric: labels.FromStrings("__name__", "test_metric1", "foo", "boo"),
},
promql.Series{
Points: []promql.Point{
{V: 0, T: timestamp.FromTime(start)},
{V: 0, T: timestamp.FromTime(start.Add(1 * time.Second))},
{V: 0, T: timestamp.FromTime(start.Add(2 * time.Second))},
},
Metric: labels.FromStrings("__name__", "test_metric1", "foo", "bar"),
},
},
},
},
{
endpoint: api.queryRange,
query: url.Values{
"query": []string{"test_metric5"},
"start": []string{"0"},
"end": []string{"2"},
"step": []string{"1"},
},
response: &queryData{
ResultType: parser.ValueTypeMatrix,
Result: promql.Matrix{
promql.Series{
Points: []promql.Point{
{V: 100, T: timestamp.FromTime(start)},
{V: 100, T: timestamp.FromTime(start.Add(1 * time.Second))},
{V: 100, T: timestamp.FromTime(start.Add(2 * time.Second))},
},
Metric: labels.FromStrings("__name__", "test_metric5", "dup", "1", "foo", "boo"),
},
promql.Series{
Points: []promql.Point{
{V: 1, T: timestamp.FromTime(start)},
{V: 1, T: timestamp.FromTime(start.Add(1 * time.Second))},
{V: 2, T: timestamp.FromTime(start.Add(2 * time.Second))},
{V: 1, T: timestamp.FromTime(start.Add(2 * time.Second))},
},
Metric: labels.FromStrings("__name__", "test_metric5", "foo", "boo"),
},
promql.Series{
Points: []promql.Point{
{V: 0, T: timestamp.FromTime(start)},
{V: 0, T: timestamp.FromTime(start.Add(1 * time.Second))},
{V: 0, T: timestamp.FromTime(start.Add(2 * time.Second))},
},
Metric: nil,
Metric: labels.FromStrings("__name__", "test_metric5", "foo", "bar"),
},
},
},
......@@ -1468,6 +1579,7 @@ func testEndpoints(t *testing.T, api *API, tr *testTargetRetriever, testLabelAPI
"test_metric2",
"test_metric3",
"test_metric4",
"test_metric5",
},
},
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册