scroll.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. package elastic
  5. import (
  6. "encoding/json"
  7. "fmt"
  8. "net/url"
  9. "strings"
  10. "github.com/olivere/elastic/uritemplates"
  11. )
  12. // ScrollService manages a cursor through documents in Elasticsearch.
  13. type ScrollService struct {
  14. client *Client
  15. indices []string
  16. types []string
  17. keepAlive string
  18. query Query
  19. size *int
  20. pretty bool
  21. scrollId string
  22. }
  23. func NewScrollService(client *Client) *ScrollService {
  24. builder := &ScrollService{
  25. client: client,
  26. query: NewMatchAllQuery(),
  27. }
  28. return builder
  29. }
  30. func (s *ScrollService) Index(index string) *ScrollService {
  31. if s.indices == nil {
  32. s.indices = make([]string, 0)
  33. }
  34. s.indices = append(s.indices, index)
  35. return s
  36. }
  37. func (s *ScrollService) Indices(indices ...string) *ScrollService {
  38. if s.indices == nil {
  39. s.indices = make([]string, 0)
  40. }
  41. s.indices = append(s.indices, indices...)
  42. return s
  43. }
  44. func (s *ScrollService) Type(typ string) *ScrollService {
  45. if s.types == nil {
  46. s.types = make([]string, 0)
  47. }
  48. s.types = append(s.types, typ)
  49. return s
  50. }
  51. func (s *ScrollService) Types(types ...string) *ScrollService {
  52. if s.types == nil {
  53. s.types = make([]string, 0)
  54. }
  55. s.types = append(s.types, types...)
  56. return s
  57. }
  58. // Scroll is an alias for KeepAlive, the time to keep
  59. // the cursor alive (e.g. "5m" for 5 minutes).
  60. func (s *ScrollService) Scroll(keepAlive string) *ScrollService {
  61. s.keepAlive = keepAlive
  62. return s
  63. }
  64. // KeepAlive sets the maximum time the cursor will be
  65. // available before expiration (e.g. "5m" for 5 minutes).
  66. func (s *ScrollService) KeepAlive(keepAlive string) *ScrollService {
  67. s.keepAlive = keepAlive
  68. return s
  69. }
  70. func (s *ScrollService) Query(query Query) *ScrollService {
  71. s.query = query
  72. return s
  73. }
  74. func (s *ScrollService) Pretty(pretty bool) *ScrollService {
  75. s.pretty = pretty
  76. return s
  77. }
  78. func (s *ScrollService) Size(size int) *ScrollService {
  79. s.size = &size
  80. return s
  81. }
  82. func (s *ScrollService) ScrollId(scrollId string) *ScrollService {
  83. s.scrollId = scrollId
  84. return s
  85. }
  86. func (s *ScrollService) Do() (*SearchResult, error) {
  87. if s.scrollId == "" {
  88. return s.GetFirstPage()
  89. }
  90. return s.GetNextPage()
  91. }
  92. func (s *ScrollService) GetFirstPage() (*SearchResult, error) {
  93. // Build url
  94. path := "/"
  95. // Indices part
  96. indexPart := make([]string, 0)
  97. for _, index := range s.indices {
  98. index, err := uritemplates.Expand("{index}", map[string]string{
  99. "index": index,
  100. })
  101. if err != nil {
  102. return nil, err
  103. }
  104. indexPart = append(indexPart, index)
  105. }
  106. if len(indexPart) > 0 {
  107. path += strings.Join(indexPart, ",")
  108. }
  109. // Types
  110. typesPart := make([]string, 0)
  111. for _, typ := range s.types {
  112. typ, err := uritemplates.Expand("{type}", map[string]string{
  113. "type": typ,
  114. })
  115. if err != nil {
  116. return nil, err
  117. }
  118. typesPart = append(typesPart, typ)
  119. }
  120. if len(typesPart) > 0 {
  121. path += "/" + strings.Join(typesPart, ",")
  122. }
  123. // Search
  124. path += "/_search"
  125. // Parameters
  126. params := make(url.Values)
  127. params.Set("search_type", "scan")
  128. if s.pretty {
  129. params.Set("pretty", fmt.Sprintf("%v", s.pretty))
  130. }
  131. if s.keepAlive != "" {
  132. params.Set("scroll", s.keepAlive)
  133. } else {
  134. params.Set("scroll", defaultKeepAlive)
  135. }
  136. if s.size != nil && *s.size > 0 {
  137. params.Set("size", fmt.Sprintf("%d", *s.size))
  138. }
  139. // Set body
  140. body := make(map[string]interface{})
  141. if s.query != nil {
  142. body["query"] = s.query.Source()
  143. }
  144. // Get response
  145. res, err := s.client.PerformRequest("POST", path, params, body)
  146. if err != nil {
  147. return nil, err
  148. }
  149. // Return result
  150. searchResult := new(SearchResult)
  151. if err := json.Unmarshal(res.Body, searchResult); err != nil {
  152. return nil, err
  153. }
  154. return searchResult, nil
  155. }
  156. func (s *ScrollService) GetNextPage() (*SearchResult, error) {
  157. if s.scrollId == "" {
  158. return nil, EOS
  159. }
  160. // Build url
  161. path := "/_search/scroll"
  162. // Parameters
  163. params := make(url.Values)
  164. if s.pretty {
  165. params.Set("pretty", fmt.Sprintf("%v", s.pretty))
  166. }
  167. if s.keepAlive != "" {
  168. params.Set("scroll", s.keepAlive)
  169. } else {
  170. params.Set("scroll", defaultKeepAlive)
  171. }
  172. // Get response
  173. res, err := s.client.PerformRequest("POST", path, params, s.scrollId)
  174. if err != nil {
  175. return nil, err
  176. }
  177. // Return result
  178. searchResult := new(SearchResult)
  179. if err := json.Unmarshal(res.Body, searchResult); err != nil {
  180. return nil, err
  181. }
  182. // Determine last page
  183. if searchResult == nil || searchResult.Hits == nil || len(searchResult.Hits.Hits) == 0 || searchResult.Hits.TotalHits == 0 {
  184. return nil, EOS
  185. }
  186. return searchResult, nil
  187. }