nikkiing 2 years ago
parent 9ed53c342a
commit 2ac6c072ee
  1. 9
      pkg/es/README.md
  2. 13
      pkg/es/query.go
  3. 160
      pkg/es/script.go
  4. 16
      pkg/es/search_aggs.go
  5. 422
      pkg/es/search_aggs_bucket_terms.go
  6. 112
      pkg/es/search_aggs_metrics_avg.go
  7. 127
      pkg/es/search_aggs_metrics_cardinality.go
  8. 108
      pkg/es/search_aggs_metrics_max.go
  9. 109
      pkg/es/search_aggs_metrics_min.go
  10. 203
      pkg/es/search_queries_bool.go
  11. 189
      pkg/es/search_queries_match.go
  12. 89
      pkg/es/search_queries_match_phrase.go
  13. 89
      pkg/es/search_queries_match_phrase_prefix.go
  14. 76
      pkg/es/search_queries_prefix.go
  15. 350
      pkg/es/search_queries_query_string.go
  16. 155
      pkg/es/search_queries_range.go
  17. 213
      pkg/es/search_queries_rank_feature.go
  18. 27
      pkg/es/search_queries_raw_string.go
  19. 91
      pkg/es/search_queries_regexp.go
  20. 51
      pkg/es/search_queries_script.go
  21. 110
      pkg/es/search_queries_script_score.go
  22. 53
      pkg/es/search_queries_slice.go
  23. 67
      pkg/es/search_queries_term.go
  24. 88
      pkg/es/search_queries_terms.go
  25. 76
      pkg/es/search_terms_lookup.go

@ -0,0 +1,9 @@
### es
> 复制 gitea.drugeyes.vip/pharnexcloud/elastic/v7 的构建es查询参数的代码
> 方便构造 github.com/elastic/go-elasticsearch/v7 查询语句

@ -0,0 +1,13 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// Query represents the generic query interface. A query's sole purpose
// is to return the source of the query as a JSON-serializable object.
// Returning map[string]interface{} is the norm for queries.
type Query interface {
// Source returns the JSON-serializable query request.
Source() (interface{}, error)
}

@ -0,0 +1,160 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
import (
"encoding/json"
"errors"
"fmt"
"strings"
)
// Script holds all the parameters necessary to compile or find in cache
// and then execute a script.
//
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/modules-scripting.html
// for details of scripting.
type Script struct {
script string
typ string
lang string
params map[string]interface{}
}
// NewScript creates and initializes a new Script. By default, it is of
// type "inline". Use NewScriptStored for a stored script (where type is "id").
func NewScript(script string) *Script {
return &Script{
script: script,
typ: "inline",
params: make(map[string]interface{}),
}
}
// NewScriptInline creates and initializes a new inline script, i.e. code.
func NewScriptInline(script string) *Script {
return NewScript(script).Type("inline")
}
// NewScriptStored creates and initializes a new stored script.
func NewScriptStored(script string) *Script {
return NewScript(script).Type("id")
}
// Script is either the cache key of the script to be compiled/executed
// or the actual script source code for inline scripts. For indexed
// scripts this is the id used in the request. For file scripts this is
// the file name.
func (s *Script) Script(script string) *Script {
s.script = script
return s
}
// Type sets the type of script: "inline" or "id".
func (s *Script) Type(typ string) *Script {
s.typ = typ
return s
}
// Lang sets the language of the script. The default scripting language
// is Painless ("painless").
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/modules-scripting.html
// for details.
func (s *Script) Lang(lang string) *Script {
s.lang = lang
return s
}
// Param adds a key/value pair to the parameters that this script will be executed with.
func (s *Script) Param(name string, value interface{}) *Script {
if s.params == nil {
s.params = make(map[string]interface{})
}
s.params[name] = value
return s
}
// Params sets the map of parameters this script will be executed with.
func (s *Script) Params(params map[string]interface{}) *Script {
s.params = params
return s
}
// Source returns the JSON serializable data for this Script.
func (s *Script) Source() (interface{}, error) {
if s.typ == "" && s.lang == "" && len(s.params) == 0 {
return s.script, nil
}
source := make(map[string]interface{})
// Beginning with 6.0, the type can only be "source" or "id"
if s.typ == "" || s.typ == "inline" {
src, err := s.rawScriptSource(s.script)
if err != nil {
return nil, err
}
source["source"] = src
} else {
source["id"] = s.script
}
if s.lang != "" {
source["lang"] = s.lang
}
if len(s.params) > 0 {
source["params"] = s.params
}
return source, nil
}
// rawScriptSource returns an embeddable script. If it uses a short
// script form, e.g. "ctx._source.likes++" (without the quotes), it
// is quoted. Otherwise it returns the raw script that will be directly
// embedded into the JSON data.
func (s *Script) rawScriptSource(script string) (interface{}, error) {
v := strings.TrimSpace(script)
if !strings.HasPrefix(v, "{") && !strings.HasPrefix(v, `"`) {
v = fmt.Sprintf("%q", v)
}
raw := json.RawMessage(v)
return &raw, nil
}
// -- Script Field --
// ScriptField is a single script field.
type ScriptField struct {
FieldName string // name of the field
script *Script
ignoreFailure *bool // used in e.g. ScriptSource
}
// NewScriptField creates and initializes a new ScriptField.
func NewScriptField(fieldName string, script *Script) *ScriptField {
return &ScriptField{FieldName: fieldName, script: script}
}
// IgnoreFailure indicates whether to ignore failures. It is used
// in e.g. ScriptSource.
func (f *ScriptField) IgnoreFailure(ignore bool) *ScriptField {
f.ignoreFailure = &ignore
return f
}
// Source returns the serializable JSON for the ScriptField.
func (f *ScriptField) Source() (interface{}, error) {
if f.script == nil {
return nil, errors.New("ScriptField expects script")
}
source := make(map[string]interface{})
src, err := f.script.Source()
if err != nil {
return nil, err
}
source["script"] = src
if v := f.ignoreFailure; v != nil {
source["ignore_failure"] = *v
}
return source, nil
}

@ -0,0 +1,16 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// Aggregations can be seen as a unit-of-work that build
// analytic information over a set of documents. It is
// (in many senses) the follow-up of facets in Elasticsearch.
// For more details about aggregations, visit:
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-aggregations.html
type Aggregation interface {
// Source returns a JSON-serializable aggregation that is a fragment
// of the request sent to Elasticsearch.
Source() (interface{}, error)
}

