This commit performs the following modifications: - The library is properly documented in Godoc format. - The CustomQuery function is made to be a bit more versatile by allowing it to also be used standalone (i.e. instead of passing a `CustomQuery` as a parameter to the `Query` function, they now have their own `Run` method). - Queries and aggregations can now also be executed using the `RunSearch` method. This method is the same as the `Run` method, except that instead of an `*elasticSearch.Client` value, it accepts an `esapi.Search` value. This is provided for consuming code that needs to implement mock clients of ElasticSearch (e.g. for test purposes). The ElasticSearch client does not provide an interface type describing its API, so its Search function (which is actually a field of a function type) can be used instead. - Bugfix: the CustomAgg function was unusable as it did not accept a name parameter and thus did not implement the Aggregation interface. - Bugfix: the enumeration types are rewritten according to Go standards, and the `RangeRelation` type's default value is now empty. - The golint and godox linters are added.
254 lines
7.7 KiB
Go
254 lines
7.7 KiB
Go
package esquery
|
|
|
|
import (
|
|
"github.com/fatih/structs"
|
|
)
|
|
|
|
type matchType uint8
|
|
|
|
const (
|
|
// TypeMatch denotes a query of type "match"
|
|
TypeMatch matchType = iota
|
|
|
|
// TypeMatchBool denotes a query of type "match_bool_prefix"
|
|
TypeMatchBoolPrefix
|
|
|
|
// TypeMatchPhrase denotes a query of type "match_phrase"
|
|
TypeMatchPhrase
|
|
|
|
// TypeMatchPhrasePrefix denotes a query of type "match_phrase_prefix"
|
|
TypeMatchPhrasePrefix
|
|
)
|
|
|
|
// MatchQuery represents a query of type "match", "match_bool_prefix",
|
|
// "match_phrase" and "match_phrase_prefix". While all four share the same
|
|
// general structure, they don't necessarily support all the same options. The
|
|
// library does not attempt to verify provided options are supported.
|
|
// See the ElasticSearch documentation for more information:
|
|
// - https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query.html
|
|
// - https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-bool-prefix-query.html
|
|
// - https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase.html
|
|
// - https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-query-phrase-prefix.html
|
|
type MatchQuery struct {
|
|
field string
|
|
mType matchType
|
|
params matchParams
|
|
}
|
|
|
|
// Map returns a map representation of the query, thus implementing the
|
|
// Mappable interface.
|
|
func (q *MatchQuery) Map() map[string]interface{} {
|
|
var mType string
|
|
switch q.mType {
|
|
case TypeMatch:
|
|
mType = "match"
|
|
case TypeMatchBoolPrefix:
|
|
mType = "match_bool_prefix"
|
|
case TypeMatchPhrase:
|
|
mType = "match_phrase"
|
|
case TypeMatchPhrasePrefix:
|
|
mType = "match_phrase_prefix"
|
|
}
|
|
|
|
return map[string]interface{}{
|
|
mType: map[string]interface{}{
|
|
q.field: structs.Map(q.params),
|
|
},
|
|
}
|
|
}
|
|
|
|
type matchParams struct {
|
|
Qry interface{} `structs:"query"`
|
|
Anl string `structs:"analyzer,omitempty"`
|
|
AutoGenerate *bool `structs:"auto_generate_synonyms_phrase_query,omitempty"`
|
|
Fuzz string `structs:"fuzziness,omitempty"`
|
|
MaxExp uint16 `structs:"max_expansions,omitempty"`
|
|
PrefLen uint16 `structs:"prefix_length,omitempty"`
|
|
Trans *bool `structs:"transpositions,omitempty"`
|
|
FuzzyRw string `structs:"fuzzy_rewrite,omitempty"`
|
|
Lent bool `structs:"lenient,omitempty"`
|
|
Op MatchOperator `structs:"operator,string,omitempty"`
|
|
MinMatch string `structs:"minimum_should_match,omitempty"`
|
|
ZeroTerms ZeroTerms `structs:"zero_terms_query,string,omitempty"`
|
|
Slp uint16 `structs:"slop,omitempty"` // only relevant for match_phrase query
|
|
}
|
|
|
|
// Match creates a new query of type "match" with the provided field name.
|
|
// A comparison value can optionally be provided to quickly create a simple
|
|
// query such as { "match": { "message": "this is a test" } }
|
|
func Match(fieldName string, simpleQuery ...interface{}) *MatchQuery {
|
|
return newMatch(TypeMatch, fieldName, simpleQuery...)
|
|
}
|
|
|
|
// MatchBoolPrefix creates a new query of type "match_bool_prefix" with the
|
|
// provided field name. A comparison value can optionally be provided to quickly
|
|
// create a simple query such as { "match": { "message": "this is a test" } }
|
|
func MatchBoolPrefix(fieldName string, simpleQuery ...interface{}) *MatchQuery {
|
|
return newMatch(TypeMatchBoolPrefix, fieldName, simpleQuery...)
|
|
}
|
|
|
|
// MatchPhrase creates a new query of type "match_phrase" with the
|
|
// provided field name. A comparison value can optionally be provided to quickly
|
|
// create a simple query such as { "match": { "message": "this is a test" } }
|
|
func MatchPhrase(fieldName string, simpleQuery ...interface{}) *MatchQuery {
|
|
return newMatch(TypeMatchPhrase, fieldName, simpleQuery...)
|
|
}
|
|
|
|
// MatchPhrasePrefix creates a new query of type "match_phrase_prefix" with the
|
|
// provided field name. A comparison value can optionally be provided to quickly
|
|
// create a simple query such as { "match": { "message": "this is a test" } }
|
|
func MatchPhrasePrefix(fieldName string, simpleQuery ...interface{}) *MatchQuery {
|
|
return newMatch(TypeMatchPhrasePrefix, fieldName, simpleQuery...)
|
|
}
|
|
|
|
func newMatch(mType matchType, fieldName string, simpleQuery ...interface{}) *MatchQuery {
|
|
var qry interface{}
|
|
if len(simpleQuery) > 0 {
|
|
qry = simpleQuery[len(simpleQuery)-1]
|
|
}
|
|
|
|
return &MatchQuery{
|
|
field: fieldName,
|
|
mType: mType,
|
|
params: matchParams{
|
|
Qry: qry,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Query sets the data to find in the query's field (it is the "query" component
|
|
// of the query).
|
|
func (q *MatchQuery) Query(data interface{}) *MatchQuery {
|
|
q.params.Qry = data
|
|
return q
|
|
}
|
|
|
|
// Analyzer sets the analyzer used to convert the text in the "query" value into
|
|
// tokens.
|
|
func (q *MatchQuery) Analyzer(a string) *MatchQuery {
|
|
q.params.Anl = a
|
|
return q
|
|
}
|
|
|
|
// AutoGenerateSynonymsPhraseQuery sets the "auto_generate_synonyms_phrase_query"
|
|
// boolean.
|
|
func (q *MatchQuery) AutoGenerateSynonymsPhraseQuery(b bool) *MatchQuery {
|
|
q.params.AutoGenerate = &b
|
|
return q
|
|
}
|
|
|
|
// Fuzziness set the maximum edit distance allowed for matching.
|
|
func (q *MatchQuery) Fuzziness(f string) *MatchQuery {
|
|
q.params.Fuzz = f
|
|
return q
|
|
}
|
|
|
|
// MaxExpansions sets the maximum number of terms to which the query will expand.
|
|
func (q *MatchQuery) MaxExpansions(e uint16) *MatchQuery {
|
|
q.params.MaxExp = e
|
|
return q
|
|
}
|
|
|
|
// PrefixLength sets the number of beginning characters left unchanged for fuzzy
|
|
// matching.
|
|
func (q *MatchQuery) PrefixLength(l uint16) *MatchQuery {
|
|
q.params.PrefLen = l
|
|
return q
|
|
}
|
|
|
|
// Transpositions sets whether edits for fuzzy matching include transpositions
|
|
// of two adjacent characters.
|
|
func (q *MatchQuery) Transpositions(b bool) *MatchQuery {
|
|
q.params.Trans = &b
|
|
return q
|
|
}
|
|
|
|
// FuzzyRewrite sets the method used to rewrite the query.
|
|
func (q *MatchQuery) FuzzyRewrite(s string) *MatchQuery {
|
|
q.params.FuzzyRw = s
|
|
return q
|
|
}
|
|
|
|
// Lenient sets whether format-based errors should be ignored.
|
|
func (q *MatchQuery) Lenient(b bool) *MatchQuery {
|
|
q.params.Lent = b
|
|
return q
|
|
}
|
|
|
|
// Operator sets the boolean logic used to interpret text in the query value.
|
|
func (q *MatchQuery) Operator(op MatchOperator) *MatchQuery {
|
|
q.params.Op = op
|
|
return q
|
|
}
|
|
|
|
// MinimumShouldMatch sets the minimum number of clauses that must match for a
|
|
// document to be returned.
|
|
func (q *MatchQuery) MinimumShouldMatch(s string) *MatchQuery {
|
|
q.params.MinMatch = s
|
|
return q
|
|
}
|
|
|
|
// Slop sets the maximum number of positions allowed between matching tokens.
|
|
func (q *MatchQuery) Slop(n uint16) *MatchQuery {
|
|
q.params.Slp = n
|
|
return q
|
|
}
|
|
|
|
// ZeroTermsQuery sets the "zero_terms_query" option to use. This indicates
|
|
// whether no documents are returned if the analyzer removes all tokens, such as
|
|
// when using a stop filter.
|
|
func (q *MatchQuery) ZeroTermsQuery(s ZeroTerms) *MatchQuery {
|
|
q.params.ZeroTerms = s
|
|
return q
|
|
}
|
|
|
|
// MatchOperator is an enumeration type representing supported values for a
|
|
// match query's "operator" parameter.
|
|
type MatchOperator uint8
|
|
|
|
const (
|
|
// OperatorOr is the "or" operator
|
|
OperatorOr MatchOperator = iota
|
|
|
|
// OperatorAnd is the "and" operator
|
|
OperatorAnd
|
|
)
|
|
|
|
// String returns a string representation of the match operator, as known to
|
|
// ElasticSearch.
|
|
func (a MatchOperator) String() string {
|
|
switch a {
|
|
case OperatorOr:
|
|
return "OR"
|
|
case OperatorAnd:
|
|
return "AND"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
// ZeroTerms is an enumeration type representing supported values for a match
|
|
// query's "zero_terms_query" parameter.
|
|
type ZeroTerms uint8
|
|
|
|
const (
|
|
// ZeroTermsNone is the "none" value
|
|
ZeroTermsNone ZeroTerms = iota
|
|
|
|
// ZeroTermsAll is the "all" value
|
|
ZeroTermsAll
|
|
)
|
|
|
|
// String returns a string representation of the zero_terms_query parameter, as
|
|
// known to ElasticSearch.
|
|
func (a ZeroTerms) String() string {
|
|
switch a {
|
|
case ZeroTermsNone:
|
|
return "none"
|
|
case ZeroTermsAll:
|
|
return "all"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|