1// Copyright 2012-2015 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 7import "errors" 8 9// CompletionSuggester is a fast suggester for e.g. type-ahead completion. 10// See http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-suggesters-completion.html 11// for more details. 12type CompletionSuggester struct { 13 Suggester 14 name string 15 text string 16 field string 17 analyzer string 18 size *int 19 shardSize *int 20 contextQueries []SuggesterContextQuery 21} 22 23// Creates a new completion suggester. 24func NewCompletionSuggester(name string) *CompletionSuggester { 25 return &CompletionSuggester{ 26 name: name, 27 contextQueries: make([]SuggesterContextQuery, 0), 28 } 29} 30 31func (q *CompletionSuggester) Name() string { 32 return q.name 33} 34 35func (q *CompletionSuggester) Text(text string) *CompletionSuggester { 36 q.text = text 37 return q 38} 39 40func (q *CompletionSuggester) Field(field string) *CompletionSuggester { 41 q.field = field 42 return q 43} 44 45func (q *CompletionSuggester) Analyzer(analyzer string) *CompletionSuggester { 46 q.analyzer = analyzer 47 return q 48} 49 50func (q *CompletionSuggester) Size(size int) *CompletionSuggester { 51 q.size = &size 52 return q 53} 54 55func (q *CompletionSuggester) ShardSize(shardSize int) *CompletionSuggester { 56 q.shardSize = &shardSize 57 return q 58} 59 60func (q *CompletionSuggester) ContextQuery(query SuggesterContextQuery) *CompletionSuggester { 61 q.contextQueries = append(q.contextQueries, query) 62 return q 63} 64 65func (q *CompletionSuggester) ContextQueries(queries ...SuggesterContextQuery) *CompletionSuggester { 66 q.contextQueries = append(q.contextQueries, queries...) 67 return q 68} 69 70// completionSuggesterRequest is necessary because the order in which 71// the JSON elements are routed to Elasticsearch is relevant. 72// We got into trouble when using plain maps because the text element 73// needs to go before the completion element. 74type completionSuggesterRequest struct { 75 Text string `json:"text"` 76 Completion interface{} `json:"completion"` 77} 78 79// Source creates the JSON structure for the completion suggester. 80func (q *CompletionSuggester) Source(includeName bool) (interface{}, error) { 81 cs := &completionSuggesterRequest{} 82 83 if q.text != "" { 84 cs.Text = q.text 85 } 86 87 suggester := make(map[string]interface{}) 88 cs.Completion = suggester 89 90 if q.analyzer != "" { 91 suggester["analyzer"] = q.analyzer 92 } 93 if q.field != "" { 94 suggester["field"] = q.field 95 } 96 if q.size != nil { 97 suggester["size"] = *q.size 98 } 99 if q.shardSize != nil { 100 suggester["shard_size"] = *q.shardSize 101 } 102 switch len(q.contextQueries) { 103 case 0: 104 case 1: 105 src, err := q.contextQueries[0].Source() 106 if err != nil { 107 return nil, err 108 } 109 suggester["context"] = src 110 default: 111 ctxq := make(map[string]interface{}) 112 for _, query := range q.contextQueries { 113 src, err := query.Source() 114 if err != nil { 115 return nil, err 116 } 117 // Merge the dictionary into ctxq 118 m, ok := src.(map[string]interface{}) 119 if !ok { 120 return nil, errors.New("elastic: context query is not a map") 121 } 122 for k, v := range m { 123 ctxq[k] = v 124 } 125 } 126 suggester["context"] = ctxq 127 } 128 129 // TODO(oe) Add completion-suggester specific parameters here 130 131 if !includeName { 132 return cs, nil 133 } 134 135 source := make(map[string]interface{}) 136 source[q.name] = cs 137 return source, nil 138} 139