1// Copyright 2012-present Oliver Eilhard. All rights reserved.
2// Use of this source code is governed by a MIT-license.
3// See http://olivere.mit-license.org/license.txt for details.
4
5package elastic
6
7// MatchQuery is a family of queries that accepts text/numerics/dates,
8// analyzes them, and constructs a query.
9//
10// To create a new MatchQuery, use NewMatchQuery. To create specific types
11// of queries, e.g. a match_phrase query, use NewMatchPhrQuery(...).Type("phrase"),
12// or use one of the shortcuts e.g. NewMatchPhraseQuery(...).
13//
14// For more details, see
15// https://www.elastic.co/guide/en/elasticsearch/reference/5.2/query-dsl-match-query.html
16type MatchQuery struct {
17	name                string
18	text                interface{}
19	operator            string // or / and
20	analyzer            string
21	boost               *float64
22	fuzziness           string
23	prefixLength        *int
24	maxExpansions       *int
25	minimumShouldMatch  string
26	fuzzyRewrite        string
27	lenient             *bool
28	fuzzyTranspositions *bool
29	zeroTermsQuery      string
30	cutoffFrequency     *float64
31	queryName           string
32}
33
34// NewMatchQuery creates and initializes a new MatchQuery.
35func NewMatchQuery(name string, text interface{}) *MatchQuery {
36	return &MatchQuery{name: name, text: text}
37}
38
39// Operator sets the operator to use when using a boolean query.
40// Can be "AND" or "OR" (default).
41func (q *MatchQuery) Operator(operator string) *MatchQuery {
42	q.operator = operator
43	return q
44}
45
46// Analyzer explicitly sets the analyzer to use. It defaults to use explicit
47// mapping config for the field, or, if not set, the default search analyzer.
48func (q *MatchQuery) Analyzer(analyzer string) *MatchQuery {
49	q.analyzer = analyzer
50	return q
51}
52
53// Fuzziness sets the fuzziness when evaluated to a fuzzy query type.
54// Defaults to "AUTO".
55func (q *MatchQuery) Fuzziness(fuzziness string) *MatchQuery {
56	q.fuzziness = fuzziness
57	return q
58}
59
60// PrefixLength sets the length of a length of common (non-fuzzy)
61// prefix for fuzzy match queries. It must be non-negative.
62func (q *MatchQuery) PrefixLength(prefixLength int) *MatchQuery {
63	q.prefixLength = &prefixLength
64	return q
65}
66
67// MaxExpansions is used with fuzzy or prefix type queries. It specifies
68// the number of term expansions to use. It defaults to unbounded so that
69// its recommended to set it to a reasonable value for faster execution.
70func (q *MatchQuery) MaxExpansions(maxExpansions int) *MatchQuery {
71	q.maxExpansions = &maxExpansions
72	return q
73}
74
75// CutoffFrequency can be a value in [0..1] (or an absolute number >=1).
76// It represents the maximum treshold of a terms document frequency to be
77// considered a low frequency term.
78func (q *MatchQuery) CutoffFrequency(cutoff float64) *MatchQuery {
79	q.cutoffFrequency = &cutoff
80	return q
81}
82
83// MinimumShouldMatch sets the optional minimumShouldMatch value to
84// apply to the query.
85func (q *MatchQuery) MinimumShouldMatch(minimumShouldMatch string) *MatchQuery {
86	q.minimumShouldMatch = minimumShouldMatch
87	return q
88}
89
90// FuzzyRewrite sets the fuzzy_rewrite parameter controlling how the
91// fuzzy query will get rewritten.
92func (q *MatchQuery) FuzzyRewrite(fuzzyRewrite string) *MatchQuery {
93	q.fuzzyRewrite = fuzzyRewrite
94	return q
95}
96
97// FuzzyTranspositions sets whether transpositions are supported in
98// fuzzy queries.
99//
100// The default metric used by fuzzy queries to determine a match is
101// the Damerau-Levenshtein distance formula which supports transpositions.
102// Setting transposition to false will
103// * switch to classic Levenshtein distance.
104// * If not set, Damerau-Levenshtein distance metric will be used.
105func (q *MatchQuery) FuzzyTranspositions(fuzzyTranspositions bool) *MatchQuery {
106	q.fuzzyTranspositions = &fuzzyTranspositions
107	return q
108}
109
110// Lenient specifies whether format based failures will be ignored.
111func (q *MatchQuery) Lenient(lenient bool) *MatchQuery {
112	q.lenient = &lenient
113	return q
114}
115
116// ZeroTermsQuery can be "all" or "none".
117func (q *MatchQuery) ZeroTermsQuery(zeroTermsQuery string) *MatchQuery {
118	q.zeroTermsQuery = zeroTermsQuery
119	return q
120}
121
122// Boost sets the boost to apply to this query.
123func (q *MatchQuery) Boost(boost float64) *MatchQuery {
124	q.boost = &boost
125	return q
126}
127
128// QueryName sets the query name for the filter that can be used when
129// searching for matched filters per hit.
130func (q *MatchQuery) QueryName(queryName string) *MatchQuery {
131	q.queryName = queryName
132	return q
133}
134
135// Source returns JSON for the function score query.
136func (q *MatchQuery) Source() (interface{}, error) {
137	// {"match":{"name":{"query":"value","type":"boolean/phrase"}}}
138	source := make(map[string]interface{})
139
140	match := make(map[string]interface{})
141	source["match"] = match
142
143	query := make(map[string]interface{})
144	match[q.name] = query
145
146	query["query"] = q.text
147
148	if q.operator != "" {
149		query["operator"] = q.operator
150	}
151	if q.analyzer != "" {
152		query["analyzer"] = q.analyzer
153	}
154	if q.fuzziness != "" {
155		query["fuzziness"] = q.fuzziness
156	}
157	if q.prefixLength != nil {
158		query["prefix_length"] = *q.prefixLength
159	}
160	if q.maxExpansions != nil {
161		query["max_expansions"] = *q.maxExpansions
162	}
163	if q.minimumShouldMatch != "" {
164		query["minimum_should_match"] = q.minimumShouldMatch
165	}
166	if q.fuzzyRewrite != "" {
167		query["fuzzy_rewrite"] = q.fuzzyRewrite
168	}
169	if q.lenient != nil {
170		query["lenient"] = *q.lenient
171	}
172	if q.fuzzyTranspositions != nil {
173		query["fuzzy_transpositions"] = *q.fuzzyTranspositions
174	}
175	if q.zeroTermsQuery != "" {
176		query["zero_terms_query"] = q.zeroTermsQuery
177	}
178	if q.cutoffFrequency != nil {
179		query["cutoff_frequency"] = q.cutoffFrequency
180	}
181	if q.boost != nil {
182		query["boost"] = *q.boost
183	}
184	if q.queryName != "" {
185		query["_name"] = q.queryName
186	}
187
188	return source, nil
189}
190