@ -0,0 +1,422 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
import "fmt"
// TermsAggregation is a multi-bucket value source based aggregation
// where buckets are dynamically built - one per unique value.
//
// See: http://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-aggregations-bucket-terms-aggregation.html
type TermsAggregation struct {
field string
script *Script
missing interface{}
subAggregations map[string]Aggregation
meta map[string]interface{}
size *int
shardSize *int
requiredSize *int
minDocCount *int
shardMinDocCount *int
valueType string
includeExclude *TermsAggregationIncludeExclude
executionHint string
collectionMode string
showTermDocCountError *bool
order []TermsOrder
}
func NewTermsAggregation() *TermsAggregation {
return &TermsAggregation{
subAggregations: make(map[string]Aggregation),
}
}
func (a *TermsAggregation) Field(field string) *TermsAggregation {
a.field = field
return a
}
func (a *TermsAggregation) Script(script *Script) *TermsAggregation {
a.script = script
return a
}
// Missing configures the value to use when documents miss a value.
func (a *TermsAggregation) Missing(missing interface{}) *TermsAggregation {
a.missing = missing
return a
}
func (a *TermsAggregation) SubAggregation(name string, subAggregation Aggregation) *TermsAggregation {
a.subAggregations[name] = subAggregation
return a
}
// Meta sets the meta data to be included in the aggregation response.
func (a *TermsAggregation) Meta(metaData map[string]interface{}) *TermsAggregation {
a.meta = metaData
return a
}
func (a *TermsAggregation) Size(size int) *TermsAggregation {
a.size = &size
return a
}
func (a *TermsAggregation) RequiredSize(requiredSize int) *TermsAggregation {
a.requiredSize = &requiredSize
return a
}
func (a *TermsAggregation) ShardSize(shardSize int) *TermsAggregation {
a.shardSize = &shardSize
return a
}
func (a *TermsAggregation) MinDocCount(minDocCount int) *TermsAggregation {
a.minDocCount = &minDocCount
return a
}
func (a *TermsAggregation) ShardMinDocCount(shardMinDocCount int) *TermsAggregation {
a.shardMinDocCount = &shardMinDocCount
return a
}
func (a *TermsAggregation) Include(regexp string) *TermsAggregation {
if a.includeExclude == nil {
a.includeExclude = &TermsAggregationIncludeExclude{}
}
a.includeExclude.Include = regexp
return a
}
func (a *TermsAggregation) IncludeValues(values ...interface{}) *TermsAggregation {
if a.includeExclude == nil {
a.includeExclude = &TermsAggregationIncludeExclude{}
}
a.includeExclude.IncludeValues = append(a.includeExclude.IncludeValues, values...)
return a
}
func (a *TermsAggregation) Exclude(regexp string) *TermsAggregation {
if a.includeExclude == nil {
a.includeExclude = &TermsAggregationIncludeExclude{}
}
a.includeExclude.Exclude = regexp
return a
}
func (a *TermsAggregation) ExcludeValues(values ...interface{}) *TermsAggregation {
if a.includeExclude == nil {
a.includeExclude = &TermsAggregationIncludeExclude{}
}
a.includeExclude.ExcludeValues = append(a.includeExclude.ExcludeValues, values...)
return a
}
func (a *TermsAggregation) Partition(p int) *TermsAggregation {
if a.includeExclude == nil {
a.includeExclude = &TermsAggregationIncludeExclude{}
}
a.includeExclude.Partition = p
return a
}
func (a *TermsAggregation) NumPartitions(n int) *TermsAggregation {
if a.includeExclude == nil {
a.includeExclude = &TermsAggregationIncludeExclude{}
}
a.includeExclude.NumPartitions = n
return a
}
func (a *TermsAggregation) IncludeExclude(includeExclude *TermsAggregationIncludeExclude) *TermsAggregation {
a.includeExclude = includeExclude
return a
}
// ValueType can be string, long, or double.
func (a *TermsAggregation) ValueType(valueType string) *TermsAggregation {
a.valueType = valueType
return a
}
func (a *TermsAggregation) Order(order string, asc bool) *TermsAggregation {
a.order = append(a.order, TermsOrder{Field: order, Ascending: asc})
return a
}
func (a *TermsAggregation) OrderByCount(asc bool) *TermsAggregation {
// "order" : { "_count" : "asc" }
a.order = append(a.order, TermsOrder{Field: "_count", Ascending: asc})
return a
}
func (a *TermsAggregation) OrderByCountAsc() *TermsAggregation {
return a.OrderByCount(true)
}
func (a *TermsAggregation) OrderByCountDesc() *TermsAggregation {
return a.OrderByCount(false)
}
// Deprecated: Use OrderByKey instead.
func (a *TermsAggregation) OrderByTerm(asc bool) *TermsAggregation {
// "order" : { "_term" : "asc" }
a.order = append(a.order, TermsOrder{Field: "_term", Ascending: asc})
return a
}
// Deprecated: Use OrderByKeyAsc instead.
func (a *TermsAggregation) OrderByTermAsc() *TermsAggregation {
return a.OrderByTerm(true)
}
// Deprecated: Use OrderByKeyDesc instead.
func (a *TermsAggregation) OrderByTermDesc() *TermsAggregation {
return a.OrderByTerm(false)
}
func (a *TermsAggregation) OrderByKey(asc bool) *TermsAggregation {
// "order" : { "_term" : "asc" }
a.order = append(a.order, TermsOrder{Field: "_key", Ascending: asc})
return a
}
func (a *TermsAggregation) OrderByKeyAsc() *TermsAggregation {
return a.OrderByKey(true)
}
func (a *TermsAggregation) OrderByKeyDesc() *TermsAggregation {
return a.OrderByKey(false)
}
// OrderByAggregation creates a bucket ordering strategy which sorts buckets
// based on a single-valued calc get.
func (a *TermsAggregation) OrderByAggregation(aggName string, asc bool) *TermsAggregation {
// {
// "aggs" : {
// "genders" : {
// "terms" : {
// "field" : "gender",
// "order" : { "avg_height" : "desc" }
// },
// "aggs" : {
// "avg_height" : { "avg" : { "field" : "height" } }
// }
// }
// }
// }
a.order = append(a.order, TermsOrder{Field: aggName, Ascending: asc})
return a
}
// OrderByAggregationAndMetric creates a bucket ordering strategy which
// sorts buckets based on a multi-valued calc get.
func (a *TermsAggregation) OrderByAggregationAndMetric(aggName, metric string, asc bool) *TermsAggregation {
// {
// "aggs" : {
// "genders" : {
// "terms" : {
// "field" : "gender",
// "order" : { "height_stats.avg" : "desc" }
// },
// "aggs" : {
// "height_stats" : { "stats" : { "field" : "height" } }
// }
// }
// }
// }
a.order = append(a.order, TermsOrder{Field: aggName + "." + metric, Ascending: asc})
return a
}
func (a *TermsAggregation) ExecutionHint(hint string) *TermsAggregation {
a.executionHint = hint
return a
}
// Collection mode can be depth_first or breadth_first as of 1.4.0.
func (a *TermsAggregation) CollectionMode(collectionMode string) *TermsAggregation {
a.collectionMode = collectionMode
return a
}
func (a *TermsAggregation) ShowTermDocCountError(showTermDocCountError bool) *TermsAggregation {
a.showTermDocCountError = &showTermDocCountError
return a
}
func (a *TermsAggregation) Source() (interface{}, error) {
// Example:
// {
// "aggs" : {
// "genders" : {
// "terms" : { "field" : "gender" }
// }
// }
// }
// This method returns only the { "terms" : { "field" : "gender" } } part.
source := make(map[string]interface{})
opts := make(map[string]interface{})
source["terms"] = opts
// ValuesSourceAggregationBuilder
if a.field != "" {
opts["field"] = a.field
}
if a.script != nil {
src, err := a.script.Source()
if err != nil {
return nil, err
}
opts["script"] = src
}
if a.missing != nil {
opts["missing"] = a.missing
}
// TermsBuilder
if a.size != nil && *a.size >= 0 {
opts["size"] = *a.size
}
if a.shardSize != nil && *a.shardSize >= 0 {
opts["shard_size"] = *a.shardSize
}
if a.requiredSize != nil && *a.requiredSize >= 0 {
opts["required_size"] = *a.requiredSize
}
if a.minDocCount != nil && *a.minDocCount >= 0 {
opts["min_doc_count"] = *a.minDocCount
}
if a.shardMinDocCount != nil && *a.shardMinDocCount >= 0 {
opts["shard_min_doc_count"] = *a.shardMinDocCount
}
if a.showTermDocCountError != nil {
opts["show_term_doc_count_error"] = *a.showTermDocCountError
}
if a.collectionMode != "" {
opts["collect_mode"] = a.collectionMode
}
if a.valueType != "" {
opts["value_type"] = a.valueType
}
if len(a.order) > 0 {
var orderSlice []interface{}
for _, order := range a.order {
src, err := order.Source()
if err != nil {
return nil, err
}
orderSlice = append(orderSlice, src)
}
opts["order"] = orderSlice
}
// Include/Exclude
if ie := a.includeExclude; ie != nil {
if err := ie.MergeInto(opts); err != nil {
return nil, err
}
}
if a.executionHint != "" {
opts["execution_hint"] = a.executionHint
}
// AggregationBuilder (SubAggregations)
if len(a.subAggregations) > 0 {
aggsMap := make(map[string]interface{})
source["aggregations"] = aggsMap
for name, aggregate := range a.subAggregations {
src, err := aggregate.Source()
if err != nil {
return nil, err
}
aggsMap[name] = src
}
}
// Add Meta data if available
if len(a.meta) > 0 {
source["meta"] = a.meta
}
return source, nil
}
// TermsAggregationIncludeExclude allows for include/exclude in a TermsAggregation.
type TermsAggregationIncludeExclude struct {
Include string
Exclude string
IncludeValues []interface{}
ExcludeValues []interface{}
Partition int
NumPartitions int
}
// Source returns a JSON serializable struct.
func (ie *TermsAggregationIncludeExclude) Source() (interface{}, error) {
source := make(map[string]interface{})
// Include
if ie.Include != "" {
source["include"] = ie.Include
} else if len(ie.IncludeValues) > 0 {
source["include"] = ie.IncludeValues
} else if ie.NumPartitions > 0 {
inc := make(map[string]interface{})
inc["partition"] = ie.Partition
inc["num_partitions"] = ie.NumPartitions
source["include"] = inc
}
// Exclude
if ie.Exclude != "" {
source["exclude"] = ie.Exclude
} else if len(ie.ExcludeValues) > 0 {
source["exclude"] = ie.ExcludeValues
}
return source, nil
}
// MergeInto merges the values of the include/exclude options into source.
func (ie *TermsAggregationIncludeExclude) MergeInto(source map[string]interface{}) error {
values, err := ie.Source()
if err != nil {
return err
}
mv, ok := values.(map[string]interface{})
if !ok {
return fmt.Errorf("IncludeExclude: expected a map[string]interface{}, got %T", values)
}
for k, v := range mv {
source[k] = v
}
return nil
}
// TermsOrder specifies a single order field for a terms aggregation.
type TermsOrder struct {
Field string
Ascending bool
}
// Source returns serializable JSON of the TermsOrder.
func (order *TermsOrder) Source() (interface{}, error) {
source := make(map[string]string)
if order.Ascending {
source[order.Field] = "asc"
} else {
source[order.Field] = "desc"
}
return source, nil
}

@ -0,0 +1,112 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// AvgAggregation is a single-value metrics aggregation that computes
// the average of numeric values that are extracted from the
// aggregated documents. These values can be extracted either from
// specific numeric fields in the documents, or be generated by
// a provided script.
//
// See: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-aggregations-metrics-avg-aggregation.html
type AvgAggregation struct {
field string
script *Script
format string
missing interface{}
subAggregations map[string]Aggregation
meta map[string]interface{}
}
func NewAvgAggregation() *AvgAggregation {
return &AvgAggregation{
subAggregations: make(map[string]Aggregation),
}
}
func (a *AvgAggregation) Field(field string) *AvgAggregation {
a.field = field
return a
}
func (a *AvgAggregation) Script(script *Script) *AvgAggregation {
a.script = script
return a
}
func (a *AvgAggregation) Format(format string) *AvgAggregation {
a.format = format
return a
}
func (a *AvgAggregation) Missing(missing interface{}) *AvgAggregation {
a.missing = missing
return a
}
func (a *AvgAggregation) SubAggregation(name string, subAggregation Aggregation) *AvgAggregation {
a.subAggregations[name] = subAggregation
return a
}
// Meta sets the meta data to be included in the aggregation response.
func (a *AvgAggregation) Meta(metaData map[string]interface{}) *AvgAggregation {
a.meta = metaData
return a
}
func (a *AvgAggregation) Source() (interface{}, error) {
// Example:
// {
// "aggs" : {
// "avg_grade" : { "avg" : { "field" : "grade" } }
// }
// }
// This method returns only the { "avg" : { "field" : "grade" } } part.
source := make(map[string]interface{})
opts := make(map[string]interface{})
source["avg"] = opts
// ValuesSourceAggregationBuilder
if a.field != "" {
opts["field"] = a.field
}
if a.script != nil {
src, err := a.script.Source()
if err != nil {
return nil, err
}
opts["script"] = src
}
if a.format != "" {
opts["format"] = a.format
}
if a.missing != nil {
opts["missing"] = a.missing
}
// AggregationBuilder (SubAggregations)
if len(a.subAggregations) > 0 {
aggsMap := make(map[string]interface{})
source["aggregations"] = aggsMap
for name, aggregate := range a.subAggregations {
src, err := aggregate.Source()
if err != nil {
return nil, err
}
aggsMap[name] = src
}
}
// Add Meta data if available
if len(a.meta) > 0 {
source["meta"] = a.meta
}
return source, nil
}

