mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			459 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			459 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
| package es
 | |
| 
 | |
| import (
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/grafana/grafana/pkg/tsdb"
 | |
| )
 | |
| 
 | |
| // SearchRequestBuilder represents a builder which can build a search request
 | |
| type SearchRequestBuilder struct {
 | |
| 	version      int
 | |
| 	interval     tsdb.Interval
 | |
| 	index        string
 | |
| 	size         int
 | |
| 	sort         map[string]interface{}
 | |
| 	queryBuilder *QueryBuilder
 | |
| 	aggBuilders  []AggBuilder
 | |
| 	customProps  map[string]interface{}
 | |
| }
 | |
| 
 | |
| // NewSearchRequestBuilder create a new search request builder
 | |
| func NewSearchRequestBuilder(version int, interval tsdb.Interval) *SearchRequestBuilder {
 | |
| 	builder := &SearchRequestBuilder{
 | |
| 		version:     version,
 | |
| 		interval:    interval,
 | |
| 		sort:        make(map[string]interface{}),
 | |
| 		customProps: make(map[string]interface{}),
 | |
| 		aggBuilders: make([]AggBuilder, 0),
 | |
| 	}
 | |
| 	return builder
 | |
| }
 | |
| 
 | |
| // Build builds and return a search request
 | |
