mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
447 lines
10 KiB
Go
447 lines
10 KiB
Go
|
package es
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// SearchRequestBuilder represents a builder which can build a search request
|
||
|
type SearchRequestBuilder struct {
|
||
|
version int
|
||
|
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) *SearchRequestBuilder {
|
||
|
builder := &SearchRequestBuilder{
|
||
|
version: version,
|
||
|
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,
|
||
|
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
|
||
|
}
|
||
|
for _, agg := range aggArray {
|
||
|
sr.Aggs = append(sr.Aggs, agg)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 initaite and returns a new aggregation builder
|
||
|
func (b *SearchRequestBuilder) Agg() AggBuilder {
|
||
|
aggBuilder := newAggBuilder()
|
||
|
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() *SearchRequestBuilder {
|
||
|
b := NewSearchRequestBuilder(m.version)
|
||
|
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
|
||
|
}
|
||
|
|
||
|
func newAggBuilder() *aggBuilderImpl {
|
||
|
return &aggBuilderImpl{
|
||
|
aggDefs: make([]*aggDef, 0),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
for _, childAgg := range childAggs {
|
||
|
agg.Aggregation.Aggs = append(agg.Aggregation.Aggs, childAgg)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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()
|
||
|
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()
|
||
|
aggDef.builders = append(aggDef.builders, builder)
|
||
|
fn(innerAgg, builder)
|
||
|
}
|
||
|
|
||
|
b.aggDefs = append(b.aggDefs, aggDef)
|
||
|
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
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()
|
||
|
aggDef.builders = append(aggDef.builders, builder)
|
||
|
fn(innerAgg, builder)
|
||
|
}
|
||
|
|
||
|
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()
|
||
|
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()
|
||
|
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
|
||
|
}
|