@ -0,0 +1,127 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// CardinalityAggregation is a single-value metrics aggregation that
// calculates an approximate count of distinct values.
// Values can be extracted either from specific fields in the document
// or generated by a script.
// See: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-aggregations-metrics-cardinality-aggregation.html
type CardinalityAggregation struct {
field string
script *Script
format string
missing interface{}
subAggregations map[string]Aggregation
meta map[string]interface{}
precisionThreshold *int64
rehash *bool
}
func NewCardinalityAggregation() *CardinalityAggregation {
return &CardinalityAggregation{
subAggregations: make(map[string]Aggregation),
}
}
func (a *CardinalityAggregation) Field(field string) *CardinalityAggregation {
a.field = field
return a
}
func (a *CardinalityAggregation) Script(script *Script) *CardinalityAggregation {
a.script = script
return a
}
func (a *CardinalityAggregation) Format(format string) *CardinalityAggregation {
a.format = format
return a
}
func (a *CardinalityAggregation) Missing(missing interface{}) *CardinalityAggregation {
a.missing = missing
return a
}
func (a *CardinalityAggregation) SubAggregation(name string, subAggregation Aggregation) *CardinalityAggregation {
a.subAggregations[name] = subAggregation
return a
}
// Meta sets the meta data to be included in the aggregation response.
func (a *CardinalityAggregation) Meta(metaData map[string]interface{}) *CardinalityAggregation {
a.meta = metaData
return a
}
func (a *CardinalityAggregation) PrecisionThreshold(threshold int64) *CardinalityAggregation {
a.precisionThreshold = &threshold
return a
}
func (a *CardinalityAggregation) Rehash(rehash bool) *CardinalityAggregation {
a.rehash = &rehash
return a
}
func (a *CardinalityAggregation) Source() (interface{}, error) {
// Example:
// {
// "aggs" : {
// "author_count" : {
// "cardinality" : { "field" : "author" }
// }
// }
// }
// This method returns only the "cardinality" : { "field" : "author" } part.
source := make(map[string]interface{})
opts := make(map[string]interface{})
source["cardinality"] = opts
// ValuesSourceAggregationBuilder
if a.field != "" {
opts["field"] = a.field
}
if a.script != nil {
src, err := a.script.Source()
if err != nil {
return nil, err
}
opts["script"] = src
}
if a.missing != nil {
opts["missing"] = a.missing
}
if a.format != "" {
opts["format"] = a.format
}
if a.precisionThreshold != nil {
opts["precision_threshold"] = *a.precisionThreshold
}
if a.rehash != nil {
opts["rehash"] = *a.rehash
}
// AggregationBuilder (SubAggregations)
if len(a.subAggregations) > 0 {
aggsMap := make(map[string]interface{})
source["aggregations"] = aggsMap
for name, aggregate := range a.subAggregations {
src, err := aggregate.Source()
if err != nil {
return nil, err
}
aggsMap[name] = src
}
}
// Add Meta data if available
if len(a.meta) > 0 {
source["meta"] = a.meta
}
return source, nil
}

@ -0,0 +1,108 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// MaxAggregation is a single-value metrics aggregation that keeps track and
// returns the maximum value among the numeric values extracted from
// the aggregated documents. These values can be extracted either from
// specific numeric fields in the documents, or be generated by
// a provided script.
// See: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-aggregations-metrics-max-aggregation.html
type MaxAggregation struct {
field string
script *Script
format string
missing interface{}
subAggregations map[string]Aggregation
meta map[string]interface{}
}
func NewMaxAggregation() *MaxAggregation {
return &MaxAggregation{
subAggregations: make(map[string]Aggregation),
}
}
func (a *MaxAggregation) Field(field string) *MaxAggregation {
a.field = field
return a
}
func (a *MaxAggregation) Script(script *Script) *MaxAggregation {
a.script = script
return a
}
func (a *MaxAggregation) Format(format string) *MaxAggregation {
a.format = format
return a
}
func (a *MaxAggregation) Missing(missing interface{}) *MaxAggregation {
a.missing = missing
return a
}
func (a *MaxAggregation) SubAggregation(name string, subAggregation Aggregation) *MaxAggregation {
a.subAggregations[name] = subAggregation
return a
}
// Meta sets the meta data to be included in the aggregation response.
func (a *MaxAggregation) Meta(metaData map[string]interface{}) *MaxAggregation {
a.meta = metaData
return a
}
func (a *MaxAggregation) Source() (interface{}, error) {
// Example:
// {
// "aggs" : {
// "max_price" : { "max" : { "field" : "price" } }
// }
// }
// This method returns only the { "max" : { "field" : "price" } } part.
source := make(map[string]interface{})
opts := make(map[string]interface{})
source["max"] = opts
// ValuesSourceAggregationBuilder
if a.field != "" {
opts["field"] = a.field
}
if a.script != nil {
src, err := a.script.Source()
if err != nil {
return nil, err
}
opts["script"] = src
}
if a.format != "" {
opts["format"] = a.format
}
if a.missing != nil {
opts["missing"] = a.missing
}
// AggregationBuilder (SubAggregations)
if len(a.subAggregations) > 0 {
aggsMap := make(map[string]interface{})
source["aggregations"] = aggsMap
for name, aggregate := range a.subAggregations {
src, err := aggregate.Source()
if err != nil {
return nil, err
}
aggsMap[name] = src
}
}
// Add Meta data if available
if len(a.meta) > 0 {
source["meta"] = a.meta
}
return source, nil
}

@ -0,0 +1,109 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// MinAggregation is a single-value metrics aggregation that keeps track and
// returns the minimum value among numeric values extracted from the
// aggregated documents. These values can be extracted either from
// specific numeric fields in the documents, or be generated by a
// provided script.
// See: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-aggregations-metrics-min-aggregation.html
type MinAggregation struct {
field string
script *Script
format string
missing interface{}
subAggregations map[string]Aggregation
meta map[string]interface{}
}
func NewMinAggregation() *MinAggregation {
return &MinAggregation{
subAggregations: make(map[string]Aggregation),
}
}
func (a *MinAggregation) Field(field string) *MinAggregation {
a.field = field
return a
}
func (a *MinAggregation) Script(script *Script) *MinAggregation {
a.script = script
return a
}
func (a *MinAggregation) Format(format string) *MinAggregation {
a.format = format
return a
}
func (a *MinAggregation) Missing(missing interface{}) *MinAggregation {
a.missing = missing
return a
}
func (a *MinAggregation) SubAggregation(name string, subAggregation Aggregation) *MinAggregation {
a.subAggregations[name] = subAggregation
return a
}
// Meta sets the meta data to be included in the aggregation response.
func (a *MinAggregation) Meta(metaData map[string]interface{}) *MinAggregation {
a.meta = metaData
return a
}
func (a *MinAggregation) Source() (interface{}, error) {
// Example:
// {
// "aggs" : {
// "min_price" : { "min" : { "field" : "price" } }
// }
// }
// This method returns only the { "min" : { "field" : "price" } } part.
source := make(map[string]interface{})
opts := make(map[string]interface{})
source["min"] = opts
// ValuesSourceAggregationBuilder
if a.field != "" {
opts["field"] = a.field
}
if a.script != nil {
src, err := a.script.Source()
if err != nil {
return nil, err
}
opts["script"] = src
}
if a.format != "" {
opts["format"] = a.format
}
if a.missing != nil {
opts["missing"] = a.missing
}
// AggregationBuilder (SubAggregations)
if len(a.subAggregations) > 0 {
aggsMap := make(map[string]interface{})
source["aggregations"] = aggsMap
for name, aggregate := range a.subAggregations {
src, err := aggregate.Source()
if err != nil {
return nil, err
}
aggsMap[name] = src
}
}
// Add Meta data if available
if len(a.meta) > 0 {
source["meta"] = a.meta
}
return source, nil
}