| func (b *SearchRequestBuilder) Build() (*SearchRequest, error) {
 | |
| 	sr := SearchRequest{
 | |
| 		Index:       b.index,
 | |
| 		Interval:    b.interval,
 | |
| 		Size:        b.size,
 | |
| 		Sort:        b.sort,
 | |
| 		CustomProps: b.customProps,
 | |
| 	}
 | |
| 
 | |
| 	if b.queryBuilder != nil {
 | |
| 		q, err := b.queryBuilder.Build()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		sr.Query = q
 | |
| 	}
 | |
| 
 | |
| 	if len(b.aggBuilders) > 0 {
 | |
| 		sr.Aggs = make(AggArray, 0)
 | |
| 
 | |
| 		for _, ab := range b.aggBuilders {
 | |
| 			aggArray, err := ab.Build()
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 			sr.Aggs = append(sr.Aggs, aggArray...)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return &sr, nil
 | |
| }
 | |
| 
 | |
| // Size sets the size of the search request
 | |
| func (b *SearchRequestBuilder) Size(size int) *SearchRequestBuilder {
 | |
| 	b.size = size
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| // SortDesc adds a sort to the search request
 | |
| func (b *SearchRequestBuilder) SortDesc(field, unmappedType string) *SearchRequestBuilder {
 | |
| 	props := map[string]string{
 | |
| 		"order": "desc",
 | |
| 	}
 | |
| 
 | |
| 	if unmappedType != "" {
 | |
| 		props["unmapped_type"] = unmappedType
 | |
| 	}
 | |
| 
 | |
| 	b.sort[field] = props
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| // AddDocValueField adds a doc value field to the search request
 | |
| func (b *SearchRequestBuilder) AddDocValueField(field string) *SearchRequestBuilder {
 | |
| 	// fields field not supported on version >= 5
 | |
| 	if b.version < 5 {
 | |
| 		b.customProps["fields"] = []string{"*", "_source"}
 | |
| 	}
 | |
| 
 | |
| 	b.customProps["script_fields"] = make(map[string]interface{})
 | |
| 
 | |
| 	if b.version < 5 {
 | |
| 		b.customProps["fielddata_fields"] = []string{field}
 | |
| 	} else {
 | |
| 		b.customProps["docvalue_fields"] = []string{field}
 | |
| 	}
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| // Query creates and return a query builder
 | |
| func (b *SearchRequestBuilder) Query() *QueryBuilder {
 | |
| 	if b.queryBuilder == nil {
 | |
| 		b.queryBuilder = NewQueryBuilder()
 | |
| 	}
 | |
| 	return b.queryBuilder
 | |
| }
 | |
| 
 | |
| // Agg initiate and returns a new aggregation builder
 | |
| func (b *SearchRequestBuilder) Agg() AggBuilder {
 | |
| 	aggBuilder := newAggBuilder(b.version)
 | |
| 	b.aggBuilders = append(b.aggBuilders, aggBuilder)
 | |
| 	return aggBuilder
 | |
| }
 | |
| 
 | |
| // MultiSearchRequestBuilder represents a builder which can build a multi search request
 | |
| type MultiSearchRequestBuilder struct {
 | |
| 	version         int
 | |
| 	requestBuilders []*SearchRequestBuilder
 | |
| }
 | |
| 
 | |
| // NewMultiSearchRequestBuilder creates a new multi search request builder
 | |
| func NewMultiSearchRequestBuilder(version int) *MultiSearchRequestBuilder {
 | |
| 	return &MultiSearchRequestBuilder{
 | |
| 		version: version,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Search initiates and returns a new search request builder
 | |
| func (m *MultiSearchRequestBuilder) Search(interval tsdb.Interval) *SearchRequestBuilder {
 | |
| 	b := NewSearchRequestBuilder(m.version, interval)
 | |
| 	m.requestBuilders = append(m.requestBuilders, b)
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| // Build builds and return a multi search request
 | |
| func (m *MultiSearchRequestBuilder) Build() (*MultiSearchRequest, error) {
 | |
| 	requests := []*SearchRequest{}
 | |
| 	for _, sb := range m.requestBuilders {
 | |
| 		searchRequest, err := sb.Build()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		requests = append(requests, searchRequest)
 | |
| 	}
 | |
| 
 | |
| 	return &MultiSearchRequest{
 | |
| 		Requests: requests,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| // QueryBuilder represents a query builder
 | |
| type QueryBuilder struct {
 | |
| 	boolQueryBuilder *BoolQueryBuilder
 | |
| }
 | |
| 
 | |
| // NewQueryBuilder create a new query builder
 | |
| func NewQueryBuilder() *QueryBuilder {
 | |
| 	return &QueryBuilder{}
 | |
| }
 | |
| 
 | |
| // Build builds and return a query builder
 | |
| func (b *QueryBuilder) Build() (*Query, error) {
 | |
| 	q := Query{}
 | |
| 
 | |
| 	if b.boolQueryBuilder != nil {
 | |
| 		b, err := b.boolQueryBuilder.Build()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		q.Bool = b
 | |
| 	}
 | |
| 
 | |
| 	return &q, nil
 | |
| }
 | |
| 
 | |
| // Bool creates and return a query builder
 | |
| func (b *QueryBuilder) Bool() *BoolQueryBuilder {
 | |
| 	if b.boolQueryBuilder == nil {
 | |
| 		b.boolQueryBuilder = NewBoolQueryBuilder()
 | |
| 	}
 | |
| 	return b.boolQueryBuilder
 | |
| }
 | |
| 
 | |
| // BoolQueryBuilder represents a bool query builder
 | |
| type BoolQueryBuilder struct {
 | |
| 	filterQueryBuilder *FilterQueryBuilder
 | |
| }
 | |
| 
 | |
| // NewBoolQueryBuilder create a new bool query builder
 | |
| func NewBoolQueryBuilder() *BoolQueryBuilder {
 | |
| 	return &BoolQueryBuilder{}
 | |
| }
 | |
| 
 | |
| // Filter creates and return a filter query builder
 | |
| func (b *BoolQueryBuilder) Filter() *FilterQueryBuilder {
 | |
| 	if b.filterQueryBuilder == nil {
 | |
| 		b.filterQueryBuilder = NewFilterQueryBuilder()
 | |
| 	}
 | |
| 	return b.filterQueryBuilder
 | |
| }
 | |
| 
 | |
| // Build builds and return a bool query builder
 | |
| func (b *BoolQueryBuilder) Build() (*BoolQuery, error) {
 | |
| 	boolQuery := BoolQuery{}
 | |
| 
 | |
| 	if b.filterQueryBuilder != nil {
 | |
| 		filters, err := b.filterQueryBuilder.Build()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		boolQuery.Filters = filters
 | |
| 	}
 | |
| 
 | |
| 	return &boolQuery, nil
 | |
| }
 | |
| 
 | |
| // FilterQueryBuilder represents a filter query builder
 | |
| type FilterQueryBuilder struct {
 | |
| 	filters []Filter
 | |
| }
 | |
| 
 | |
| // NewFilterQueryBuilder creates a new filter query builder
 | |
| func NewFilterQueryBuilder() *FilterQueryBuilder {
 | |
| 	return &FilterQueryBuilder{
 | |
| 		filters: make([]Filter, 0),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Build builds and return a filter query builder
 | |
| func (b *FilterQueryBuilder) Build() ([]Filter, error) {
 | |
| 	return b.filters, nil
 | |
| }
 | |
| 
 | |
| // AddDateRangeFilter adds a new time range filter
 | |
| func (b *FilterQueryBuilder) AddDateRangeFilter(timeField, lte, gte, format string) *FilterQueryBuilder {
 | |
| 	b.filters = append(b.filters, &RangeFilter{
 | |
| 		Key:    timeField,
 | |
| 		Lte:    lte,
 | |
| 		Gte:    gte,
 | |
| 		Format: format,
 | |
| 	})
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| // AddQueryStringFilter adds a new query string filter
 | |
| func (b *FilterQueryBuilder) AddQueryStringFilter(querystring string, analyseWildcard bool) *FilterQueryBuilder {
 | |
| 	if len(strings.TrimSpace(querystring)) == 0 {
 | |
| 		return b
 | |
| 	}
 | |
| 
 | |
| 	b.filters = append(b.filters, &QueryStringFilter{
 | |
| 		Query:           querystring,
 | |
| 		AnalyzeWildcard: analyseWildcard,
 | |
| 	})
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| // AggBuilder represents an aggregation builder
 | |
| type AggBuilder interface {
 | |
| 	Histogram(key, field string, fn func(a *HistogramAgg, b AggBuilder)) AggBuilder
 | |
| 	DateHistogram(key, field string, fn func(a *DateHistogramAgg, b AggBuilder)) AggBuilder
 | |
| 	Terms(key, field string, fn func(a *TermsAggregation, b AggBuilder)) AggBuilder
 | |
| 	Filters(key string, fn func(a *FiltersAggregation, b AggBuilder)) AggBuilder
 | |
| 	GeoHashGrid(key, field string, fn func(a *GeoHashGridAggregation, b AggBuilder)) AggBuilder
 | |
| 	Metric(key, metricType, field string, fn func(a *MetricAggregation)) AggBuilder
 | |
| 	Pipeline(key, pipelineType, bucketPath string, fn func(a *PipelineAggregation)) AggBuilder
 | |
| 	Build() (AggArray, error)
 | |
| }
 | |
| 
 | |
| type aggBuilderImpl struct {
 | |
| 	AggBuilder
 | |
| 	aggDefs []*aggDef
 | |
| 	version int
 | |
| }
 | |
| 
 | |
| func newAggBuilder(version int) *aggBuilderImpl {
 | |
| 	return &aggBuilderImpl{
 | |
| 		aggDefs: make([]*aggDef, 0),
 | |
| 		version: version,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (b *aggBuilderImpl) Build() (AggArray, error) {
 | |
| 	aggs := make(AggArray, 0)
 | |
| 
 | |
| 	for _, aggDef := range b.aggDefs {
 | |
| 		agg := &Agg{
 | |
| 			Key:         aggDef.key,
 | |
| 			Aggregation: aggDef.aggregation,
 | |
| 		}
 | |
| 
 | |
| 		for _, cb := range aggDef.builders {
 | |
| 			childAggs, err := cb.Build()
 | |
| 			if err != nil {
 | |
| 				return nil, err
 | |
| 			}
 | |
| 
 | |
| 			agg.Aggregation.Aggs = append(agg.Aggregation.Aggs, childAggs...)
 | |
| 		}
 | |
| 
 | |
| 		aggs = append(aggs, agg)
 | |
| 	}
 | |
| 
 | |
| 	return aggs, nil
 | |
| }
 | |
| 
 | |
| func (b *aggBuilderImpl) Histogram(key, field string, fn func(a *HistogramAgg, b AggBuilder)) AggBuilder {
 | |
| 	innerAgg := &HistogramAgg{
 | |
| 		Field: field,
 | |
| 	}
 | |
| 	aggDef := newAggDef(key, &aggContainer{
 | |
| 		Type:        "histogram",
 | |
| 		Aggregation: innerAgg,
 | |
| 	})
 | |
| 
 | |
| 	if fn != nil {
 | |
| 		builder := newAggBuilder(b.version)
 | |
| 		aggDef.builders = append(aggDef.builders, builder)
 | |
| 		fn(innerAgg, builder)
 | |
| 	}
 | |
| 
 | |
| 	b.aggDefs = append(b.aggDefs, aggDef)
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| func (b *aggBuilderImpl) DateHistogram(key, field string, fn func(a *DateHistogramAgg, b AggBuilder)) AggBuilder {
 | |
| 	innerAgg := &DateHistogramAgg{
 | |
| 		Field: field,
 | |
| 	}
 | |
| 	aggDef := newAggDef(key, &aggContainer{
 | |
| 		Type:        "date_histogram",
 | |
| 		Aggregation: innerAgg,
 | |
| 	})
 | |
| 
 | |
| 	if fn != nil {
 | |
| 		builder := newAggBuilder(b.version)
 | |
| 		aggDef.builders = append(aggDef.builders, builder)
 | |
| 		fn(innerAgg, builder)
 | |
| 	}
 | |
| 
 | |
| 	b.aggDefs = append(b.aggDefs, aggDef)
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| const termsOrderTerm = "_term"
 | |
| 
 | |
| func (b *aggBuilderImpl) Terms(key, field string, fn func(a *TermsAggregation, b AggBuilder)) AggBuilder {
 | |
| 	innerAgg := &TermsAggregation{
 | |
| 		Field: field,
 | |
| 		Order: make(map[string]interface{}),
 | |
| 	}
 | |
| 	aggDef := newAggDef(key, &aggContainer{
 | |
| 		Type:        "terms",
 | |
| 		Aggregation: innerAgg,
 | |
| 	})
 | |
| 
 | |
| 	if fn != nil {
 | |
| 		builder := newAggBuilder(b.version)
 | |
| 		aggDef.builders = append(aggDef.builders, builder)
 | |
| 		fn(innerAgg, builder)
 | |
| 	}
 | |
| 
 | |
| 	if b.version >= 60 && len(innerAgg.Order) > 0 {
 | |
| 		if orderBy, exists := innerAgg.Order[termsOrderTerm]; exists {
 | |
| 			innerAgg.Order["_key"] = orderBy
 | |
| 			delete(innerAgg.Order, termsOrderTerm)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	b.aggDefs = append(b.aggDefs, aggDef)
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| func (b *aggBuilderImpl) Filters(key string, fn func(a *FiltersAggregation, b AggBuilder)) AggBuilder {
 | |
| 	innerAgg := &FiltersAggregation{
 | |
| 		Filters: make(map[string]interface{}),
 | |
| 	}
 | |
| 	aggDef := newAggDef(key, &aggContainer{
 | |
| 		Type:        "filters",
 | |
| 		Aggregation: innerAgg,
 | |
| 	})
 | |
| 	if fn != nil {
 | |
| 		builder := newAggBuilder(b.version)
 | |
| 		aggDef.builders = append(aggDef.builders, builder)
 | |
| 		fn(innerAgg, builder)
 | |
| 	}
 | |
| 
 | |
| 	b.aggDefs = append(b.aggDefs, aggDef)
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| func (b *aggBuilderImpl) GeoHashGrid(key, field string, fn func(a *GeoHashGridAggregation, b AggBuilder)) AggBuilder {
 | |
| 	innerAgg := &GeoHashGridAggregation{
 | |
| 		Field:     field,
 | |
| 		Precision: 5,
 | |
| 	}
 | |
| 	aggDef := newAggDef(key, &aggContainer{
 | |
| 		Type:        "geohash_grid",
 | |
| 		Aggregation: innerAgg,
 | |
| 	})
 | |
| 
 | |
| 	if fn != nil {
 | |
| 		builder := newAggBuilder(b.version)
 | |
| 		aggDef.builders = append(aggDef.builders, builder)
 | |
| 		fn(innerAgg, builder)
 | |
| 	}
 | |
| 
 | |
| 	b.aggDefs = append(b.aggDefs, aggDef)
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| func (b *aggBuilderImpl) Metric(key, metricType, field string, fn func(a *MetricAggregation)) AggBuilder {
 | |
| 	innerAgg := &MetricAggregation{
 | |
| 		Field:    field,
 | |
| 		Settings: make(map[string]interface{}),
 | |
| 	}
 | |
| 	aggDef := newAggDef(key, &aggContainer{
 | |
| 		Type:        metricType,
 | |
| 		Aggregation: innerAgg,
 | |
| 	})
 | |
| 
 | |
| 	if fn != nil {
 | |
| 		fn(innerAgg)
 | |
| 	}
 | |
| 
 | |
| 	b.aggDefs = append(b.aggDefs, aggDef)
 | |
| 
 | |
| 	return b
 | |
| }
 | |
| 
 | |
| func (b *aggBuilderImpl) Pipeline(key, pipelineType, bucketPath string, fn func(a *PipelineAggregation)) AggBuilder {
 | |
| 	innerAgg := &PipelineAggregation{
 | |
| 		BucketPath: bucketPath,
 | |
| 		Settings:   make(map[string]interface{}),
 | |
| 	}
 | |
| 	aggDef := newAggDef(key, &aggContainer{
 | |
| 		Type:        pipelineType,
 | |
| 		Aggregation: innerAgg,
 | |
| 	})
 | |
| 
 | |
| 	if fn != nil {
 | |
| 		fn(innerAgg)
 | |
| 	}
 | |
| 
 | |
| 	b.aggDefs = append(b.aggDefs, aggDef)
 | |
| 
 | |
| 	return b
 | |
| }
 |