count.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. "fmt"
  8. "net/url"
  9. "strings"
  10. "gopkg.in/olivere/elastic.v5/uritemplates"
  11. )
  12. // CountService is a convenient service for determining the
  13. // number of documents in an index. Use SearchService with
  14. // a SearchType of count for counting with queries etc.
  15. type CountService struct {
  16. client *Client
  17. pretty bool
  18. index []string
  19. typ []string
  20. allowNoIndices *bool
  21. analyzeWildcard *bool
  22. analyzer string
  23. defaultOperator string
  24. df string
  25. expandWildcards string
  26. ignoreUnavailable *bool
  27. lenient *bool
  28. lowercaseExpandedTerms *bool
  29. minScore interface{}
  30. preference string
  31. q string
  32. query Query
  33. routing string
  34. bodyJson interface{}
  35. bodyString string
  36. }
  37. // NewCountService creates a new CountService.
  38. func NewCountService(client *Client) *CountService {
  39. return &CountService{
  40. client: client,
  41. }
  42. }
  43. // Index sets the names of the indices to restrict the results.
  44. func (s *CountService) Index(index ...string) *CountService {
  45. if s.index == nil {
  46. s.index = make([]string, 0)
  47. }
  48. s.index = append(s.index, index...)
  49. return s
  50. }
  51. // Type sets the types to use to restrict the results.
  52. func (s *CountService) Type(typ ...string) *CountService {
  53. if s.typ == nil {
  54. s.typ = make([]string, 0)
  55. }
  56. s.typ = append(s.typ, typ...)
  57. return s
  58. }
  59. // AllowNoIndices indicates whether to ignore if a wildcard indices
  60. // expression resolves into no concrete indices. (This includes "_all" string
  61. // or when no indices have been specified).
  62. func (s *CountService) AllowNoIndices(allowNoIndices bool) *CountService {
  63. s.allowNoIndices = &allowNoIndices
  64. return s
  65. }
  66. // AnalyzeWildcard specifies whether wildcard and prefix queries should be
  67. // analyzed (default: false).
  68. func (s *CountService) AnalyzeWildcard(analyzeWildcard bool) *CountService {
  69. s.analyzeWildcard = &analyzeWildcard
  70. return s
  71. }
  72. // Analyzer specifies the analyzer to use for the query string.
  73. func (s *CountService) Analyzer(analyzer string) *CountService {
  74. s.analyzer = analyzer
  75. return s
  76. }
  77. // DefaultOperator specifies the default operator for query string query (AND or OR).
  78. func (s *CountService) DefaultOperator(defaultOperator string) *CountService {
  79. s.defaultOperator = defaultOperator
  80. return s
  81. }
  82. // Df specifies the field to use as default where no field prefix is given
  83. // in the query string.
  84. func (s *CountService) Df(df string) *CountService {
  85. s.df = df
  86. return s
  87. }
  88. // ExpandWildcards indicates whether to expand wildcard expression to
  89. // concrete indices that are open, closed or both.
  90. func (s *CountService) ExpandWildcards(expandWildcards string) *CountService {
  91. s.expandWildcards = expandWildcards
  92. return s
  93. }
  94. // IgnoreUnavailable indicates whether specified concrete indices should be
  95. // ignored when unavailable (missing or closed).
  96. func (s *CountService) IgnoreUnavailable(ignoreUnavailable bool) *CountService {
  97. s.ignoreUnavailable = &ignoreUnavailable
  98. return s
  99. }
  100. // Lenient specifies whether format-based query failures (such as
  101. // providing text to a numeric field) should be ignored.
  102. func (s *CountService) Lenient(lenient bool) *CountService {
  103. s.lenient = &lenient
  104. return s
  105. }
  106. // LowercaseExpandedTerms specifies whether query terms should be lowercased.
  107. func (s *CountService) LowercaseExpandedTerms(lowercaseExpandedTerms bool) *CountService {
  108. s.lowercaseExpandedTerms = &lowercaseExpandedTerms
  109. return s
  110. }
  111. // MinScore indicates to include only documents with a specific `_score`
  112. // value in the result.
  113. func (s *CountService) MinScore(minScore interface{}) *CountService {
  114. s.minScore = minScore
  115. return s
  116. }
  117. // Preference specifies the node or shard the operation should be
  118. // performed on (default: random).
  119. func (s *CountService) Preference(preference string) *CountService {
  120. s.preference = preference
  121. return s
  122. }
  123. // Q in the Lucene query string syntax. You can also use Query to pass
  124. // a Query struct.
  125. func (s *CountService) Q(q string) *CountService {
  126. s.q = q
  127. return s
  128. }
  129. // Query specifies the query to pass. You can also pass a query string with Q.
  130. func (s *CountService) Query(query Query) *CountService {
  131. s.query = query
  132. return s
  133. }
  134. // Routing specifies the routing value.
  135. func (s *CountService) Routing(routing string) *CountService {
  136. s.routing = routing
  137. return s
  138. }
  139. // Pretty indicates that the JSON response be indented and human readable.
  140. func (s *CountService) Pretty(pretty bool) *CountService {
  141. s.pretty = pretty
  142. return s
  143. }
  144. // BodyJson specifies the query to restrict the results specified with the
  145. // Query DSL (optional). The interface{} will be serialized to a JSON document,
  146. // so use a map[string]interface{}.
  147. func (s *CountService) BodyJson(body interface{}) *CountService {
  148. s.bodyJson = body
  149. return s
  150. }
  151. // Body specifies a query to restrict the results specified with
  152. // the Query DSL (optional).
  153. func (s *CountService) BodyString(body string) *CountService {
  154. s.bodyString = body
  155. return s
  156. }
  157. // buildURL builds the URL for the operation.
  158. func (s *CountService) buildURL() (string, url.Values, error) {
  159. var err error
  160. var path string
  161. if len(s.index) > 0 && len(s.typ) > 0 {
  162. path, err = uritemplates.Expand("/{index}/{type}/_count", map[string]string{
  163. "index": strings.Join(s.index, ","),
  164. "type": strings.Join(s.typ, ","),
  165. })
  166. } else if len(s.index) > 0 {
  167. path, err = uritemplates.Expand("/{index}/_count", map[string]string{
  168. "index": strings.Join(s.index, ","),
  169. })
  170. } else if len(s.typ) > 0 {
  171. path, err = uritemplates.Expand("/_all/{type}/_count", map[string]string{
  172. "type": strings.Join(s.typ, ","),
  173. })
  174. } else {
  175. path = "/_all/_count"
  176. }
  177. if err != nil {
  178. return "", url.Values{}, err
  179. }
  180. // Add query string parameters
  181. params := url.Values{}
  182. if s.pretty {
  183. params.Set("pretty", "1")
  184. }
  185. if s.allowNoIndices != nil {
  186. params.Set("allow_no_indices", fmt.Sprintf("%v", *s.allowNoIndices))
  187. }
  188. if s.analyzeWildcard != nil {
  189. params.Set("analyze_wildcard", fmt.Sprintf("%v", *s.analyzeWildcard))
  190. }
  191. if s.analyzer != "" {
  192. params.Set("analyzer", s.analyzer)
  193. }
  194. if s.defaultOperator != "" {
  195. params.Set("default_operator", s.defaultOperator)
  196. }
  197. if s.df != "" {
  198. params.Set("df", s.df)
  199. }
  200. if s.expandWildcards != "" {
  201. params.Set("expand_wildcards", s.expandWildcards)
  202. }
  203. if s.ignoreUnavailable != nil {
  204. params.Set("ignore_unavailable", fmt.Sprintf("%v", *s.ignoreUnavailable))
  205. }
  206. if s.lenient != nil {
  207. params.Set("lenient", fmt.Sprintf("%v", *s.lenient))
  208. }
  209. if s.lowercaseExpandedTerms != nil {
  210. params.Set("lowercase_expanded_terms", fmt.Sprintf("%v", *s.lowercaseExpandedTerms))
  211. }
  212. if s.minScore != nil {
  213. params.Set("min_score", fmt.Sprintf("%v", s.minScore))
  214. }
  215. if s.preference != "" {
  216. params.Set("preference", s.preference)
  217. }
  218. if s.q != "" {
  219. params.Set("q", s.q)
  220. }
  221. if s.routing != "" {
  222. params.Set("routing", s.routing)
  223. }
  224. return path, params, nil
  225. }
  226. // Validate checks if the operation is valid.
  227. func (s *CountService) Validate() error {
  228. return nil
  229. }
  230. // Do executes the operation.
  231. func (s *CountService) Do(ctx context.Context) (int64, error) {
  232. // Check pre-conditions
  233. if err := s.Validate(); err != nil {
  234. return 0, err
  235. }
  236. // Get URL for request
  237. path, params, err := s.buildURL()
  238. if err != nil {
  239. return 0, err
  240. }
  241. // Setup HTTP request body
  242. var body interface{}
  243. if s.query != nil {
  244. src, err := s.query.Source()
  245. if err != nil {
  246. return 0, err
  247. }
  248. query := make(map[string]interface{})
  249. query["query"] = src
  250. body = query
  251. } else if s.bodyJson != nil {
  252. body = s.bodyJson
  253. } else if s.bodyString != "" {
  254. body = s.bodyString
  255. }
  256. // Get HTTP response
  257. res, err := s.client.PerformRequest(ctx, "POST", path, params, body)
  258. if err != nil {
  259. return 0, err
  260. }
  261. // Return result
  262. ret := new(CountResponse)
  263. if err := s.client.decoder.Decode(res.Body, ret); err != nil {
  264. return 0, err
  265. }
  266. if ret != nil {
  267. return ret.Count, nil
  268. }
  269. return int64(0), nil
  270. }
  271. // CountResponse is the response of using the Count API.
  272. type CountResponse struct {
  273. Count int64 `json:"count"`
  274. Shards shardsInfo `json:"_shards,omitempty"`
  275. }