@ -0,0 +1,203 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
import "fmt"
// A bool query matches documents matching boolean
// combinations of other queries.
// For more details, see:
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-bool-query.html
type BoolQuery struct {
Query
mustClauses []Query
mustNotClauses []Query
filterClauses []Query
shouldClauses []Query
boost *float64
minimumShouldMatch string
adjustPureNegative *bool
queryName string
}
// Creates a new bool query.
func NewBoolQuery() *BoolQuery {
return &BoolQuery{
mustClauses: make([]Query, 0),
mustNotClauses: make([]Query, 0),
filterClauses: make([]Query, 0),
shouldClauses: make([]Query, 0),
}
}
func (q *BoolQuery) Must(queries ...Query) *BoolQuery {
q.mustClauses = append(q.mustClauses, queries...)
return q
}
func (q *BoolQuery) MustNot(queries ...Query) *BoolQuery {
q.mustNotClauses = append(q.mustNotClauses, queries...)
return q
}
func (q *BoolQuery) Filter(filters ...Query) *BoolQuery {
q.filterClauses = append(q.filterClauses, filters...)
return q
}
func (q *BoolQuery) Should(queries ...Query) *BoolQuery {
q.shouldClauses = append(q.shouldClauses, queries...)
return q
}
func (q *BoolQuery) Boost(boost float64) *BoolQuery {
q.boost = &boost
return q
}
func (q *BoolQuery) MinimumShouldMatch(minimumShouldMatch string) *BoolQuery {
q.minimumShouldMatch = minimumShouldMatch
return q
}
func (q *BoolQuery) MinimumNumberShouldMatch(minimumNumberShouldMatch int) *BoolQuery {
q.minimumShouldMatch = fmt.Sprintf("%d", minimumNumberShouldMatch)
return q
}
func (q *BoolQuery) AdjustPureNegative(adjustPureNegative bool) *BoolQuery {
q.adjustPureNegative = &adjustPureNegative
return q
}
func (q *BoolQuery) QueryName(queryName string) *BoolQuery {
q.queryName = queryName
return q
}
// Creates the query source for the bool query.
func (q *BoolQuery) Source() (interface{}, error) {
// {
// "bool" : {
// "must" : {
// "term" : { "user" : "kimchy" }
// },
// "must_not" : {
// "range" : {
// "age" : { "from" : 10, "to" : 20 }
// }
// },
// "filter" : [
// ...
// ]
// "should" : [
// {
// "term" : { "tag" : "wow" }
// },
// {
// "term" : { "tag" : "elasticsearch" }
// }
// ],
// "minimum_should_match" : 1,
// "boost" : 1.0
// }
// }
query := make(map[string]interface{})
boolClause := make(map[string]interface{})
query["bool"] = boolClause
// must
if len(q.mustClauses) == 1 {
src, err := q.mustClauses[0].Source()
if err != nil {
return nil, err
}
boolClause["must"] = src
} else if len(q.mustClauses) > 1 {
var clauses []interface{}
for _, subQuery := range q.mustClauses {
src, err := subQuery.Source()
if err != nil {
return nil, err
}
clauses = append(clauses, src)
}
boolClause["must"] = clauses
}
// must_not
if len(q.mustNotClauses) == 1 {
src, err := q.mustNotClauses[0].Source()
if err != nil {
return nil, err
}
boolClause["must_not"] = src
} else if len(q.mustNotClauses) > 1 {
var clauses []interface{}
for _, subQuery := range q.mustNotClauses {
src, err := subQuery.Source()
if err != nil {
return nil, err
}
clauses = append(clauses, src)
}
boolClause["must_not"] = clauses
}
// filter
if len(q.filterClauses) == 1 {
src, err := q.filterClauses[0].Source()
if err != nil {
return nil, err
}
boolClause["filter"] = src
} else if len(q.filterClauses) > 1 {
var clauses []interface{}
for _, subQuery := range q.filterClauses {
src, err := subQuery.Source()
if err != nil {
return nil, err
}
clauses = append(clauses, src)
}
boolClause["filter"] = clauses
}
// should
if len(q.shouldClauses) == 1 {
src, err := q.shouldClauses[0].Source()
if err != nil {
return nil, err
}
boolClause["should"] = src
} else if len(q.shouldClauses) > 1 {
var clauses []interface{}
for _, subQuery := range q.shouldClauses {
src, err := subQuery.Source()
if err != nil {
return nil, err
}
clauses = append(clauses, src)
}
boolClause["should"] = clauses
}
if q.boost != nil {
boolClause["boost"] = *q.boost
}
if q.minimumShouldMatch != "" {
boolClause["minimum_should_match"] = q.minimumShouldMatch
}
if q.adjustPureNegative != nil {
boolClause["adjust_pure_negative"] = *q.adjustPureNegative
}
if q.queryName != "" {
boolClause["_name"] = q.queryName
}
return query, nil
}

@ -0,0 +1,189 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// MatchQuery is a family of queries that accepts text/numerics/dates,
// analyzes them, and constructs a query.
//
// To create a new MatchQuery, use NewMatchQuery. To create specific types
// of queries, e.g. a match_phrase query, use NewMatchPhrQuery(...).Type("phrase"),
// or use one of the shortcuts e.g. NewMatchPhraseQuery(...).
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-match-query.html
type MatchQuery struct {
name string
text interface{}
operator string // or / and
analyzer string
boost *float64
fuzziness string
prefixLength *int
maxExpansions *int
minimumShouldMatch string
fuzzyRewrite string
lenient *bool
fuzzyTranspositions *bool
zeroTermsQuery string
cutoffFrequency *float64
queryName string
}
// NewMatchQuery creates and initializes a new MatchQuery.
func NewMatchQuery(name string, text interface{}) *MatchQuery {
return &MatchQuery{name: name, text: text}
}
// Operator sets the operator to use when using a boolean query.
// Can be "AND" or "OR" (default).
func (q *MatchQuery) Operator(operator string) *MatchQuery {
q.operator = operator
return q
}
// Analyzer explicitly sets the analyzer to use. It defaults to use explicit
// mapping config for the field, or, if not set, the default search analyzer.
func (q *MatchQuery) Analyzer(analyzer string) *MatchQuery {
q.analyzer = analyzer
return q
}
// Fuzziness sets the fuzziness when evaluated to a fuzzy query type.
// Defaults to "AUTO".
func (q *MatchQuery) Fuzziness(fuzziness string) *MatchQuery {
q.fuzziness = fuzziness
return q
}
// PrefixLength sets the length of a length of common (non-fuzzy)
// prefix for fuzzy match queries. It must be non-negative.
func (q *MatchQuery) PrefixLength(prefixLength int) *MatchQuery {
q.prefixLength = &prefixLength
return q
}
// MaxExpansions is used with fuzzy or prefix type queries. It specifies
// the number of term expansions to use. It defaults to unbounded so that
// its recommended to set it to a reasonable value for faster execution.
func (q *MatchQuery) MaxExpansions(maxExpansions int) *MatchQuery {
q.maxExpansions = &maxExpansions
return q
}
// CutoffFrequency can be a value in [0..1] (or an absolute number >=1).
// It represents the maximum treshold of a terms document frequency to be
// considered a low frequency term.
func (q *MatchQuery) CutoffFrequency(cutoff float64) *MatchQuery {
q.cutoffFrequency = &cutoff
return q
}
// MinimumShouldMatch sets the optional minimumShouldMatch value to
// apply to the query.
func (q *MatchQuery) MinimumShouldMatch(minimumShouldMatch string) *MatchQuery {
q.minimumShouldMatch = minimumShouldMatch
return q
}
// FuzzyRewrite sets the fuzzy_rewrite parameter controlling how the
// fuzzy query will get rewritten.
func (q *MatchQuery) FuzzyRewrite(fuzzyRewrite string) *MatchQuery {
q.fuzzyRewrite = fuzzyRewrite
return q
}
// FuzzyTranspositions sets whether transpositions are supported in
// fuzzy queries.
//
// The default metric used by fuzzy queries to determine a match is
// the Damerau-Levenshtein distance formula which supports transpositions.
// Setting transposition to false will
// * switch to classic Levenshtein distance.
// * If not set, Damerau-Levenshtein distance metric will be used.
func (q *MatchQuery) FuzzyTranspositions(fuzzyTranspositions bool) *MatchQuery {
q.fuzzyTranspositions = &fuzzyTranspositions
return q
}
// Lenient specifies whether format based failures will be ignored.
func (q *MatchQuery) Lenient(lenient bool) *MatchQuery {
q.lenient = &lenient
return q
}
// ZeroTermsQuery can be "all" or "none".
func (q *MatchQuery) ZeroTermsQuery(zeroTermsQuery string) *MatchQuery {
q.zeroTermsQuery = zeroTermsQuery
return q
}
// Boost sets the boost to apply to this query.
func (q *MatchQuery) Boost(boost float64) *MatchQuery {
q.boost = &boost
return q
}
// QueryName sets the query name for the filter that can be used when
// searching for matched filters per hit.
func (q *MatchQuery) QueryName(queryName string) *MatchQuery {
q.queryName = queryName
return q
}
// Source returns JSON for the function score query.
func (q *MatchQuery) Source() (interface{}, error) {
// {"match":{"name":{"query":"value","type":"boolean/phrase"}}}
source := make(map[string]interface{})
match := make(map[string]interface{})
source["match"] = match
query := make(map[string]interface{})
match[q.name] = query
query["query"] = q.text
if q.operator != "" {
query["operator"] = q.operator
}
if q.analyzer != "" {
query["analyzer"] = q.analyzer
}
if q.fuzziness != "" {
query["fuzziness"] = q.fuzziness
}
if q.prefixLength != nil {
query["prefix_length"] = *q.prefixLength
}
if q.maxExpansions != nil {
query["max_expansions"] = *q.maxExpansions
}
if q.minimumShouldMatch != "" {
query["minimum_should_match"] = q.minimumShouldMatch
}
if q.fuzzyRewrite != "" {
query["fuzzy_rewrite"] = q.fuzzyRewrite
}
if q.lenient != nil {
query["lenient"] = *q.lenient
}
if q.fuzzyTranspositions != nil {
query["fuzzy_transpositions"] = *q.fuzzyTranspositions
}
if q.zeroTermsQuery != "" {
query["zero_terms_query"] = q.zeroTermsQuery
}
if q.cutoffFrequency != nil {
query["cutoff_frequency"] = *q.cutoffFrequency
}
if q.boost != nil {
query["boost"] = *q.boost
}
if q.queryName != "" {
query["_name"] = q.queryName
}
return source, nil
}

