esquery/match.go

262 lines
5.9 KiB
Go

package esquery
import (
"bytes"
"encoding/json"
"errors"
"io"
"github.com/elastic/go-elasticsearch/esapi"
)
/*******************************************************************************
* Match Queries
* 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 matchType uint8
const (
TypeMatch matchType = iota
TypeMatchBoolPrefix
TypeMatchPhrase
TypeMatchPhrasePrefix
)
type MatchQuery struct {
field string
mType matchType
params matchParams
}
func (a MatchQuery) MarshalJSON() ([]byte, error) {
var mType string
switch a.mType {
case TypeMatch:
mType = "match"
case TypeMatchBoolPrefix:
mType = "match_bool_prefix"
case TypeMatchPhrase:
mType = "match_phrase"
case TypeMatchPhrasePrefix:
mType = "match_phrase_prefix"
}
return json.Marshal(map[string]interface{}{
mType: map[string]interface{}{
a.field: a.params,
},
})
}
func (a *MatchQuery) Run(api *esapi.API, o ...func(*esapi.SearchRequest)) (res *esapi.Response, err error) {
return search(*a, api, o...)
}
type matchParams struct {
Qry interface{} `json:"query"`
Anl string `json:"analyzer,omitempty"`
AutoGenerate *bool `json:"auto_generate_synonyms_phrase_query,omitempty"`
Fuzz string `json:"fuzziness,omitempty"`
MaxExp uint16 `json:"max_expansions,omitempty"`
PrefLen uint16 `json:"prefix_length,omitempty"`
Trans *bool `json:"transpositions,omitempty"`
FuzzyRw string `json:"fuzzy_rewrite,omitempty"`
Lent bool `json:"lenient,omitempty"`
Op MatchOperator `json:"operator,omitempty"`
MinMatch string `json:"minimum_should_match,omitempty"`
ZeroTerms string `json:"zero_terms_query,omitempty"`
Slp uint16 `json:"slop,omitempty"` // only relevant for match_phrase query
}
func Match(fieldName string, simpleQuery ...interface{}) *MatchQuery {
return newMatch(TypeMatch, fieldName, simpleQuery...)
}
func MatchBoolPrefix(fieldName string, simpleQuery ...interface{}) *MatchQuery {
return newMatch(TypeMatchBoolPrefix, fieldName, simpleQuery...)
}
func MatchPhrase(fieldName string, simpleQuery ...interface{}) *MatchQuery {
return newMatch(TypeMatchPhrase, fieldName, simpleQuery...)
}
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 simpleQuery != nil && len(simpleQuery) > 0 {
qry = simpleQuery[len(simpleQuery)-1]
}
return &MatchQuery{
field: fieldName,
mType: mType,
params: matchParams{
Qry: qry,
},
}
}
func (q *MatchQuery) Query(data interface{}) *MatchQuery {
q.params.Qry = data
return q
}
func (q *MatchQuery) Analyzer(a string) *MatchQuery {
q.params.Anl = a
return q
}
func (q *MatchQuery) AutoGenerateSynonymsPhraseQuery(b bool) *MatchQuery {
q.params.AutoGenerate = &b
return q
}
func (q *MatchQuery) Fuzziness(f string) *MatchQuery {
q.params.Fuzz = f
return q
}
func (q *MatchQuery) MaxExpansions(e uint16) *MatchQuery {
q.params.MaxExp = e
return q
}
func (q *MatchQuery) PrefixLength(l uint16) *MatchQuery {
q.params.PrefLen = l
return q
}
func (q *MatchQuery) Transpositions(b bool) *MatchQuery {
q.params.Trans = &b
return q
}
func (q *MatchQuery) FuzzyRewrite(s string) *MatchQuery {
q.params.FuzzyRw = s
return q
}
func (q *MatchQuery) Lenient(b bool) *MatchQuery {
q.params.Lent = b
return q
}
func (q *MatchQuery) Operator(op MatchOperator) *MatchQuery {
q.params.Op = op
return q
}
func (q *MatchQuery) MinimumShouldMatch(s string) *MatchQuery {
q.params.MinMatch = s
return q
}
func (q *MatchQuery) Slop(n uint16) *MatchQuery {
q.params.Slp = n
return q
}
func (q *MatchQuery) ZeroTermsQuery(s string) *MatchQuery {
q.params.ZeroTerms = s
return q
}
func (q *MatchQuery) Reader() io.Reader {
var b bytes.Buffer
return &b
}
type MatchOperator uint8
const (
OR MatchOperator = iota
AND
)
var ErrInvalidValue = errors.New("invalid constant value")
func (a MatchOperator) MarshalJSON() ([]byte, error) {
var s string
switch a {
case OR:
s = "or"
case AND:
s = "and"
default:
return nil, ErrInvalidValue
}
return json.Marshal(s)
}
type ZeroTerms uint8
const (
None ZeroTerms = iota
All
)
func (a ZeroTerms) MarshalJSON() ([]byte, error) {
var s string
switch a {
case None:
s = "none"
case All:
s = "all"
default:
return nil, ErrInvalidValue
}
return json.Marshal(s)
}
/*******************************************************************************
* Multi-Match Queries
* https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html
* NOTE: uncommented for now, article is too long
******************************************************************************/
//type MultiMatchQuery struct {
//fields []string
//mType multiMatchType
//params multiMatchQueryParams
//}
//type multiMatchType uint8
//const (
//BestFields multiMatchType = iota
//MostFields
//CrossFields
//Phrase
//PhrasePrefix
//BoolPrefix
//)
//func (a multiMatchType) MarshalJSON() ([]byte, error) {
//var s string
//switch a {
//case BestFields:
//s = "best_fields"
//case MostFields:
//s = "most_fields"
//case CrossFields:
//s = "cross_fields"
//case Phrase:
//s = "phrase"
//case PhrasePrefix:
//s = "phrase_prefix"
//case BoolPrefix:
//s = "bool_prefix"
//default:
//return nil, ErrInvalidValue
//}
//return json.Marshal(s)
//}