Skip to content

Commit 36c8ae5

Browse files
committed
Refactor completion suggester to accept regex/prefix and options
The completion suggester now supports regex/prefix and their options. The FuzzyCompletionSuggester is removed as it can be completely implemented with CompletionSuggester now.
1 parent 7a065d5 commit 36c8ae5

8 files changed

+282
-238
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ services:
1212
- docker
1313
before_install:
1414
- sudo sysctl -w vm.max_map_count=262144
15-
- docker run -d --rm -p 9200:9200 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "bootstrap.memory_lock=true" -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:6.0.0 elasticsearch -Expack.security.enabled=false -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_
15+
- docker run -d --rm -p 9200:9200 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "bootstrap.memory_lock=true" -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:6.1.1 elasticsearch -Expack.security.enabled=false -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_

CONTRIBUTORS

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Marcy Buccellato [@marcybuccellato](https://github.com/marcybuccellato)
8484
Mark Costello [@mcos](https://github.com/mcos)
8585
Martin Häger [@protomouse](https://github.com/protomouse)
8686
Medhi Bechina [@mdzor](https://github.com/mdzor)
87+
mnpritula [@mnpritula](https://github.com/mnpritula)
8788
mosa [@mosasiru](https://github.com/mosasiru)
8889
naimulhaider [@naimulhaider](https://github.com/naimulhaider)
8990
Naoya Yoshizawa [@azihsoyn](https://github.com/azihsoyn)

client.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626

2727
const (
2828
// Version is the current version of Elastic.
29-
Version = "6.0.0"
29+
Version = "6.1.0"
3030

3131
// DefaultURL is the default endpoint of Elasticsearch on the local machine.
3232
// It is used e.g. when initializing a new Client without a specific URL.

run-es.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/bin/sh
2-
VERSION=${VERSION:=6.0.0}
2+
VERSION=${VERSION:=6.1.1}
33
docker run --rm -p 9200:9200 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "bootstrap.memory_lock=true" -e "ES_JAVA_OPTS=-Xms1g -Xmx1g" docker.elastic.co/elasticsearch/elasticsearch:$VERSION elasticsearch -Expack.security.enabled=false -Enetwork.host=_local_,_site_ -Enetwork.publish_host=_local_

suggester_completion.go

+220-6
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,30 @@ package elastic
77
import "errors"
88

99
// CompletionSuggester is a fast suggester for e.g. type-ahead completion.
10-
// See https://www.elastic.co/guide/en/elasticsearch/reference/6.0/search-suggesters-completion.html
10+
// See https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-suggesters-completion.html
1111
// for more details.
1212
type CompletionSuggester struct {
1313
Suggester
1414
name string
1515
text string
16+
prefix string
17+
regex string
1618
field string
1719
analyzer string
1820
size *int
1921
shardSize *int
2022
contextQueries []SuggesterContextQuery
23+
payload interface{}
24+
25+
fuzzyOptions *FuzzyCompletionSuggesterOptions
26+
regexOptions *RegexCompletionSuggesterOptions
27+
skipDuplicates *bool
2128
}
2229

2330
// Creates a new completion suggester.
2431
func NewCompletionSuggester(name string) *CompletionSuggester {
2532
return &CompletionSuggester{
26-
name: name,
27-
contextQueries: make([]SuggesterContextQuery, 0),
33+
name: name,
2834
}
2935
}
3036

@@ -37,6 +43,57 @@ func (q *CompletionSuggester) Text(text string) *CompletionSuggester {
3743
return q
3844
}
3945

46+
func (q *CompletionSuggester) Prefix(prefix string) *CompletionSuggester {
47+
q.prefix = prefix
48+
return q
49+
}
50+
51+
func (q *CompletionSuggester) PrefixWithEditDistance(prefix string, editDistance interface{}) *CompletionSuggester {
52+
q.prefix = prefix
53+
q.fuzzyOptions = NewFuzzyCompletionSuggesterOptions().EditDistance(editDistance)
54+
return q
55+
}
56+
57+
func (q *CompletionSuggester) PrefixWithOptions(prefix string, options *FuzzyCompletionSuggesterOptions) *CompletionSuggester {
58+
q.prefix = prefix
59+
q.fuzzyOptions = options
60+
return q
61+
}
62+
63+
func (q *CompletionSuggester) FuzzyOptions(options *FuzzyCompletionSuggesterOptions) *CompletionSuggester {
64+
q.fuzzyOptions = options
65+
return q
66+
}
67+
68+
func (q *CompletionSuggester) Fuzziness(fuzziness interface{}) *CompletionSuggester {
69+
if q.fuzzyOptions == nil {
70+
q.fuzzyOptions = NewFuzzyCompletionSuggesterOptions()
71+
}
72+
q.fuzzyOptions = q.fuzzyOptions.EditDistance(fuzziness)
73+
return q
74+
}
75+
76+
func (q *CompletionSuggester) Regex(regex string) *CompletionSuggester {
77+
q.regex = regex
78+
return q
79+
}
80+
81+
func (q *CompletionSuggester) RegexWithOptions(regex string, options *RegexCompletionSuggesterOptions) *CompletionSuggester {
82+
q.regex = regex
83+
q.regexOptions = options
84+
return q
85+
}
86+
87+
func (q *CompletionSuggester) RegexOptions(options *RegexCompletionSuggesterOptions) *CompletionSuggester {
88+
q.regexOptions = options
89+
return q
90+
}
91+
92+
func (q *CompletionSuggester) SkipDuplicates(skipDuplicates bool) *CompletionSuggester {
93+
q.skipDuplicates = &skipDuplicates
94+
return q
95+
}
96+
4097
func (q *CompletionSuggester) Field(field string) *CompletionSuggester {
4198
q.field = field
4299
return q
@@ -72,17 +129,25 @@ func (q *CompletionSuggester) ContextQueries(queries ...SuggesterContextQuery) *
72129
// We got into trouble when using plain maps because the text element
73130
// needs to go before the completion element.
74131
type completionSuggesterRequest struct {
75-
Text string `json:"text"`
76-
Completion interface{} `json:"completion"`
132+
Text string `json:"text,omitempty"`
133+
Prefix string `json:"prefix,omitempty"`
134+
Regex string `json:"regex,omitempty"`
135+
Completion interface{} `json:"completion,omitempty"`
77136
}
78137

79-
// Creates the source for the completion suggester.
138+
// Source creates the JSON data for the completion suggester.
80139
func (q *CompletionSuggester) Source(includeName bool) (interface{}, error) {
81140
cs := &completionSuggesterRequest{}
82141

83142
if q.text != "" {
84143
cs.Text = q.text
85144
}
145+
if q.prefix != "" {
146+
cs.Prefix = q.prefix
147+
}
148+
if q.regex != "" {
149+
cs.Regex = q.regex
150+
}
86151

87152
suggester := make(map[string]interface{})
88153
cs.Completion = suggester
@@ -126,6 +191,28 @@ func (q *CompletionSuggester) Source(includeName bool) (interface{}, error) {
126191
suggester["contexts"] = ctxq
127192
}
128193

194+
// Fuzzy options
195+
if q.fuzzyOptions != nil {
196+
src, err := q.fuzzyOptions.Source()
197+
if err != nil {
198+
return nil, err
199+
}
200+
suggester["fuzzy"] = src
201+
}
202+
203+
// Regex options
204+
if q.regexOptions != nil {
205+
src, err := q.regexOptions.Source()
206+
if err != nil {
207+
return nil, err
208+
}
209+
suggester["regex"] = src
210+
}
211+
212+
if q.skipDuplicates != nil {
213+
suggester["skip_duplicates"] = *q.skipDuplicates
214+
}
215+
129216
// TODO(oe) Add completion-suggester specific parameters here
130217

131218
if !includeName {
@@ -136,3 +223,130 @@ func (q *CompletionSuggester) Source(includeName bool) (interface{}, error) {
136223
source[q.name] = cs
137224
return source, nil
138225
}
226+
227+
// -- Fuzzy options --
228+
229+
// FuzzyCompletionSuggesterOptions represents the options for fuzzy completion suggester.
230+
type FuzzyCompletionSuggesterOptions struct {
231+
editDistance interface{}
232+
transpositions *bool
233+
minLength *int
234+
prefixLength *int
235+
unicodeAware *bool
236+
maxDeterminizedStates *int
237+
}
238+
239+
// NewFuzzyCompletionSuggesterOptions initializes a new FuzzyCompletionSuggesterOptions instance.
240+
func NewFuzzyCompletionSuggesterOptions() *FuzzyCompletionSuggesterOptions {
241+
return &FuzzyCompletionSuggesterOptions{}
242+
}
243+
244+
// EditDistance specifies the maximum number of edits, e.g. a number like "1" or "2"
245+
// or a string like "0..2" or ">5". See https://www.elastic.co/guide/en/elasticsearch/reference/5.6/common-options.html#fuzziness
246+
// for details.
247+
func (o *FuzzyCompletionSuggesterOptions) EditDistance(editDistance interface{}) *FuzzyCompletionSuggesterOptions {
248+
o.editDistance = editDistance
249+
return o
250+
}
251+
252+
// Transpositions, if set to true, are counted as one change instead of two (defaults to true).
253+
func (o *FuzzyCompletionSuggesterOptions) Transpositions(transpositions bool) *FuzzyCompletionSuggesterOptions {
254+
o.transpositions = &transpositions
255+
return o
256+
}
257+
258+
// MinLength represents the minimum length of the input before fuzzy suggestions are returned (defaults to 3).
259+
func (o *FuzzyCompletionSuggesterOptions) MinLength(minLength int) *FuzzyCompletionSuggesterOptions {
260+
o.minLength = &minLength
261+
return o
262+
}
263+
264+
// PrefixLength represents the minimum length of the input, which is not checked for
265+
// fuzzy alternatives (defaults to 1).
266+
func (o *FuzzyCompletionSuggesterOptions) PrefixLength(prefixLength int) *FuzzyCompletionSuggesterOptions {
267+
o.prefixLength = &prefixLength
268+
return o
269+
}
270+
271+
// UnicodeAware, if true, all measurements (like fuzzy edit distance, transpositions, and lengths)
272+
// are measured in Unicode code points instead of in bytes. This is slightly slower than
273+
// raw bytes, so it is set to false by default.
274+
func (o *FuzzyCompletionSuggesterOptions) UnicodeAware(unicodeAware bool) *FuzzyCompletionSuggesterOptions {
275+
o.unicodeAware = &unicodeAware
276+
return o
277+
}
278+
279+
// MaxDeterminizedStates is currently undocumented in Elasticsearch. It represents
280+
// the maximum automaton states allowed for fuzzy expansion.
281+
func (o *FuzzyCompletionSuggesterOptions) MaxDeterminizedStates(max int) *FuzzyCompletionSuggesterOptions {
282+
o.maxDeterminizedStates = &max
283+
return o
284+
}
285+
286+
// Source creates the JSON data.
287+
func (o *FuzzyCompletionSuggesterOptions) Source() (interface{}, error) {
288+
out := make(map[string]interface{})
289+
290+
if o.editDistance != nil {
291+
out["fuzziness"] = o.editDistance
292+
}
293+
if o.transpositions != nil {
294+
out["transpositions"] = *o.transpositions
295+
}
296+
if o.minLength != nil {
297+
out["min_length"] = *o.minLength
298+
}
299+
if o.prefixLength != nil {
300+
out["prefix_length"] = *o.prefixLength
301+
}
302+
if o.unicodeAware != nil {
303+
out["unicode_aware"] = *o.unicodeAware
304+
}
305+
if o.maxDeterminizedStates != nil {
306+
out["max_determinized_states"] = *o.maxDeterminizedStates
307+
}
308+
309+
return out, nil
310+
}
311+
312+
// -- Regex options --
313+
314+
// RegexCompletionSuggesterOptions represents the options for regex completion suggester.
315+
type RegexCompletionSuggesterOptions struct {
316+
flags interface{} // string or int
317+
maxDeterminizedStates *int
318+
}
319+
320+
// NewRegexCompletionSuggesterOptions initializes a new RegexCompletionSuggesterOptions instance.
321+
func NewRegexCompletionSuggesterOptions() *RegexCompletionSuggesterOptions {
322+
return &RegexCompletionSuggesterOptions{}
323+
}
324+
325+
// Flags represents internal regex flags. See https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-suggesters-completion.html#regex
326+
// for details.
327+
func (o *RegexCompletionSuggesterOptions) Flags(flags interface{}) *RegexCompletionSuggesterOptions {
328+
o.flags = flags
329+
return o
330+
}
331+
332+
// MaxDeterminizedStates represents the maximum automaton states allowed for regex expansion.
333+
// See https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-suggesters-completion.html#regex
334+
// for details.
335+
func (o *RegexCompletionSuggesterOptions) MaxDeterminizedStates(max int) *RegexCompletionSuggesterOptions {
336+
o.maxDeterminizedStates = &max
337+
return o
338+
}
339+
340+
// Source creates the JSON data.
341+
func (o *RegexCompletionSuggesterOptions) Source() (interface{}, error) {
342+
out := make(map[string]interface{})
343+
344+
if o.flags != nil {
345+
out["flags"] = o.flags
346+
}
347+
if o.maxDeterminizedStates != nil {
348+
out["max_determinized_states"] = *o.maxDeterminizedStates
349+
}
350+
351+
return out, nil
352+
}

0 commit comments

Comments
 (0)