@ -0,0 +1,89 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// MatchPhraseQuery analyzes the text and creates a phrase query out of
// the analyzed text.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-match-query-phrase.html
type MatchPhraseQuery struct {
name string
value interface{}
analyzer string
slop *int
boost *float64
queryName string
zeroTermsQuery string
}
// NewMatchPhraseQuery creates and initializes a new MatchPhraseQuery.
func NewMatchPhraseQuery(name string, value interface{}) *MatchPhraseQuery {
return &MatchPhraseQuery{name: name, value: value}
}
// Analyzer explicitly sets the analyzer to use. It defaults to use explicit
// mapping config for the field, or, if not set, the default search analyzer.
func (q *MatchPhraseQuery) Analyzer(analyzer string) *MatchPhraseQuery {
q.analyzer = analyzer
return q
}
// Slop sets the phrase slop if evaluated to a phrase query type.
func (q *MatchPhraseQuery) Slop(slop int) *MatchPhraseQuery {
q.slop = &slop
return q
}
// ZeroTermsQuery can be "all" or "none".
func (q *MatchPhraseQuery) ZeroTermsQuery(zeroTermsQuery string) *MatchPhraseQuery {
q.zeroTermsQuery = zeroTermsQuery
return q
}
// Boost sets the boost to apply to this query.
func (q *MatchPhraseQuery) Boost(boost float64) *MatchPhraseQuery {
q.boost = &boost
return q
}
// QueryName sets the query name for the filter that can be used when
// searching for matched filters per hit.
func (q *MatchPhraseQuery) QueryName(queryName string) *MatchPhraseQuery {
q.queryName = queryName
return q
}
// Source returns JSON for the function score query.
func (q *MatchPhraseQuery) Source() (interface{}, error) {
// {"match_phrase":{"name":{"query":"value","analyzer":"my_analyzer"}}}
source := make(map[string]interface{})
match := make(map[string]interface{})
source["match_phrase"] = match
query := make(map[string]interface{})
match[q.name] = query
query["query"] = q.value
if q.analyzer != "" {
query["analyzer"] = q.analyzer
}
if q.slop != nil {
query["slop"] = *q.slop
}
if q.zeroTermsQuery != "" {
query["zero_terms_query"] = q.zeroTermsQuery
}
if q.boost != nil {
query["boost"] = *q.boost
}
if q.queryName != "" {
query["_name"] = q.queryName
}
return source, nil
}

@ -0,0 +1,89 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// MatchPhrasePrefixQuery is the same as match_phrase, except that it allows for
// prefix matches on the last term in the text.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-match-query-phrase-prefix.html
type MatchPhrasePrefixQuery struct {
name string
value interface{}
analyzer string
slop *int
maxExpansions *int
boost *float64
queryName string
}
// NewMatchPhrasePrefixQuery creates and initializes a new MatchPhrasePrefixQuery.
func NewMatchPhrasePrefixQuery(name string, value interface{}) *MatchPhrasePrefixQuery {
return &MatchPhrasePrefixQuery{name: name, value: value}
}
// Analyzer explicitly sets the analyzer to use. It defaults to use explicit
// mapping config for the field, or, if not set, the default search analyzer.
func (q *MatchPhrasePrefixQuery) Analyzer(analyzer string) *MatchPhrasePrefixQuery {
q.analyzer = analyzer
return q
}
// Slop sets the phrase slop if evaluated to a phrase query type.
func (q *MatchPhrasePrefixQuery) Slop(slop int) *MatchPhrasePrefixQuery {
q.slop = &slop
return q
}
// MaxExpansions sets the number of term expansions to use.
func (q *MatchPhrasePrefixQuery) MaxExpansions(n int) *MatchPhrasePrefixQuery {
q.maxExpansions = &n
return q
}
// Boost sets the boost to apply to this query.
func (q *MatchPhrasePrefixQuery) Boost(boost float64) *MatchPhrasePrefixQuery {
q.boost = &boost
return q
}
// QueryName sets the query name for the filter that can be used when
// searching for matched filters per hit.
func (q *MatchPhrasePrefixQuery) QueryName(queryName string) *MatchPhrasePrefixQuery {
q.queryName = queryName
return q
}
// Source returns JSON for the function score query.
func (q *MatchPhrasePrefixQuery) Source() (interface{}, error) {
// {"match_phrase_prefix":{"name":{"query":"value","max_expansions":10}}}
source := make(map[string]interface{})
match := make(map[string]interface{})
source["match_phrase_prefix"] = match
query := make(map[string]interface{})
match[q.name] = query
query["query"] = q.value
if q.analyzer != "" {
query["analyzer"] = q.analyzer
}
if q.slop != nil {
query["slop"] = *q.slop
}
if q.maxExpansions != nil {
query["max_expansions"] = *q.maxExpansions
}
if q.boost != nil {
query["boost"] = *q.boost
}
if q.queryName != "" {
query["_name"] = q.queryName
}
return source, nil
}

@ -0,0 +1,76 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// PrefixQuery matches documents that have fields containing terms
// with a specified prefix (not analyzed).
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-prefix-query.html
type PrefixQuery struct {
name string
prefix string
boost *float64
rewrite string
caseInsensitive *bool
queryName string
}
// NewPrefixQuery creates and initializes a new PrefixQuery.
func NewPrefixQuery(name string, prefix string) *PrefixQuery {
return &PrefixQuery{name: name, prefix: prefix}
}
// Boost sets the boost for this query.
func (q *PrefixQuery) Boost(boost float64) *PrefixQuery {
q.boost = &boost
return q
}
func (q *PrefixQuery) Rewrite(rewrite string) *PrefixQuery {
q.rewrite = rewrite
return q
}
func (q *PrefixQuery) CaseInsensitive(caseInsensitive bool) *PrefixQuery {
q.caseInsensitive = &caseInsensitive
return q
}
// QueryName sets the query name for the filter that can be used when
// searching for matched_filters per hit.
func (q *PrefixQuery) QueryName(queryName string) *PrefixQuery {
q.queryName = queryName
return q
}
// Source returns JSON for the query.
func (q *PrefixQuery) Source() (interface{}, error) {
source := make(map[string]interface{})
query := make(map[string]interface{})
source["prefix"] = query
if q.boost == nil && q.rewrite == "" && q.queryName == "" && q.caseInsensitive == nil {
query[q.name] = q.prefix
} else {
subQuery := make(map[string]interface{})
subQuery["value"] = q.prefix
if q.boost != nil {
subQuery["boost"] = *q.boost
}
if q.rewrite != "" {
subQuery["rewrite"] = q.rewrite
}
if q.caseInsensitive != nil {
subQuery["case_insensitive"] = *q.caseInsensitive
}
if q.queryName != "" {
subQuery["_name"] = q.queryName
}
query[q.name] = subQuery
}
return source, nil
}

