suggest.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. package elastic
  5. import (
  6. "context"
  7. "encoding/json"
  8. "fmt"
  9. "net/url"
  10. "strings"
  11. "gopkg.in/olivere/elastic.v5/uritemplates"
  12. )
  13. // SuggestService returns suggestions for text.
  14. // See https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-suggesters.html.
  15. type SuggestService struct {
  16. client *Client
  17. pretty bool
  18. routing string
  19. preference string
  20. index []string
  21. suggesters []Suggester
  22. }
  23. // NewSuggestService creates a new instance of SuggestService.
  24. func NewSuggestService(client *Client) *SuggestService {
  25. builder := &SuggestService{
  26. client: client,
  27. }
  28. return builder
  29. }
  30. // Index adds one or more indices to use for the suggestion request.
  31. func (s *SuggestService) Index(index ...string) *SuggestService {
  32. s.index = append(s.index, index...)
  33. return s
  34. }
  35. // Pretty asks Elasticsearch to return indented JSON.
  36. func (s *SuggestService) Pretty(pretty bool) *SuggestService {
  37. s.pretty = pretty
  38. return s
  39. }
  40. // Routing specifies the routing value.
  41. func (s *SuggestService) Routing(routing string) *SuggestService {
  42. s.routing = routing
  43. return s
  44. }
  45. // Preference specifies the node or shard the operation should be
  46. // performed on (default: random).
  47. func (s *SuggestService) Preference(preference string) *SuggestService {
  48. s.preference = preference
  49. return s
  50. }
  51. // Suggester adds a suggester to the request.
  52. func (s *SuggestService) Suggester(suggester Suggester) *SuggestService {
  53. s.suggesters = append(s.suggesters, suggester)
  54. return s
  55. }
  56. // buildURL builds the URL for the operation.
  57. func (s *SuggestService) buildURL() (string, url.Values, error) {
  58. var err error
  59. var path string
  60. if len(s.index) > 0 {
  61. path, err = uritemplates.Expand("/{index}/_suggest", map[string]string{
  62. "index": strings.Join(s.index, ","),
  63. })
  64. } else {
  65. path = "/_suggest"
  66. }
  67. if err != nil {
  68. return "", url.Values{}, err
  69. }
  70. // Add query string parameters
  71. params := url.Values{}
  72. if s.pretty {
  73. params.Set("pretty", fmt.Sprintf("%v", s.pretty))
  74. }
  75. if s.routing != "" {
  76. params.Set("routing", s.routing)
  77. }
  78. if s.preference != "" {
  79. params.Set("preference", s.preference)
  80. }
  81. return path, params, nil
  82. }
  83. // Do executes the request.
  84. func (s *SuggestService) Do(ctx context.Context) (SuggestResult, error) {
  85. path, params, err := s.buildURL()
  86. if err != nil {
  87. return nil, err
  88. }
  89. // Set body
  90. body := make(map[string]interface{})
  91. for _, s := range s.suggesters {
  92. src, err := s.Source(false)
  93. if err != nil {
  94. return nil, err
  95. }
  96. body[s.Name()] = src
  97. }
  98. // Get response
  99. res, err := s.client.PerformRequest(ctx, "POST", path, params, body)
  100. if err != nil {
  101. return nil, err
  102. }
  103. // There is a _shard object that cannot be deserialized.
  104. // So we use json.RawMessage instead.
  105. var suggestions map[string]*json.RawMessage
  106. if err := s.client.decoder.Decode(res.Body, &suggestions); err != nil {
  107. return nil, err
  108. }
  109. ret := make(SuggestResult)
  110. for name, result := range suggestions {
  111. if name != "_shards" {
  112. var sug []Suggestion
  113. if err := s.client.decoder.Decode(*result, &sug); err != nil {
  114. return nil, err
  115. }
  116. ret[name] = sug
  117. }
  118. }
  119. return ret, nil
  120. }
  121. // SuggestResult is the outcome of SuggestService.Do.
  122. type SuggestResult map[string][]Suggestion
  123. // Suggestion is a single suggester outcome.
  124. type Suggestion struct {
  125. Text string `json:"text"`
  126. Offset int `json:"offset"`
  127. Length int `json:"length"`
  128. Options []suggestionOption `json:"options"`
  129. }
  130. type suggestionOption struct {
  131. Text string `json:"text"`
  132. Score float64 `json:"score"`
  133. Freq int `json:"freq"`
  134. Payload interface{} `json:"payload"`
  135. CollateMatch bool `json:"collate_match"`
  136. }