elastic-site-search 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +58 -0
  3. data/.gitignore +10 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +201 -0
  7. data/NOTICE.txt +3 -0
  8. data/README.md +418 -0
  9. data/Rakefile +1 -0
  10. data/elastic-site-search.gemspec +26 -0
  11. data/lib/data/ca-bundle.crt +3554 -0
  12. data/lib/elastic/site-search.rb +9 -0
  13. data/lib/elastic/site-search/client.rb +527 -0
  14. data/lib/elastic/site-search/configuration.rb +67 -0
  15. data/lib/elastic/site-search/exceptions.rb +11 -0
  16. data/lib/elastic/site-search/ext/backport-uri.rb +33 -0
  17. data/lib/elastic/site-search/request.rb +156 -0
  18. data/lib/elastic/site-search/result_set.rb +84 -0
  19. data/lib/elastic/site-search/sso.rb +22 -0
  20. data/lib/elastic/site-search/version.rb +5 -0
  21. data/logo-site-search.png +0 -0
  22. data/spec/client_spec.rb +728 -0
  23. data/spec/configuration_spec.rb +37 -0
  24. data/spec/fixtures/vcr/analytics_autoselects.yml +57 -0
  25. data/spec/fixtures/vcr/analytics_autoselects_with_document_type.yml +57 -0
  26. data/spec/fixtures/vcr/analytics_autoselects_with_document_type_and_time_range.yml +57 -0
  27. data/spec/fixtures/vcr/analytics_autoselects_with_time_range.yml +57 -0
  28. data/spec/fixtures/vcr/analytics_clicks.yml +57 -0
  29. data/spec/fixtures/vcr/analytics_clicks_with_document_type.yml +57 -0
  30. data/spec/fixtures/vcr/analytics_clicks_with_document_type_and_time_range.yml +57 -0
  31. data/spec/fixtures/vcr/analytics_clicks_with_time_range.yml +57 -0
  32. data/spec/fixtures/vcr/analytics_searches.yml +57 -0
  33. data/spec/fixtures/vcr/analytics_searches_with_document_type_and_time_range.yml +57 -0
  34. data/spec/fixtures/vcr/analytics_searches_with_time_range.yml +57 -0
  35. data/spec/fixtures/vcr/analytics_searchs_with_document_type.yml +57 -0
  36. data/spec/fixtures/vcr/analytics_top_no_result_queries.yml +57 -0
  37. data/spec/fixtures/vcr/analytics_top_no_result_queries_paginated.yml +57 -0
  38. data/spec/fixtures/vcr/analytics_top_queries.yml +57 -0
  39. data/spec/fixtures/vcr/analytics_top_queries_paginated.yml +57 -0
  40. data/spec/fixtures/vcr/analytics_top_queries_too_large.yml +53 -0
  41. data/spec/fixtures/vcr/async_create_or_update_document_failure.yml +48 -0
  42. data/spec/fixtures/vcr/async_create_or_update_document_success.yml +52 -0
  43. data/spec/fixtures/vcr/bulk_create_documents.yml +52 -0
  44. data/spec/fixtures/vcr/bulk_create_or_update_documents_failure.yml +47 -0
  45. data/spec/fixtures/vcr/bulk_create_or_update_documents_success.yml +52 -0
  46. data/spec/fixtures/vcr/bulk_create_or_update_documents_verbose_failure.yml +47 -0
  47. data/spec/fixtures/vcr/bulk_create_or_update_documents_verbose_success.yml +52 -0
  48. data/spec/fixtures/vcr/bulk_destroy_documents.yml +47 -0
  49. data/spec/fixtures/vcr/crawl_url.yml +47 -0
  50. data/spec/fixtures/vcr/create_document.yml +52 -0
  51. data/spec/fixtures/vcr/create_document_type.yml +47 -0
  52. data/spec/fixtures/vcr/create_domain.yml +47 -0
  53. data/spec/fixtures/vcr/create_engine.yml +47 -0
  54. data/spec/fixtures/vcr/create_or_update_document_create.yml +51 -0
  55. data/spec/fixtures/vcr/create_or_update_document_update.yml +51 -0
  56. data/spec/fixtures/vcr/create_user.yml +47 -0
  57. data/spec/fixtures/vcr/destroy_document.yml +43 -0
  58. data/spec/fixtures/vcr/destroy_document_type.yml +43 -0
  59. data/spec/fixtures/vcr/destroy_domain.yml +43 -0
  60. data/spec/fixtures/vcr/destroy_engine.yml +43 -0
  61. data/spec/fixtures/vcr/destroy_non_existent_document_type.yml +45 -0
  62. data/spec/fixtures/vcr/document_receipts_multiple.yml +48 -0
  63. data/spec/fixtures/vcr/document_receipts_multiple_complete.yml +48 -0
  64. data/spec/fixtures/vcr/document_type_search.yml +63 -0
  65. data/spec/fixtures/vcr/document_type_search_pagination.yml +47 -0
  66. data/spec/fixtures/vcr/document_type_suggest.yml +52 -0
  67. data/spec/fixtures/vcr/document_type_suggest_pagination.yml +47 -0
  68. data/spec/fixtures/vcr/engine_search.yml +67 -0
  69. data/spec/fixtures/vcr/engine_search_facets.yml +164 -0
  70. data/spec/fixtures/vcr/engine_search_pagination.yml +47 -0
  71. data/spec/fixtures/vcr/engine_suggest.yml +55 -0
  72. data/spec/fixtures/vcr/engine_suggest_pagination.yml +47 -0
  73. data/spec/fixtures/vcr/find_document.yml +50 -0
  74. data/spec/fixtures/vcr/find_document_type.yml +47 -0
  75. data/spec/fixtures/vcr/find_domain.yml +47 -0
  76. data/spec/fixtures/vcr/find_domain_failure.yml +45 -0
  77. data/spec/fixtures/vcr/find_engine.yml +47 -0
  78. data/spec/fixtures/vcr/list_document_type.yml +47 -0
  79. data/spec/fixtures/vcr/list_documents.yml +71 -0
  80. data/spec/fixtures/vcr/list_documents_with_pagination.yml +71 -0
  81. data/spec/fixtures/vcr/list_domains.yml +47 -0
  82. data/spec/fixtures/vcr/list_engines.yml +48 -0
  83. data/spec/fixtures/vcr/list_users.yml +47 -0
  84. data/spec/fixtures/vcr/list_users_with_pagination.yml +47 -0
  85. data/spec/fixtures/vcr/log_clickthrough_failure.yml +45 -0
  86. data/spec/fixtures/vcr/log_clickthrough_success.yml +47 -0
  87. data/spec/fixtures/vcr/recrawl_domain_failure.yml +46 -0
  88. data/spec/fixtures/vcr/recrawl_domain_success.yml +47 -0
  89. data/spec/fixtures/vcr/show_user.yml +47 -0
  90. data/spec/fixtures/vcr/update_document.yml +50 -0
  91. data/spec/fixtures/vcr/update_document_unknown_field_failure.yml +48 -0
  92. data/spec/fixtures/vcr/update_documents_failure_non_existent_document.yml +47 -0
  93. data/spec/fixtures/vcr/update_documents_success.yml +47 -0
  94. data/spec/fixtures/vcr/users_client_secret_incorrect.yml +44 -0
  95. data/spec/fixtures/vcr/users_no_api_key.yml +44 -0
  96. data/spec/fixtures/vcr/users_no_client_id_or_secret.yml +45 -0
  97. data/spec/platform_spec.rb +95 -0
  98. data/spec/spec_helper.rb +27 -0
  99. data/spec/ssl_spec.rb +34 -0
  100. data/spec/sso_spec.rb +24 -0
  101. metadata +279 -0