@ -0,0 +1,350 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
import (
"fmt"
)
// QueryStringQuery uses the query parser in order to parse its content.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-query-string-query.html
type QueryStringQuery struct {
queryString string
defaultField string
defaultOperator string
analyzer string
quoteAnalyzer string
quoteFieldSuffix string
allowLeadingWildcard *bool
lowercaseExpandedTerms *bool // Deprecated: Decision is now made by the analyzer
enablePositionIncrements *bool
analyzeWildcard *bool
locale string // Deprecated: Decision is now made by the analyzer
boost *float64
fuzziness string
fuzzyPrefixLength *int
fuzzyMaxExpansions *int
fuzzyRewrite string
phraseSlop *int
fields []string
fieldBoosts map[string]*float64
tieBreaker *float64
rewrite string
minimumShouldMatch string
lenient *bool
queryName string
timeZone string
maxDeterminizedStates *int
escape *bool
typ string
}
// NewQueryStringQuery creates and initializes a new QueryStringQuery.
func NewQueryStringQuery(queryString string) *QueryStringQuery {
return &QueryStringQuery{
queryString: queryString,
fields: make([]string, 0),
fieldBoosts: make(map[string]*float64),
}
}
// DefaultField specifies the field to run against when no prefix field
// is specified. Only relevant when not explicitly adding fields the query
// string will run against.
func (q *QueryStringQuery) DefaultField(defaultField string) *QueryStringQuery {
q.defaultField = defaultField
return q
}
// Field adds a field to run the query string against.
func (q *QueryStringQuery) Field(field string) *QueryStringQuery {
q.fields = append(q.fields, field)
return q
}
// Type sets how multiple fields should be combined to build textual part queries,
// e.g. "best_fields".
func (q *QueryStringQuery) Type(typ string) *QueryStringQuery {
q.typ = typ
return q
}
// FieldWithBoost adds a field to run the query string against with a specific boost.
func (q *QueryStringQuery) FieldWithBoost(field string, boost float64) *QueryStringQuery {
q.fields = append(q.fields, field)
q.fieldBoosts[field] = &boost
return q
}
// TieBreaker is used when more than one field is used with the query string,
// and combined queries are using dismax.
func (q *QueryStringQuery) TieBreaker(tieBreaker float64) *QueryStringQuery {
q.tieBreaker = &tieBreaker
return q
}
// DefaultOperator sets the boolean operator of the query parser used to
// parse the query string.
//
// In default mode (OR) terms without any modifiers
// are considered optional, e.g. "capital of Hungary" is equal to
// "capital OR of OR Hungary".
//
// In AND mode, terms are considered to be in conjunction. The above mentioned
// query is then parsed as "capital AND of AND Hungary".
func (q *QueryStringQuery) DefaultOperator(operator string) *QueryStringQuery {
q.defaultOperator = operator
return q
}
// Analyzer is an optional analyzer used to analyze the query string.
// Note, if a field has search analyzer defined for it, then it will be used
// automatically. Defaults to the smart search analyzer.
func (q *QueryStringQuery) Analyzer(analyzer string) *QueryStringQuery {
q.analyzer = analyzer
return q
}
// QuoteAnalyzer is an optional analyzer to be used to analyze the query string
// for phrase searches. Note, if a field has search analyzer defined for it,
// then it will be used automatically. Defaults to the smart search analyzer.
func (q *QueryStringQuery) QuoteAnalyzer(quoteAnalyzer string) *QueryStringQuery {
q.quoteAnalyzer = quoteAnalyzer
return q
}
// MaxDeterminizedState protects against too-difficult regular expression queries.
func (q *QueryStringQuery) MaxDeterminizedState(maxDeterminizedStates int) *QueryStringQuery {
q.maxDeterminizedStates = &maxDeterminizedStates
return q
}
// AllowLeadingWildcard specifies whether leading wildcards should be allowed
// or not (defaults to true).
func (q *QueryStringQuery) AllowLeadingWildcard(allowLeadingWildcard bool) *QueryStringQuery {
q.allowLeadingWildcard = &allowLeadingWildcard
return q
}
// LowercaseExpandedTerms indicates whether terms of wildcard, prefix, fuzzy
// and range queries are automatically lower-cased or not. Default is true.
//
// Deprecated: Decision is now made by the analyzer.
func (q *QueryStringQuery) LowercaseExpandedTerms(lowercaseExpandedTerms bool) *QueryStringQuery {
q.lowercaseExpandedTerms = &lowercaseExpandedTerms
return q
}
// EnablePositionIncrements indicates whether to enable position increments
// in result query. Defaults to true.
//
// When set, result phrase and multi-phrase queries will be aware of position
// increments. Useful when e.g. a StopFilter increases the position increment
// of the token that follows an omitted token.
func (q *QueryStringQuery) EnablePositionIncrements(enablePositionIncrements bool) *QueryStringQuery {
q.enablePositionIncrements = &enablePositionIncrements
return q
}
// Fuzziness sets the edit distance for fuzzy queries. Default is "AUTO".
func (q *QueryStringQuery) Fuzziness(fuzziness string) *QueryStringQuery {
q.fuzziness = fuzziness
return q
}
// FuzzyPrefixLength sets the minimum prefix length for fuzzy queries.
// Default is 1.
func (q *QueryStringQuery) FuzzyPrefixLength(fuzzyPrefixLength int) *QueryStringQuery {
q.fuzzyPrefixLength = &fuzzyPrefixLength
return q
}
func (q *QueryStringQuery) FuzzyMaxExpansions(fuzzyMaxExpansions int) *QueryStringQuery {
q.fuzzyMaxExpansions = &fuzzyMaxExpansions
return q
}
func (q *QueryStringQuery) FuzzyRewrite(fuzzyRewrite string) *QueryStringQuery {
q.fuzzyRewrite = fuzzyRewrite
return q
}
// PhraseSlop sets the default slop for phrases. If zero, then exact matches
// are required. Default value is zero.
func (q *QueryStringQuery) PhraseSlop(phraseSlop int) *QueryStringQuery {
q.phraseSlop = &phraseSlop
return q
}
// AnalyzeWildcard indicates whether to enabled analysis on wildcard and prefix queries.
func (q *QueryStringQuery) AnalyzeWildcard(analyzeWildcard bool) *QueryStringQuery {
q.analyzeWildcard = &analyzeWildcard
return q
}
func (q *QueryStringQuery) Rewrite(rewrite string) *QueryStringQuery {
q.rewrite = rewrite
return q
}
func (q *QueryStringQuery) MinimumShouldMatch(minimumShouldMatch string) *QueryStringQuery {
q.minimumShouldMatch = minimumShouldMatch
return q
}
// Boost sets the boost for this query.
func (q *QueryStringQuery) Boost(boost float64) *QueryStringQuery {
q.boost = &boost
return q
}
// QuoteFieldSuffix is an optional field name suffix to automatically
// try and add to the field searched when using quoted text.
func (q *QueryStringQuery) QuoteFieldSuffix(quoteFieldSuffix string) *QueryStringQuery {
q.quoteFieldSuffix = quoteFieldSuffix
return q
}
// Lenient indicates whether the query string parser should be lenient
// when parsing field values. It defaults to the index setting and if not
// set, defaults to false.
func (q *QueryStringQuery) Lenient(lenient bool) *QueryStringQuery {
q.lenient = &lenient
return q
}
// QueryName sets the query name for the filter that can be used when
// searching for matched_filters per hit.
func (q *QueryStringQuery) QueryName(queryName string) *QueryStringQuery {
q.queryName = queryName
return q
}
// Locale specifies the locale to be used for string conversions.
//
// Deprecated: Decision is now made by the analyzer.
func (q *QueryStringQuery) Locale(locale string) *QueryStringQuery {
q.locale = locale
return q
}
// TimeZone can be used to automatically adjust to/from fields using a
// timezone. Only used with date fields, of course.
func (q *QueryStringQuery) TimeZone(timeZone string) *QueryStringQuery {
q.timeZone = timeZone
return q
}
// Escape performs escaping of the query string.
func (q *QueryStringQuery) Escape(escape bool) *QueryStringQuery {
q.escape = &escape
return q
}
// Source returns JSON for the query.
func (q *QueryStringQuery) Source() (interface{}, error) {
source := make(map[string]interface{})
query := make(map[string]interface{})
source["query_string"] = query
query["query"] = q.queryString
if q.defaultField != "" {
query["default_field"] = q.defaultField
}
if len(q.fields) > 0 {
var fields []string
for _, field := range q.fields {
if boost, found := q.fieldBoosts[field]; found {
if boost != nil {
fields = append(fields, fmt.Sprintf("%s^%f", field, *boost))
} else {
fields = append(fields, field)
}
} else {
fields = append(fields, field)
}
}
query["fields"] = fields
}
if q.tieBreaker != nil {
query["tie_breaker"] = *q.tieBreaker
}
if q.defaultOperator != "" {
query["default_operator"] = q.defaultOperator
}
if q.analyzer != "" {
query["analyzer"] = q.analyzer
}
if q.quoteAnalyzer != "" {
query["quote_analyzer"] = q.quoteAnalyzer
}
if q.maxDeterminizedStates != nil {
query["max_determinized_states"] = *q.maxDeterminizedStates
}
if q.allowLeadingWildcard != nil {
query["allow_leading_wildcard"] = *q.allowLeadingWildcard
}
if q.lowercaseExpandedTerms != nil {
query["lowercase_expanded_terms"] = *q.lowercaseExpandedTerms
}
if q.enablePositionIncrements != nil {
query["enable_position_increments"] = *q.enablePositionIncrements
}
if q.fuzziness != "" {
query["fuzziness"] = q.fuzziness
}
if q.boost != nil {
query["boost"] = *q.boost
}
if q.fuzzyPrefixLength != nil {
query["fuzzy_prefix_length"] = *q.fuzzyPrefixLength
}
if q.fuzzyMaxExpansions != nil {
query["fuzzy_max_expansions"] = *q.fuzzyMaxExpansions
}
if q.fuzzyRewrite != "" {
query["fuzzy_rewrite"] = q.fuzzyRewrite
}
if q.phraseSlop != nil {
query["phrase_slop"] = *q.phraseSlop
}
if q.analyzeWildcard != nil {
query["analyze_wildcard"] = *q.analyzeWildcard
}
if q.rewrite != "" {
query["rewrite"] = q.rewrite
}
if q.minimumShouldMatch != "" {
query["minimum_should_match"] = q.minimumShouldMatch
}
if q.quoteFieldSuffix != "" {
query["quote_field_suffix"] = q.quoteFieldSuffix
}
if q.lenient != nil {
query["lenient"] = *q.lenient
}
if q.queryName != "" {
query["_name"] = q.queryName
}
if q.locale != "" {
query["locale"] = q.locale
}
if q.timeZone != "" {
query["time_zone"] = q.timeZone
}
if q.escape != nil {
query["escape"] = *q.escape
}
if q.typ != "" {
query["type"] = q.typ
}
return source, nil
}

@ -0,0 +1,155 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// RangeQuery matches documents with fields that have terms within a certain range.
//
// For details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-range-query.html
type RangeQuery struct {
name string
from interface{}
to interface{}
timeZone string
includeLower bool
includeUpper bool
boost *float64
queryName string
format string
relation string
}
// NewRangeQuery creates and initializes a new RangeQuery.
func NewRangeQuery(name string) *RangeQuery {
return &RangeQuery{name: name, includeLower: true, includeUpper: true}
}
// From indicates the from part of the RangeQuery.
// Use nil to indicate an unbounded from part.
func (q *RangeQuery) From(from interface{}) *RangeQuery {
q.from = from
return q
}
// Gt indicates a greater-than value for the from part.
// Use nil to indicate an unbounded from part.
func (q *RangeQuery) Gt(from interface{}) *RangeQuery {
q.from = from
q.includeLower = false
return q
}
// Gte indicates a greater-than-or-equal value for the from part.
// Use nil to indicate an unbounded from part.
func (q *RangeQuery) Gte(from interface{}) *RangeQuery {
q.from = from
q.includeLower = true
return q
}
// To indicates the to part of the RangeQuery.
// Use nil to indicate an unbounded to part.
func (q *RangeQuery) To(to interface{}) *RangeQuery {
q.to = to
return q
}
// Lt indicates a less-than value for the to part.
// Use nil to indicate an unbounded to part.
func (q *RangeQuery) Lt(to interface{}) *RangeQuery {
q.to = to
q.includeUpper = false
return q
}
// Lte indicates a less-than-or-equal value for the to part.
// Use nil to indicate an unbounded to part.
func (q *RangeQuery) Lte(to interface{}) *RangeQuery {
q.to = to
q.includeUpper = true
return q
}
// IncludeLower indicates whether the lower bound should be included or not.
// Defaults to true.
func (q *RangeQuery) IncludeLower(includeLower bool) *RangeQuery {
q.includeLower = includeLower
return q
}
// IncludeUpper indicates whether the upper bound should be included or not.
// Defaults to true.
func (q *RangeQuery) IncludeUpper(includeUpper bool) *RangeQuery {
q.includeUpper = includeUpper
return q
}
// Boost sets the boost for this query.
func (q *RangeQuery) Boost(boost float64) *RangeQuery {
q.boost = &boost
return q
}
// QueryName sets the query name for the filter that can be used when
// searching for matched_filters per hit.
func (q *RangeQuery) QueryName(queryName string) *RangeQuery {
q.queryName = queryName
return q
}
// TimeZone is used for date fields. In that case, we can adjust the
// from/to fields using a timezone.
func (q *RangeQuery) TimeZone(timeZone string) *RangeQuery {
q.timeZone = timeZone
return q
}
// Format is used for date fields. In that case, we can set the format
// to be used instead of the mapper format.
func (q *RangeQuery) Format(format string) *RangeQuery {
q.format = format
return q
}
// Relation is used for range fields. which can be one of
// "within", "contains", "intersects" (default) and "disjoint".
func (q *RangeQuery) Relation(relation string) *RangeQuery {
q.relation = relation
return q
}
// Source returns JSON for the query.
func (q *RangeQuery) Source() (interface{}, error) {
source := make(map[string]interface{})
rangeQ := make(map[string]interface{})
source["range"] = rangeQ
params := make(map[string]interface{})
rangeQ[q.name] = params
params["from"] = q.from
params["to"] = q.to
if q.timeZone != "" {
params["time_zone"] = q.timeZone
}
if q.format != "" {
params["format"] = q.format
}
if q.relation != "" {
params["relation"] = q.relation
}
if q.boost != nil {
params["boost"] = *q.boost
}
params["include_lower"] = q.includeLower
params["include_upper"] = q.includeUpper
if q.queryName != "" {
rangeQ["_name"] = q.queryName
}
return source, nil
}

