mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
* use fixed_interval in date_histogram * Add 8.0 to available versions in datasource settings * Remove moving_avg from available metric aggregations * Add ES8 devenv * Update public/app/plugins/datasource/elasticsearch/components/QueryEditor/MetricAggregationsEditor/utils.ts Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com> * Add FE tests * Add BE test * fix FE test * fix BE test Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
349 lines
8.0 KiB
Go
349 lines
8.0 KiB
Go
package es
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
|
)
|
|
|
|
type response struct {
|
|
httpResponse *http.Response
|
|
reqInfo *SearchRequestInfo
|
|
}
|
|
|
|
type SearchRequestInfo struct {
|
|
Method string `json:"method"`
|
|
Url string `json:"url"`
|
|
Data string `json:"data"`
|
|
}
|
|
|
|
type SearchResponseInfo struct {
|
|
Status int `json:"status"`
|
|
Data *simplejson.Json `json:"data"`
|
|
}
|
|
|
|
type SearchDebugInfo struct {
|
|
Request *SearchRequestInfo `json:"request"`
|
|
Response *SearchResponseInfo `json:"response"`
|
|
}
|
|
|
|
// SearchRequest represents a search request
|
|
type SearchRequest struct {
|
|
Index string
|
|
Interval intervalv2.Interval
|
|
Size int
|
|
Sort map[string]interface{}
|
|
Query *Query
|
|
Aggs AggArray
|
|
CustomProps map[string]interface{}
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the request.
|
|
func (r *SearchRequest) MarshalJSON() ([]byte, error) {
|
|
root := make(map[string]interface{})
|
|
|
|
root["size"] = r.Size
|
|
if len(r.Sort) > 0 {
|
|
root["sort"] = r.Sort
|
|
}
|
|
|
|
for key, value := range r.CustomProps {
|
|
root[key] = value
|
|
}
|
|
|
|
root["query"] = r.Query
|
|
|
|
if len(r.Aggs) > 0 {
|
|
root["aggs"] = r.Aggs
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|
|
|
|
// SearchResponseHits represents search response hits
|
|
type SearchResponseHits struct {
|
|
Hits []map[string]interface{}
|
|
}
|
|
|
|
// SearchResponse represents a search response
|
|
type SearchResponse struct {
|
|
Error map[string]interface{} `json:"error"`
|
|
Aggregations map[string]interface{} `json:"aggregations"`
|
|
Hits *SearchResponseHits `json:"hits"`
|
|
}
|
|
|
|
// MultiSearchRequest represents a multi search request
|
|
type MultiSearchRequest struct {
|
|
Requests []*SearchRequest
|
|
}
|
|
|
|
// MultiSearchResponse represents a multi search response
|
|
type MultiSearchResponse struct {
|
|
Status int `json:"status,omitempty"`
|
|
Responses []*SearchResponse `json:"responses"`
|
|
DebugInfo *SearchDebugInfo `json:"-"`
|
|
}
|
|
|
|
// Query represents a query
|
|
type Query struct {
|
|
Bool *BoolQuery `json:"bool"`
|
|
}
|
|
|
|
// BoolQuery represents a bool query
|
|
type BoolQuery struct {
|
|
Filters []Filter
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the boolean query.
|
|
func (q *BoolQuery) MarshalJSON() ([]byte, error) {
|
|
root := make(map[string]interface{})
|
|
|
|
if len(q.Filters) > 0 {
|
|
if len(q.Filters) == 1 {
|
|
root["filter"] = q.Filters[0]
|
|
} else {
|
|
root["filter"] = q.Filters
|
|
}
|
|
}
|
|
return json.Marshal(root)
|
|
}
|
|
|
|
// Filter represents a search filter
|
|
type Filter interface{}
|
|
|
|
// QueryStringFilter represents a query string search filter
|
|
type QueryStringFilter struct {
|
|
Filter
|
|
Query string
|
|
AnalyzeWildcard bool
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the query string filter.
|
|
func (f *QueryStringFilter) MarshalJSON() ([]byte, error) {
|
|
root := map[string]interface{}{
|
|
"query_string": map[string]interface{}{
|
|
"query": f.Query,
|
|
"analyze_wildcard": f.AnalyzeWildcard,
|
|
},
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|
|
|
|
// RangeFilter represents a range search filter
|
|
type RangeFilter struct {
|
|
Filter
|
|
Key string
|
|
Gte string
|
|
Lte string
|
|
Format string
|
|
}
|
|
|
|
// DateFormatEpochMS represents a date format of epoch milliseconds (epoch_millis)
|
|
const DateFormatEpochMS = "epoch_millis"
|
|
|
|
// MarshalJSON returns the JSON encoding of the query string filter.
|
|
func (f *RangeFilter) MarshalJSON() ([]byte, error) {
|
|
root := map[string]map[string]map[string]interface{}{
|
|
"range": {
|
|
f.Key: {
|
|
"lte": f.Lte,
|
|
"gte": f.Gte,
|
|
},
|
|
},
|
|
}
|
|
|
|
if f.Format != "" {
|
|
root["range"][f.Key]["format"] = f.Format
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|
|
|
|
// Aggregation represents an aggregation
|
|
type Aggregation interface{}
|
|
|
|
// Agg represents a key and aggregation
|
|
type Agg struct {
|
|
Key string
|
|
Aggregation *aggContainer
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the agg
|
|
func (a *Agg) MarshalJSON() ([]byte, error) {
|
|
root := map[string]interface{}{
|
|
a.Key: a.Aggregation,
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|
|
|
|
// AggArray represents a collection of key/aggregation pairs
|
|
type AggArray []*Agg
|
|
|
|
// MarshalJSON returns the JSON encoding of the agg
|
|
func (a AggArray) MarshalJSON() ([]byte, error) {
|
|
aggsMap := make(map[string]Aggregation)
|
|
|
|
for _, subAgg := range a {
|
|
aggsMap[subAgg.Key] = subAgg.Aggregation
|
|
}
|
|
|
|
return json.Marshal(aggsMap)
|
|
}
|
|
|
|
type aggContainer struct {
|
|
Type string
|
|
Aggregation Aggregation
|
|
Aggs AggArray
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the aggregation container
|
|
func (a *aggContainer) MarshalJSON() ([]byte, error) {
|
|
root := map[string]interface{}{
|
|
a.Type: a.Aggregation,
|
|
}
|
|
|
|
if len(a.Aggs) > 0 {
|
|
root["aggs"] = a.Aggs
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|
|
|
|
type aggDef struct {
|
|
key string
|
|
aggregation *aggContainer
|
|
builders []AggBuilder
|
|
}
|
|
|
|
func newAggDef(key string, aggregation *aggContainer) *aggDef {
|
|
return &aggDef{
|
|
key: key,
|
|
aggregation: aggregation,
|
|
builders: make([]AggBuilder, 0),
|
|
}
|
|
}
|
|
|
|
// HistogramAgg represents a histogram aggregation
|
|
type HistogramAgg struct {
|
|
Interval int `json:"interval,omitempty"`
|
|
Field string `json:"field"`
|
|
MinDocCount int `json:"min_doc_count"`
|
|
Missing *int `json:"missing,omitempty"`
|
|
}
|
|
|
|
// DateHistogramAgg represents a date histogram aggregation
|
|
type DateHistogramAgg struct {
|
|
Field string `json:"field"`
|
|
Interval string `json:"interval,omitempty"`
|
|
FixedInterval string `json:"fixed_interval,omitempty"`
|
|
MinDocCount int `json:"min_doc_count"`
|
|
Missing *string `json:"missing,omitempty"`
|
|
ExtendedBounds *ExtendedBounds `json:"extended_bounds"`
|
|
Format string `json:"format"`
|
|
Offset string `json:"offset,omitempty"`
|
|
TimeZone string `json:"time_zone,omitempty"`
|
|
}
|
|
|
|
// FiltersAggregation represents a filters aggregation
|
|
type FiltersAggregation struct {
|
|
Filters map[string]interface{} `json:"filters"`
|
|
}
|
|
|
|
// TermsAggregation represents a terms aggregation
|
|
type TermsAggregation struct {
|
|
Field string `json:"field"`
|
|
Size int `json:"size"`
|
|
Order map[string]interface{} `json:"order"`
|
|
MinDocCount *int `json:"min_doc_count,omitempty"`
|
|
Missing *string `json:"missing,omitempty"`
|
|
}
|
|
|
|
// ExtendedBounds represents extended bounds
|
|
type ExtendedBounds struct {
|
|
Min string `json:"min"`
|
|
Max string `json:"max"`
|
|
}
|
|
|
|
// GeoHashGridAggregation represents a geo hash grid aggregation
|
|
type GeoHashGridAggregation struct {
|
|
Field string `json:"field"`
|
|
Precision int `json:"precision"`
|
|
}
|
|
|
|
// MetricAggregation represents a metric aggregation
|
|
type MetricAggregation struct {
|
|
Type string
|
|
Field string
|
|
Settings map[string]interface{}
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the metric aggregation
|
|
func (a *MetricAggregation) MarshalJSON() ([]byte, error) {
|
|
if a.Type == "top_metrics" {
|
|
root := map[string]interface{}{}
|
|
var rootMetrics []map[string]string
|
|
|
|
order, hasOrder := a.Settings["order"]
|
|
orderBy, hasOrderBy := a.Settings["orderBy"]
|
|
|
|
root["size"] = "1"
|
|
|
|
metrics, hasMetrics := a.Settings["metrics"].([]interface{})
|
|
if hasMetrics {
|
|
for _, v := range metrics {
|
|
metricValue := map[string]string{"field": v.(string)}
|
|
rootMetrics = append(rootMetrics, metricValue)
|
|
}
|
|
root["metrics"] = rootMetrics
|
|
}
|
|
|
|
if hasOrderBy && hasOrder {
|
|
root["sort"] = []map[string]interface{}{
|
|
{
|
|
orderBy.(string): order,
|
|
},
|
|
}
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|
|
root := map[string]interface{}{}
|
|
|
|
if a.Field != "" {
|
|
root["field"] = a.Field
|
|
}
|
|
|
|
for k, v := range a.Settings {
|
|
if k != "" && v != nil {
|
|
root[k] = v
|
|
}
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|
|
|
|
// PipelineAggregation represents a metric aggregation
|
|
type PipelineAggregation struct {
|
|
BucketPath interface{}
|
|
Settings map[string]interface{}
|
|
}
|
|
|
|
// MarshalJSON returns the JSON encoding of the pipeline aggregation
|
|
func (a *PipelineAggregation) MarshalJSON() ([]byte, error) {
|
|
root := map[string]interface{}{
|
|
"buckets_path": a.BucketPath,
|
|
}
|
|
|
|
for k, v := range a.Settings {
|
|
if k != "" && v != nil {
|
|
root[k] = v
|
|
}
|
|
}
|
|
|
|
return json.Marshal(root)
|
|
}
|