@@ -0,0 +1,9 @@
1
+ require 'elastic/site-search/client'
2
+ require 'elastic/site-search/sso'
3
+
4
+ module Elastic
5
+ module SiteSearch
6
+ extend Elastic::SiteSearch::Configuration
7
+ end
8
+ end
9
+
@@ -0,0 +1,527 @@
1
+ require 'elastic/site-search/configuration'
2
+ require 'elastic/site-search/result_set'
3
+ require 'elastic/site-search/request'
4
+
5
+ module Elastic
6
+ module SiteSearch
7
+ # API client for the {Elastic Site Search API}[https://www.elastic.co/products/site-search/service].
8
+ class Client
9
+ DEFAULT_TIMEOUT = 15
10
+
11
+ include Elastic::SiteSearch::Request
12
+
13
+ # Create a new Elastic::SiteSearch::Client client
14
+ #
15
+ # @param options [Hash] a hash of configuration options that will override what is set on the Elastic::SiteSearch class.
16
+ # @option options [String] :api_key an API Key to use for this client
17
+ # @option options [String] :platform_access_token a user's access token, will be used instead of API key for authenticating requests
18
+ # @option options [Numeric] :overall_timeout overall timeout for requests in seconds (default: 15s)
19
+ # @option options [Numeric] :open_timeout the number of seconds Net::HTTP (default: 15s)
20
+ # @option options [String] :proxy url of proxy to use, ex: "http://localhost:8888"
21
+ # will wait while opening a connection before raising a Timeout::Error
22
+
23
+ def initialize(options={})
24
+ @options = options
25
+ end
26
+
27
+ def api_key
28
+ @options[:api_key] || Elastic::SiteSearch.api_key
29
+ end
30
+
31
+ def platform_access_token
32
+ @options[:platform_access_token]
33
+ end
34
+
35
+ def proxy
36
+ @options[:proxy]
37
+ end
38
+
39
+ def open_timeout
40
+ @options[:open_timeout] || DEFAULT_TIMEOUT
41
+ end
42
+
43
+ def overall_timeout
44
+ (@options[:overall_timeout] || DEFAULT_TIMEOUT).to_f
45
+ end
46
+
47
+ def wrap(element)
48
+ [element].flatten(1)
49
+ end
50
+
51
+ # Methods wrapping the Elastic::SiteSearch private search and API endpoints. Using these methods, you can perform full-text
52
+ # and prefix searches over the Documents in your Engine, in a specific DocumentType, or any subset of DocumentTypes.
53
+ # You can also filter results and get faceted counts for results.
54
+ #
55
+ # For more information, visit the {REST API documentation on searching}[https://swiftype.com/documentation/site-search/searching].
56
+ module Search
57
+ # Perform an autocomplete (prefix) search over all the DocumentTypes of the provided engine.
58
+ # This can be used to implement type-ahead autocompletion. However, if your data is not sensitive,
59
+ # you should consider using the {Site Search public JSONP API}[https://swiftype.com/documentation/site-search/searching#public_search]
60
+ # in the user's web browser for suggest queries.
61
+ #
62
+ # results = client.suggest("site-search-api-example", "gla")
63
+ # results['videos'] # => [{'external_id' => 'v1uyQZNg2vE', 'title' => 'How It Feels [through Glass]', ...}, ...]
64
+ #
65
+ # @param [String] engine_id the Engine slug or ID
66
+ # @param [String] query the search terms
67
+ # @param [Hash] options search options (see {the REST API docs}[https://swiftype.com/documentation/site-search/searching] for a complete list)
68
+ # @option options [Integer] :page page number of results to fetch (server defaults to 1)
69
+ # @option options [Integer] :per_page number of results per page (server defaults to 20)
70
+ # @option options [Array] :document_types an array of DocumentType slugs to search.
71
+ # The server defaults to searching all DocumentTypes in the engine. To search a single document type,
72
+ # the +suggest_document_type+ method is more convenient.
73
+ # @option options [Hash] :fetch_fields a Hash of DocumentType slug to array of the fields to return with results
74
+ # (example: <code>{'videos' => ['title', 'channel_id']}</code>)
75
+ # @option options [Hash] :search_fields a Hash of DocumentType slug to array of the fields to search.
76
+ # May contain {field weight boosts}[https://swiftype.com/documentation/site-search/searching/field-weights]
77
+ # (example: <code>{'videos' => ['title^5', 'tags^2', 'caption']}</code>).
78
+ # The server defaults to searching all +string+ fields for suggest queries.
79
+ # @option options [Hash] :filters a Hash of DocumentType slug to filter definition Hash.
80
+ # See {filters in the REST API documentation}[https://swiftype.com/documentation/site-search/searching/filtering] for more details
81
+ # (example: <code>{'videos' => {'category_id' => ['23', '25']}}</code>)
82
+ # @option options [Hash] :functional_boosts a Hash of DocumentType slug to {functional boost}[https://swiftype.com/documentation/site-search/searching/boosting] definition
83
+ # (example: <code>{'videos' => {'view_count' => 'logarithmic'}}</code>).
84
+ # @option options [Hash] :sort_field a Hash of DocumentType slug to field name to sort on
85
+ # (example: <code>{'videos' => 'view_count'}</code>)
86
+ # @option options [Hash] :sort_direction a Hash of DocumentType slug to direction to sort
87
+ # (example: <code>'videos' => 'desc'</code>). Usually used with +:sort_field+.
88
+ #
89
+ # @return [Elastic::SiteSearch::ResultSet]
90
+ def suggest(engine_id, query, options={})
91
+ search_params = { :q => query }.merge(options)
92
+ response = post("engines/#{engine_id}/suggest.json", search_params)
93
+ ResultSet.new(response)
94
+ end
95
+
96
+ # Perform a full-text search over all the DocumentTypes of the provided engine.
97
+ #
98
+ # results = client.search("site-search-api-example", "glass")
99
+ # results['videos'] # => [{'external_id' => 'v1uyQZNg2vE', 'title' => 'How It Feels [through Glass]', ...}, ...]
100
+ #
101
+ # @param [String] engine_id the Engine slug or ID
102
+ # @param [String] query the search terms (may be nil)
103
+ # @param [Hash] options search options (see {the REST API docs}[https://swiftype.com/documentation/site-search/searching] for a complete list)
104
+ # @option options [Integer] :page page number of results to fetch (server defaults to 1)
105
+ # @option options [Integer] :per_page number of results per page (server defaults to 20)
106
+ # @option options [Array] :document_types an array of DocumentType slugs to search.
107
+ # The server defaults to searching all DocumentTypes in the engine. To search a single document type,
108
+ # the +search_document_type+ method is more convenient.
109
+ # @option options [Hash] :fetch_fields a Hash of DocumentType slug to array of the fields to return with results
110
+ # (example: <code>{'videos' => ['title', 'channel_id']}</code>)
111
+ # @option options [Hash] :search_fields a Hash of DocumentType slug to array of the fields to search.
112
+ # May contain {field weight boosts}[https://swiftype.com/documentation/site-search/searching/field-weights]
113
+ # (example: <code>{'videos' => ['title^5', 'tags^2', 'caption']}</code>).
114
+ # The server defaults to searching all +string+ and +text+ fields for search queries.
115
+ # @option options [Hash] :filters a Hash of DocumentType slug to filter definition Hash.
116
+ # See {filters in the REST API documentation}[https://swiftype.com/documentation/site-search/searching/filtering] for more details
117
+ # (example: <code>{'videos' => {'category_id' => ['23', '25']}}</code>)
118
+ # @option options [Hash] :functional_boosts a Hash of DocumentType slug to {functional boost}[https://swiftype.com/documentation/site-search/searching/boosting] definition
119
+ # (example: <code>{'videos' => {'view_count' => 'logarithmic'}}</code>).
120
+ # @option options [Hash] :facets a Hash of DocumentType slug to an Array of field names to provide facetted counts for
121
+ # (example: <code>{'videos' => ['category_id', 'channel_id']}</code>)
122
+ # @option options [Hash] :sort_field a Hash of DocumentType slug to field name to sort on
123
+ # (example: <code>{'videos' => 'view_count'}</code>)
124
+ # @option options [Hash] :sort_direction a Hash of DocumentType slug to direction to sort
125
+ # (example: <code>'videos' => 'desc'</code>). Usually used with +:sort_field+.
126
+ #
127
+ # @return [Elastic::SiteSearch::ResultSet]
128
+ def search(engine_id, query, options={})
129
+ search_params = { :q => query }.merge(options)
130
+ response = post("engines/#{engine_id}/search.json", search_params)
131
+ ResultSet.new(response)
132
+ end
133
+
134
+ # Perform an autocomplete (prefix) search over a single DocumentType in an Engine.
135
+ # This can be used to implement type-ahead autocompletion. However, if your data is not sensitive,
136
+ # you should consider using the {Site Search public JSONP API}[https://swiftype.com/documentation/site-search/searching#public_search]
137
+ # in the user's web browser for suggest queries.
138
+ #
139
+ # results = client.suggest_document_type("site-search-api-example", "videos", "gla")
140
+ # results['videos'] # => [{'external_id' => 'v1uyQZNg2vE', 'title' => 'How It Feels [through Glass]', ...}, ...]
141
+ #
142
+ # @param [String] engine_id the Engine slug or ID
143
+ # @param [String] query the search terms
144
+ # @param [Hash] options search options (see {the REST API docs}[https://swiftype.com/documentation/site-search/searching] for a complete list)
145
+ # @option options [Integer] :page page number of results to fetch (server defaults to 1)
146
+ # @option options [Integer] :per_page number of results per page (server defaults to 20)
147
+ # @option options [Array] :document_types an array of DocumentType slugs to search.
148
+ # The server defaults to searching all DocumentTypes in the engine. To search a single document type,
149
+ # the +suggest_document_type+ method is more convenient.
150
+ # @option options [Hash] :fetch_fields a Hash of DocumentType slug to array of the fields to return with results
151
+ # (example: <code>{'videos' => ['title', 'channel_id']}</code>)
152
+ # @option options [Hash] :search_fields a Hash of DocumentType slug to array of the fields to search.
153
+ # May contain {field weight boosts}[https://swiftype.com/documentation/site-search/searching/field-weights]
154
+ # (example: <code>{'videos' => ['title^5', 'tags^2', 'caption']}</code>).
155
+ # The server defaults to searching all +string+ fields for suggest queries.
156
+ # @option options [Hash] :filters a Hash of DocumentType slug to filter definition Hash.
157
+ # See {filters in the REST API documentation}[https://swiftype.com/documentation/site-search/searching/filtering] for more details
158
+ # (example: <code>{'videos' => {'category_id' => ['23', '25']}}</code>)
159
+ # @option options [Hash] :functional_boosts a Hash of DocumentType slug to {functional boost}[https://swiftype.com/documentation/site-search/searching/boosting] definition
160
+ # (example: <code>{'videos' => {'view_count' => 'logarithmic'}}</code>).
161
+ # @option options [Hash] :sort_field a Hash of DocumentType slug to field name to sort on
162
+ # (example: <code>{'videos' => 'view_count'}</code>)
163
+ # @option options [Hash] :sort_direction a Hash of DocumentType slug to direction to sort
164
+ # (example: <code>'videos' => 'desc'</code>). Usually used with +:sort_field+.
165
+ #
166
+ # @return [Elastic::SiteSearch::ResultSet]
167
+ def suggest_document_type(engine_id, document_type_id, query, options={})
168
+ search_params = { :q => query }.merge(options)
169
+ response = post("engines/#{engine_id}/document_types/#{document_type_id}/suggest.json", search_params)
170
+ ResultSet.new(response)
171
+ end
172
+
173
+ # Perform a full-text search over a single DocumentType in an Engine.
174
+ #
175
+ # results = client.search_document_type("site-search-api-example", "videos", "glass")
176
+ # results['videos'] # => [{'external_id' => 'v1uyQZNg2vE', 'title' => 'How It Feels [through Glass]', ...}, ...]
177
+ #
178
+ # @param [String] engine_id the Engine slug or ID
179
+ # @param [String] document_type_id the DocumentType slug or ID
180
+ # @param [String] query the search terms (may be nil)
181
+ # @param [Hash] options search options (see {the REST API docs}[https://swiftype.com/documentation/site-search/searching] for a complete list)
182
+ # @option options [Integer] :page page number of results to fetch (server defaults to 1)
183
+ # @option options [Integer] :per_page number of results per page (server defaults to 20)
184
+ # @option options [Hash] :fetch_fields a Hash of DocumentType slug to array of the fields to return with results
185
+ # (example: <code>{'videos' => ['title', 'channel_id']}</code>)
186
+ # @option options [Hash] :search_fields a Hash of DocumentType slug to array of the fields to search.
187
+ # May contain {field weight boosts}[https://swiftype.com/documentation/site-search/searching/field-weights]
188
+ # (example: <code>{'videos' => ['title^5', 'tags^2', 'caption']}</code>).
189
+ # The server defaults to searching all +string+ and +text+ fields for search queries.
190
+ # @option options [Hash] :filters a Hash of DocumentType slug to filter definition Hash.
191
+ # See {filters in the REST API documentation}[https://swiftype.com/documentation/site-search/searching/filtering] for more details
192
+ # (example: <code>{'videos' => {'category_id' => ['23', '25']}}</code>)
193
+ # @option options [Hash] :functional_boosts a Hash of DocumentType slug to {functional boost}[https://swiftype.com/documentation/site-search/searching/boosting] definition
194
+ # (example: <code>{'videos' => {'view_count' => 'logarithmic'}}</code>).
195
+ # @option options [Hash] :facets a Hash of DocumentType slug to an Array of field names to provide facetted counts for
196
+ # (example: <code>{'videos' => ['category_id', 'channel_id']}</code>)
197
+ # @option options [Hash] :sort_field a Hash of DocumentType slug to field name to sort on
198
+ # (example: <code>{'videos' => 'view_count'}</code>)
199
+ # @option options [Hash] :sort_direction a Hash of DocumentType slug to direction to sort
200
+ # (example: <code>'videos' => 'desc'</code>). Usually used with +:sort_field+.
201
+ #
202
+ # @return [Elastic::SiteSearch::ResultSet]
203
+ def search_document_type(engine_id, document_type_id, query, options={})
204
+ search_params = { :q => query }.merge(options)
205
+ response = post("engines/#{engine_id}/document_types/#{document_type_id}/search.json", search_params)
206
+ ResultSet.new(response)
207
+ end
208
+ end
209
+
210
+ module User
211
+ # List users for the configured application.
212
+ #
213
+ # @param options [Hash]
214
+ # @option options [Integer] :page page number of users to fetch (server defaults to 1)
215
+ # @option options [Integer] :per_page users to return per page (server defaults to 50)
216
+ def users(options={})
217
+ params = {
218
+ :client_id => Elastic::SiteSearch.platform_client_id,
219
+ :client_secret => Elastic::SiteSearch.platform_client_secret
220
+ }
221
+ get("users.json", params.merge(options))
222
+ end
223
+
224
+ # Create a new user for the configured application.
225
+ def create_user
226
+ params = {
227
+ :client_id => Elastic::SiteSearch.platform_client_id,
228
+ :client_secret => Elastic::SiteSearch.platform_client_secret
229
+ }
230
+ post("users.json", params)
231
+ end
232
+
233
+ # Return a user created by the configured application.
234
+ #
235
+ # @param user_id [String] the Site Search User ID
236
+ def user(user_id)
237
+ params = {
238
+ :client_id => Elastic::SiteSearch.platform_client_id,
239
+ :client_secret => Elastic::SiteSearch.platform_client_secret
240
+ }
241
+ get("users/#{user_id}.json", params)
242
+ end
243
+ end
244
+
245
+ # An Engine is a search engine that lets you search and filter the Documents it contains.
246
+ # For more information, see the {REST API overview}[https://swiftype.com/documentation/site-search/overview].
247
+ module Engine
248
+ def engines
249
+ get("engines.json")
250
+ end
251
+
252
+ def engine(engine_id)
253
+ get("engines/#{engine_id}.json")
254
+ end
255
+
256
+ def create_engine(name)
257
+ post("engines.json", :engine => {:name => name})
258
+ end
259
+
260
+ def destroy_engine(engine_id)
261
+ delete("engines/#{engine_id}.json")
262
+ end
263
+ end
264
+
265
+ # Every Document must belong to a DocumentType. For more information, see the {REST API overview}[https://swiftype.com/documentation/site-search/overview].
266
+ module DocumentType
267
+ def document_types(engine_id)
268
+ get("engines/#{engine_id}/document_types.json")
269
+ end
270
+
271
+ def document_type(engine_id, document_type_id)
272
+ get("engines/#{engine_id}/document_types/#{document_type_id}.json")
273
+ end
274
+
275
+ def create_document_type(engine_id, name)
276
+ post("engines/#{engine_id}/document_types.json", :document_type => {:name => name})
277
+ end
278
+
279
+ def destroy_document_type(engine_id, document_type_id)
280
+ delete("engines/#{engine_id}/document_types/#{document_type_id}.json")
281
+ end
282
+ end
283
+
284
+ # Documents have fields that can be searched or filtered.
285
+ #
286
+ # For more information on indexing documents, see the {REST API indexing documentation}[https://swiftype.com/documentation/site-search/indexing].
287
+ module Document
288
+ def documents(engine_id, document_type_id, page=nil, per_page=nil)
289
+ options = {}
290
+ options[:page] = page if page
291
+ options[:per_page] = per_page if per_page
292
+ get("engines/#{engine_id}/document_types/#{document_type_id}/documents.json", options)
293
+ end
294
+
295
+ def document(engine_id, document_type_id, document_id)
296
+ get("engines/#{engine_id}/document_types/#{document_type_id}/documents/#{document_id}.json")
297
+ end
298
+
299
+ def create_document(engine_id, document_type_id, document={})
300
+ post("engines/#{engine_id}/document_types/#{document_type_id}/documents.json", :document => document)
301
+ end
302
+
303
+ def create_documents(engine_id, document_type_id, documents=[])
304
+ post("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_create.json", :documents => documents)
305
+ end
306
+
307
+ def destroy_document(engine_id, document_type_id, document_id)
308
+ delete("engines/#{engine_id}/document_types/#{document_type_id}/documents/#{document_id}.json")
309
+ end
310
+
311
+ def destroy_documents(engine_id, document_type_id, document_ids=[])
312
+ post("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_destroy.json", :documents => document_ids)
313
+ end
314
+
315
+ def create_or_update_document(engine_id, document_type_id, document={})
316
+ post("engines/#{engine_id}/document_types/#{document_type_id}/documents/create_or_update.json", :document => document)
317
+ end
318
+
319
+ def create_or_update_documents(engine_id, document_type_id, documents=[])
320
+ post("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_create_or_update.json", :documents => documents)
321
+ end
322
+
323
+ def create_or_update_documents_verbose(engine_id, document_type_id, documents=[])
324
+ post("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_create_or_update_verbose.json", :documents => documents)
325
+ end
326
+
327
+ def update_document(engine_id, document_type_id, document_id, fields)
328
+ put("engines/#{engine_id}/document_types/#{document_type_id}/documents/#{document_id}/update_fields.json", { :fields => fields })
329
+ end
330
+
331
+ def update_documents(engine_id, document_type_id, documents={})
332
+ put("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_update.json", { :documents => documents })
333
+ end
334
+
335
+ def async_create_or_update_documents(engine_id, document_type_id, documents=[])
336
+ post("engines/#{engine_id}/document_types/#{document_type_id}/documents/async_bulk_create_or_update.json", :documents => documents)
337
+ end
338
+
339
+ # Retrieve Document Receipts from the API by ID
340
+ #
341
+ # @param [Array<String>] receipt_ids an Array of Document Receipt IDs
342
+ #
343
+ # @return [Array<Hash>] an Array of Document Receipt hashes
344
+ def document_receipts(receipt_ids)
345
+ post("document_receipts.json", :ids => receipt_ids)
346
+ end
347
+
348
+ # Index a batch of documents using the {asynchronous API}[https://swiftype.com/documentation/site-search/indexing#asynchronous].
349
+ # This is a good choice if you have a large number of documents.
350
+ #
351
+ # @param [String] engine_id the Engine slug or ID
352
+ # @param [String] document_type_id the Document Type slug or ID
353
+ # @param [Array] documents an Array of Document Hashes
354
+ # @param [Hash] options additional options
355
+ # @option options [Boolean] :async (false) When true, output is document receipts created. When false, poll until all receipts are no longer pending or timeout is reached.
356
+ # @option options [Numeric] :timeout (10) Number of seconds to wait before raising an exception
357
+ #
358
+ # @return [Array<Hash>] an Array of newly-created Document Receipt hashes if used in :async => true mode
359
+ # @return [Array<Hash>] an Array of processed Document Receipt hashes if used in :async => false mode
360
+ #
361
+ # @raise [Timeout::Error] when used in :async => false mode and the timeout expires
362
+ def index_documents(engine_id, document_type_id, documents = [], options = {})
363
+ documents = wrap(documents)
364
+
365
+ res = async_create_or_update_documents(engine_id, document_type_id, documents)
366
+
367
+ if options[:async]
368
+ res
369
+ else
370
+ receipt_ids = res["document_receipts"].map { |a| a["id"] }
371
+
372
+ poll(options) do
373
+ receipts = document_receipts(receipt_ids)
374
+ flag = receipts.all? { |a| a["status"] != "pending" }
375
+ flag ? receipts : false
376
+ end
377
+ end
378
+ end
379
+ end
380
+
381
+ # The analytics API provides a way to export analytics data similar to what is found in the Site Search Dashboard.
382
+ # See the {REST API Documentation}[https://swiftype.com/documentation/site-search/analytics] for details.
383
+ module Analytics
384
+ # Return the number of searches that occurred on each day in the time range for the provided Engine and optional DocumentType.
385
+ # The maximum time range between start and end dates is 30 days.
386
+ #
387
+ # @param [String] engine_id the Engine slug or ID
388
+ # @param [Hash] options
389
+ # @option options [String] :document_type_id the DocumentType slug or ID
390
+ # @option options [String] :start_date a date formatted like '2013-01-01'
391
+ # @option options [String] :end_date to a date formatted like '2013-01-01'
392
+ def analytics_searches(engine_id, options={})
393
+ document_type_id = options.delete(:document_type_id)
394
+ if document_type_id
395
+ get("engines/#{engine_id}/document_types/#{document_type_id}/analytics/searches.json", options)
396
+ else
397
+ get("engines/#{engine_id}/analytics/searches.json", options)
398
+ end
399
+ end
400
+
401
+ # Return the number of autoselects (when a user clicks a result from an autocomplete dropdown)
402
+ # that occurred on each day in the time range for the provided Engine and optional DocumentType.
403
+ # The maximum time range between start and end dates is 30 days.
404
+ #
405
+ # @param [String] engine_id the Engine slug or ID
406
+ # @param [Hash] options
407
+ # @option options [String] :document_type_id the DocumentType slug or ID
408
+ # @option options [String] :start_date a date formatted like '2013-01-01'
409
+ # @option options [String] :end_date to a date formatted like '2013-01-01'
410
+ def analytics_autoselects(engine_id, options={})
411
+ document_type_id = options.delete(:document_type_id)
412
+ if document_type_id
413
+ get("engines/#{engine_id}/document_types/#{document_type_id}/analytics/autoselects.json", options)
414
+ else
415
+ get("engines/#{engine_id}/analytics/autoselects.json", options)
416
+ end
417
+ end
418
+
419
+ # Return the number of clickthroughs (when a user clicks a result from a search results page)
420
+ # that occurred on each day in the time range for the provided Engine and optional DocumentType.
421
+ # The maximum time range between start and end dates is 30 days.
422
+ #
423
+ # @param [String] engine_id the Engine slug or ID
424
+ # @param [Hash] options
425
+ # @option options [String] :document_type_id the DocumentType slug or ID
426
+ # @option options [String] :start_date a date formatted like '2013-01-01'
427
+ # @option options [String] :end_date to a date formatted like '2013-01-01'
428
+ def analytics_clicks(engine_id, options={})
429
+ document_type_id = options.delete(:document_type_id)
430
+ if document_type_id
431
+ get("engines/#{engine_id}/document_types/#{document_type_id}/analytics/clicks.json", options)
432
+ else
433
+ get("engines/#{engine_id}/analytics/clicks.json", options)
434
+ end
435
+ end
436
+
437
+ # Return top queries for an engine.
438
+ #
439
+ # @param [String] engine_id the engine slug or ID
440
+ # @param [Hash] options
441
+ # @option options [String] :start_date a date formatted like '2013-01-01'
442
+ # @option options [String] :end_date a date formatted like '2013-01-01'
443
+ # @option options [Integer] :page page number. The server defaults to page 1 and the maximum is 50.
444
+ # @option options [Integer] :per_page number of results per page. The server defaults to 20 and the maximum is 100.
445
+ def analytics_top_queries(engine_id, options={})
446
+ get("engines/#{engine_id}/analytics/top_queries.json", options)
447
+ end
448
+
449
+ # Return top queries with no results for an engine.
450
+ #
451
+ # @param [String] engine_id the engine slug or ID
452
+ # @param [Hash] options
453
+ # @option options [String] :start_date a date formatted like '2013-01-01'
454
+ # @option options [String] :end_date a date formatted like '2013-01-01'
455
+ # @option options [Integer] :page page number. The server defaults to page 1 and the maximum is 50.
456
+ # @option options [Integer] :per_page number of results per page. The server defaults to 20 and the maximum is 100.
457
+ def analytics_top_no_result_queries(engine_id, options={})
458
+ get("engines/#{engine_id}/analytics/top_no_result_queries.json", options)
459
+ end
460
+ end
461
+
462
+ # A Domain represents a host in a crawler-based Engine. Domains
463
+ # are only relevant to crawler-base engines, but you can
464
+ # manipulate them through the REST API.
465
+ module Domain
466
+ def domains(engine_id)
467
+ get("engines/#{engine_id}/domains.json")
468
+ end
469
+
470
+ def domain(engine_id, domain_id)
471
+ get("engines/#{engine_id}/domains/#{domain_id}.json")
472
+ end
473
+
474
+ def create_domain(engine_id, url)
475
+ post("engines/#{engine_id}/domains.json", {:domain => {:submitted_url => url}})
476
+ end
477
+
478
+ def destroy_domain(engine_id, domain_id)
479
+ delete("engines/#{engine_id}/domains/#{domain_id}.json")
480
+ end
481
+
482
+ # Trigger a recrawl request for a Domain. Note that this will fail if you have exceeded your recrawl limit.
483
+ def recrawl_domain(engine_id, domain_id)
484
+ put("engines/#{engine_id}/domains/#{domain_id}/recrawl.json")
485
+ end
486
+
487
+ # Request to add or update a URL on a Domain. The host of the URL must match the host of the Domain.
488
+ #
489
+ # @param [String] engine_id the Engine slug or ID
490
+ # @param [String] domain_id the Domain ID
491
+ # @param [String] url the URL to crawl
492
+ def crawl_url(engine_id, domain_id, url)
493
+ put("engines/#{engine_id}/domains/#{domain_id}/crawl_url.json", {:url => url})
494
+ end
495
+ end
496
+
497
+ # A Clickthrough represents a user clicking on a full-text search result.
498
+ #
499
+ # If you are routing searches through your own server instead of
500
+ # executing them client-side with the Site Search JavaScript API, you
501
+ # will need to record clickthroughs yourself.
502
+ module Clickthrough
503
+ # Log a clickthrough for a Document.
504
+ #
505
+ # @param [String] engine_id the Engine slug or ID
506
+ # @param [String] document_type the DocumentType slug or ID
507
+ # @param [String] q the query that generated the search result
508
+ # @param [String] id the external_id or ID of the Document
509
+ def log_clickthrough(engine_id, document_type, q, id)
510
+ post(
511
+ "engines/#{engine_id}/document_types/#{document_type}/analytics/log_clickthrough.json",
512
+ {:q => q, :id => id}
513
+ )
514
+ end
515
+ end
516
+
517
+ include Elastic::SiteSearch::Client::User
518
+ include Elastic::SiteSearch::Client::Search
519
+ include Elastic::SiteSearch::Client::Engine
520
+ include Elastic::SiteSearch::Client::DocumentType
521
+ include Elastic::SiteSearch::Client::Document
522
+ include Elastic::SiteSearch::Client::Analytics
523
+ include Elastic::SiteSearch::Client::Domain
524
+ include Elastic::SiteSearch::Client::Clickthrough
525
+ end
526
+ end
527
+ end