@ -0,0 +1,213 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// RankFeatureQuery boosts the relevance score of documents based on the
// numeric value of a rank_feature or rank_features field.
//
// The RankFeatureQuery is typically used in the should clause of a BoolQuery
// so its relevance scores are added to other scores from the BoolQuery.
//
// For more details, see:
// https://www.elastic.co/guide/en/elasticsearch/reference/7.14/query-dsl-rank-feature-query.html
type RankFeatureQuery struct {
field string
scoreFunc RankFeatureScoreFunction
boost *float64
queryName string
}
// NewRankFeatureQuery creates and initializes a new RankFeatureQuery.
func NewRankFeatureQuery(field string) *RankFeatureQuery {
return &RankFeatureQuery{
field: field,
}
}
// Field name.
func (q *RankFeatureQuery) Field(field string) *RankFeatureQuery {
q.field = field
return q
}
// ScoreFunction specifies the score function for the RankFeatureQuery.
func (q *RankFeatureQuery) ScoreFunction(f RankFeatureScoreFunction) *RankFeatureQuery {
q.scoreFunc = f
return q
}
// Boost sets the boost for this query.
func (q *RankFeatureQuery) Boost(boost float64) *RankFeatureQuery {
q.boost = &boost
return q
}
// QueryName sets the query name for the filter that can be used when
// searching for matched_filters per hit.
func (q *RankFeatureQuery) QueryName(queryName string) *RankFeatureQuery {
q.queryName = queryName
return q
}
// Source returns the JSON serializable content for this query.
func (q *RankFeatureQuery) Source() (interface{}, error) {
// {
// "rank_feature": {
// "field": "pagerank",
// "saturation": {
// "pivot": 8
// }
// }
// }
query := make(map[string]interface{})
params := make(map[string]interface{})
query["rank_feature"] = params
params["field"] = q.field
if q.scoreFunc != nil {
src, err := q.scoreFunc.Source()
if err != nil {
return nil, err
}
params[q.scoreFunc.Name()] = src
}
if q.boost != nil {
params["boost"] = *q.boost
}
if q.queryName != "" {
params["_name"] = q.queryName
}
return query, nil
}
// -- Score functions --
// RankFeatureScoreFunction specifies the interface for score functions
// in the context of a RankFeatureQuery.
type RankFeatureScoreFunction interface {
Name() string
Source() (interface{}, error)
}
// -- Log score function --
// RankFeatureLogScoreFunction represents a Logarithmic score function for a
// RankFeatureQuery.
//
// See here for details:
// https://www.elastic.co/guide/en/elasticsearch/reference/7.14/query-dsl-rank-feature-query.html#rank-feature-query-logarithm
type RankFeatureLogScoreFunction struct {
scalingFactor float64
}
// NewRankFeatureLogScoreFunction returns a new RankFeatureLogScoreFunction
// with the given scaling factor.
func NewRankFeatureLogScoreFunction(scalingFactor float64) *RankFeatureLogScoreFunction {
return &RankFeatureLogScoreFunction{
scalingFactor: scalingFactor,
}
}
// Name of the score function.
func (f *RankFeatureLogScoreFunction) Name() string { return "log" }
// Source returns a serializable JSON object for building the query.
func (f *RankFeatureLogScoreFunction) Source() (interface{}, error) {
return map[string]interface{}{
"scaling_factor": f.scalingFactor,
}, nil
}
// -- Saturation score function --
// RankFeatureSaturationScoreFunction represents a Log score function for a
// RankFeatureQuery.
//
// See here for details:
// https://www.elastic.co/guide/en/elasticsearch/reference/7.14/query-dsl-rank-feature-query.html#rank-feature-query-saturation
type RankFeatureSaturationScoreFunction struct {
pivot *float64
}
// NewRankFeatureSaturationScoreFunction initializes a new
// RankFeatureSaturationScoreFunction.
func NewRankFeatureSaturationScoreFunction() *RankFeatureSaturationScoreFunction {
return &RankFeatureSaturationScoreFunction{}
}
// Pivot specifies the pivot to use.
func (f *RankFeatureSaturationScoreFunction) Pivot(pivot float64) *RankFeatureSaturationScoreFunction {
f.pivot = &pivot
return f
}
// Name of the score function.
func (f *RankFeatureSaturationScoreFunction) Name() string { return "saturation" }
// Source returns a serializable JSON object for building the query.
func (f *RankFeatureSaturationScoreFunction) Source() (interface{}, error) {
m := make(map[string]interface{})
if f.pivot != nil {
m["pivot"] = *f.pivot
}
return m, nil
}
// -- Sigmoid score function --
// RankFeatureSigmoidScoreFunction represents a Sigmoid score function for a
// RankFeatureQuery.
//
// See here for details:
// https://www.elastic.co/guide/en/elasticsearch/reference/7.14/query-dsl-rank-feature-query.html#rank-feature-query-sigmoid
type RankFeatureSigmoidScoreFunction struct {
pivot float64
exponent float64
}
// NewRankFeatureSigmoidScoreFunction returns a new RankFeatureSigmoidScoreFunction
// with the given scaling factor.
func NewRankFeatureSigmoidScoreFunction(pivot, exponent float64) *RankFeatureSigmoidScoreFunction {
return &RankFeatureSigmoidScoreFunction{
pivot: pivot,
exponent: exponent,
}
}
// Name of the score function.
func (f *RankFeatureSigmoidScoreFunction) Name() string { return "sigmoid" }
// Source returns a serializable JSON object for building the query.
func (f *RankFeatureSigmoidScoreFunction) Source() (interface{}, error) {
return map[string]interface{}{
"pivot": f.pivot,
"exponent": f.exponent,
}, nil
}
// -- Linear score function --
// RankFeatureLinearScoreFunction represents a Linear score function for a
// RankFeatureQuery.
//
// See here for details:
// https://www.elastic.co/guide/en/elasticsearch/reference/7.14/query-dsl-rank-feature-query.html#rank-feature-query-linear
type RankFeatureLinearScoreFunction struct {
}
// NewRankFeatureLinearScoreFunction initializes a new
// RankFeatureLinearScoreFunction.
func NewRankFeatureLinearScoreFunction() *RankFeatureLinearScoreFunction {
return &RankFeatureLinearScoreFunction{}
}
// Name of the score function.
func (f *RankFeatureLinearScoreFunction) Name() string { return "linear" }
// Source returns a serializable JSON object for building the query.
func (f *RankFeatureLinearScoreFunction) Source() (interface{}, error) {
return map[string]interface{}{}, nil
}

@ -0,0 +1,27 @@
// Copyright 2012-present Oliver Eilhard, John Stanford. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
import "encoding/json"
// RawStringQuery can be used to treat a string representation of an ES query
// as a Query. Example usage:
//
// q := RawStringQuery("{\"match_all\":{}}")
// db.Search().Query(q).From(1).Size(100).Do()
type RawStringQuery string
// NewRawStringQuery ininitializes a new RawStringQuery.
// It is the same as RawStringQuery(q).
func NewRawStringQuery(q string) RawStringQuery {
return RawStringQuery(q)
}
// Source returns the JSON encoded body
func (q RawStringQuery) Source() (interface{}, error) {
var f interface{}
err := json.Unmarshal([]byte(q), &f)
return f, err
}

@ -0,0 +1,91 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// RegexpQuery allows you to use regular expression term queries.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-regexp-query.html
type RegexpQuery struct {
name string
regexp string
flags string
boost *float64
rewrite string
caseInsensitive *bool
queryName string
maxDeterminizedStates *int
}
// NewRegexpQuery creates and initializes a new RegexpQuery.
func NewRegexpQuery(name string, regexp string) *RegexpQuery {
return &RegexpQuery{name: name, regexp: regexp}
}
// Flags sets the regexp flags.
func (q *RegexpQuery) Flags(flags string) *RegexpQuery {
q.flags = flags
return q
}
// MaxDeterminizedStates protects against complex regular expressions.
func (q *RegexpQuery) MaxDeterminizedStates(maxDeterminizedStates int) *RegexpQuery {
q.maxDeterminizedStates = &maxDeterminizedStates
return q
}
// Boost sets the boost for this query.
func (q *RegexpQuery) Boost(boost float64) *RegexpQuery {
q.boost = &boost
return q
}
func (q *RegexpQuery) Rewrite(rewrite string) *RegexpQuery {
q.rewrite = rewrite
return q
}
func (q *RegexpQuery) CaseInsensitive(caseInsensitive bool) *RegexpQuery {
q.caseInsensitive = &caseInsensitive
return q
}
// QueryName sets the query name for the filter that can be used
// when searching for matched_filters per hit
func (q *RegexpQuery) QueryName(queryName string) *RegexpQuery {
q.queryName = queryName
return q
}
// Source returns the JSON-serializable query data.
func (q *RegexpQuery) Source() (interface{}, error) {
source := make(map[string]interface{})
query := make(map[string]interface{})
source["regexp"] = query
x := make(map[string]interface{})
x["value"] = q.regexp
if q.flags != "" {
x["flags"] = q.flags
}
if q.maxDeterminizedStates != nil {
x["max_determinized_states"] = *q.maxDeterminizedStates
}
if q.boost != nil {
x["boost"] = *q.boost
}
if q.rewrite != "" {
x["rewrite"] = q.rewrite
}
if q.caseInsensitive != nil {
x["case_insensitive"] = *q.caseInsensitive
}
if q.queryName != "" {
x["name"] = q.queryName
}
query[q.name] = x
return source, nil
}

@ -0,0 +1,51 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
import "errors"
// ScriptQuery allows to define scripts as filters.
//
// For details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-script-query.html
type ScriptQuery struct {
script *Script
queryName string
}
// NewScriptQuery creates and initializes a new ScriptQuery.
func NewScriptQuery(script *Script) *ScriptQuery {
return &ScriptQuery{
script: script,
}
}
// QueryName sets the query name for the filter that can be used
// when searching for matched_filters per hit
func (q *ScriptQuery) QueryName(queryName string) *ScriptQuery {
q.queryName = queryName
return q
}
// Source returns JSON for the query.
func (q *ScriptQuery) Source() (interface{}, error) {
if q.script == nil {
return nil, errors.New("ScriptQuery expected a script")
}
source := make(map[string]interface{})
params := make(map[string]interface{})
source["script"] = params
src, err := q.script.Source()
if err != nil {
return nil, err
}
params["script"] = src
if q.queryName != "" {
params["_name"] = q.queryName
}
return source, nil
}

@ -0,0 +1,110 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
import "errors"
// ScriptScoreQuery uses a script to provide a custom score for returned documents.
//
// A ScriptScoreQuery query is useful if, for example, a scoring function is
// expensive and you only need to calculate the score of a filtered set of documents.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.4/query-dsl-script-score-query.html
type ScriptScoreQuery struct {
query Query
script *Script
minScore *float64
boost *float64
queryName string
}
// NewScriptScoreQuery creates and initializes a new script_score query.
func NewScriptScoreQuery(query Query, script *Script) *ScriptScoreQuery {
return &ScriptScoreQuery{
query: query,
script: script,
}
}
// Query to be used in the ScriptScoreQuery.
func (q *ScriptScoreQuery) Query(query Query) *ScriptScoreQuery {
q.query = query
return q
}
// Script to calculate the score.
func (q *ScriptScoreQuery) Script(script *Script) *ScriptScoreQuery {
q.script = script
return q
}
// MinScore sets the minimum score.
func (q *ScriptScoreQuery) MinScore(minScore float64) *ScriptScoreQuery {
q.minScore = &minScore
return q
}
// Boost sets the boost for this query.
func (q *ScriptScoreQuery) Boost(boost float64) *ScriptScoreQuery {
q.boost = &boost
return q
}
// QueryName sets the query name for the filter.
func (q *ScriptScoreQuery) QueryName(queryName string) *ScriptScoreQuery {
q.queryName = queryName
return q
}
// Source returns JSON for the function score query.
func (q *ScriptScoreQuery) Source() (interface{}, error) {
// {
// "script_score" : {
// "query" : {
// "match" : { "message": "elasticsearch" }
// },
// "script" : {
// "source" : "doc['likes'].value / 10"
// }
// }
// }
source := make(map[string]interface{})
query := make(map[string]interface{})
source["script_score"] = query
if q.query == nil {
return nil, errors.New("ScriptScoreQuery: Query is missing")
}
if q.script == nil {
return nil, errors.New("ScriptScoreQuery: Script is missing")
}
if src, err := q.query.Source(); err != nil {
return nil, err
} else {
query["query"] = src
}
if src, err := q.script.Source(); err != nil {
return nil, err
} else {
query["script"] = src
}
if v := q.minScore; v != nil {
query["min_score"] = *v
}
if v := q.boost; v != nil {
query["boost"] = *v
}
if q.queryName != "" {
query["_name"] = q.queryName
}
return source, nil
}

@ -0,0 +1,53 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// SliceQuery allows to partition the documents into several slices.
// It is used e.g. to slice scroll operations in Elasticsearch 5.0 or later.
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-request-scroll.html#sliced-scroll
// for details.
type SliceQuery struct {
field string
id *int
max *int
}
// NewSliceQuery creates a new SliceQuery.
func NewSliceQuery() *SliceQuery {
return &SliceQuery{}
}
// Field is the name of the field to slice against (_uid by default).
func (s *SliceQuery) Field(field string) *SliceQuery {
s.field = field
return s
}
// Id is the id of the slice.
func (s *SliceQuery) Id(id int) *SliceQuery {
s.id = &id
return s
}
// Max is the maximum number of slices.
func (s *SliceQuery) Max(max int) *SliceQuery {
s.max = &max
return s
}
// Source returns the JSON body.
func (s *SliceQuery) Source() (interface{}, error) {
m := make(map[string]interface{})
if s.field != "" {
m["field"] = s.field
}
if s.id != nil {
m["id"] = *s.id
}
if s.max != nil {
m["max"] = *s.max
}
return m, nil
}

@ -0,0 +1,67 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// TermQuery finds documents that contain the exact term specified
// in the inverted index.
//
// For details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-term-query.html
type TermQuery struct {
name string
value interface{}
boost *float64
caseInsensitive *bool
queryName string
}
// NewTermQuery creates and initializes a new TermQuery.
func NewTermQuery(name string, value interface{}) *TermQuery {
return &TermQuery{name: name, value: value}
}
// Boost sets the boost for this query.
func (q *TermQuery) Boost(boost float64) *TermQuery {
q.boost = &boost
return q
}
func (q *TermQuery) CaseInsensitive(caseInsensitive bool) *TermQuery {
q.caseInsensitive = &caseInsensitive
return q
}
// QueryName sets the query name for the filter that can be used
// when searching for matched_filters per hit
func (q *TermQuery) QueryName(queryName string) *TermQuery {
q.queryName = queryName
return q
}
// Source returns JSON for the query.
func (q *TermQuery) Source() (interface{}, error) {
// {"term":{"name":"value"}}
source := make(map[string]interface{})
tq := make(map[string]interface{})
source["term"] = tq
if q.boost == nil && q.caseInsensitive == nil && q.queryName == "" {
tq[q.name] = q.value
} else {
subQ := make(map[string]interface{})
subQ["value"] = q.value
if q.boost != nil {
subQ["boost"] = *q.boost
}
if q.caseInsensitive != nil {
subQ["case_insensitive"] = *q.caseInsensitive
}
if q.queryName != "" {
subQ["_name"] = q.queryName
}
tq[q.name] = subQ
}
return source, nil
}

@ -0,0 +1,88 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// TermsQuery filters documents that have fields that match any
// of the provided terms (not analyzed).
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-terms-query.html
type TermsQuery struct {
name string
values []interface{}
termsLookup *TermsLookup
queryName string
boost *float64
}
// NewTermsQuery creates and initializes a new TermsQuery.
func NewTermsQuery(name string, values ...interface{}) *TermsQuery {
q := &TermsQuery{
name: name,
values: make([]interface{}, 0),
}
if len(values) > 0 {
q.values = append(q.values, values...)
}
return q
}
// NewTermsQueryFromStrings creates and initializes a new TermsQuery
// from strings.
func NewTermsQueryFromStrings(name string, values ...string) *TermsQuery {
q := &TermsQuery{
name: name,
values: make([]interface{}, 0),
}
for _, v := range values {
q.values = append(q.values, v)
}
return q
}
// TermsLookup adds terms lookup details to the query.
func (q *TermsQuery) TermsLookup(lookup *TermsLookup) *TermsQuery {
q.termsLookup = lookup
return q
}
// Boost sets the boost for this query.
func (q *TermsQuery) Boost(boost float64) *TermsQuery {
q.boost = &boost
return q
}
// QueryName sets the query name for the filter that can be used
// when searching for matched_filters per hit
func (q *TermsQuery) QueryName(queryName string) *TermsQuery {
q.queryName = queryName
return q
}
// Creates the query source for the term query.
func (q *TermsQuery) Source() (interface{}, error) {
// {"terms":{"name":["value1","value2"]}}
source := make(map[string]interface{})
params := make(map[string]interface{})
source["terms"] = params
if q.termsLookup != nil {
src, err := q.termsLookup.Source()
if err != nil {
return nil, err
}
params[q.name] = src
} else {
params[q.name] = q.values
if q.boost != nil {
params["boost"] = *q.boost
}
if q.queryName != "" {
params["_name"] = q.queryName
}
}
return source, nil
}

@ -0,0 +1,76 @@
// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.
package es
// TermsLookup encapsulates the parameters needed to fetch terms.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-terms-query.html#query-dsl-terms-lookup.
type TermsLookup struct {
index string
typ string
id string
path string
routing string
}
// NewTermsLookup creates and initializes a new TermsLookup.
func NewTermsLookup() *TermsLookup {
t := &TermsLookup{}
return t
}
// Index name.
func (t *TermsLookup) Index(index string) *TermsLookup {
t.index = index
return t
}
// Type name.
//
// Deprecated: Types are in the process of being removed.
func (t *TermsLookup) Type(typ string) *TermsLookup {
t.typ = typ
return t
}
// Id to look up.
func (t *TermsLookup) Id(id string) *TermsLookup {
t.id = id
return t
}
// Path to use for lookup.
func (t *TermsLookup) Path(path string) *TermsLookup {
t.path = path
return t
}
// Routing value.
func (t *TermsLookup) Routing(routing string) *TermsLookup {
t.routing = routing
return t
}
// Source creates the JSON source of the builder.
func (t *TermsLookup) Source() (interface{}, error) {
src := make(map[string]interface{})
if t.index != "" {
src["index"] = t.index
}
if t.typ != "" {
src["type"] = t.typ
}
if t.id != "" {
src["id"] = t.id
}
if t.path != "" {
src["path"] = t.path
}
if t.routing != "" {
src["routing"] = t.routing
}
return src, nil
}
Loading…
Cancel
Save