gcloud 0.7.2 → 0.8.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.
@@ -1,246 +0,0 @@
1
- # Copyright 2015 Google Inc. All rights reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
-
16
- require "gcloud/search/field_values"
17
- require "gcloud/search/field_value"
18
-
19
- module Gcloud
20
- module Search
21
- ##
22
- # # Fields
23
- #
24
- # Fields is the object that provides access to a document's fields.
25
- #
26
- # Each field has a name (String) and a list of values. Each field name
27
- # consists of only ASCII characters, must be unique within the document and
28
- # is case sensitive. A field name must start with a letter and can contain
29
- # letters, digits, or underscore, with a maximum of 500 characters.
30
- #
31
- # A field can have multiple values with same or different types; however, it
32
- # cannot have multiple datetime (DateTime) or number (Float) values. (See
33
- # {FieldValues} and {FieldValue})
34
- #
35
- # @example
36
- # require "gcloud"
37
- #
38
- # gcloud = Gcloud.new
39
- # search = gcloud.search
40
- # index = search.index "products"
41
- #
42
- # document = index.document "product-sku-000001"
43
- # puts "The document #{document.doc_id} has the following fields:"
44
- # document.names.each do |name|
45
- # puts "* #{name}:"
46
- # document[name].each do |value|
47
- # puts " * #{value} (#{value.type})"
48
- # end
49
- # end
50
- #
51
- # @see https://cloud.google.com/search/documents_indexes Documents and
52
- # fields
53
- #
54
- class Fields
55
- include Enumerable
56
-
57
- ##
58
- # @private Create a new empty fields object.
59
- def initialize
60
- @hash = {}
61
- end
62
-
63
- ##
64
- # Retrieve the field values associated to a field name.
65
- #
66
- # @param [String] name The name of the field. New values will be
67
- # configured with this name.
68
- #
69
- # @return [FieldValues]
70
- #
71
- # @example
72
- # require "gcloud"
73
- #
74
- # gcloud = Gcloud.new
75
- # search = gcloud.search
76
- # index = search.index "products"
77
- #
78
- # document = index.document "product-sku-000001"
79
- # puts "The document description is:"
80
- # document.fields["description"].each do |value|
81
- # puts "* #{value} (#{value.type}) [#{value.lang}]"
82
- # end
83
- #
84
- def [] name
85
- @hash[name] ||= FieldValues.new name
86
- end
87
-
88
- ##
89
- # Add a new value. If the field name does not exist it will be added. If
90
- # the field value is a DateTime or Numeric, or the type is set to
91
- # `:datetime` or `:number`, then the added value will replace any existing
92
- # values of the same type (since there can be only one).
93
- #
94
- # @param [String] name The name of the field.
95
- # @param [String, Datetime, Float] value The value to add to the field.
96
- # @param [Symbol] type The type of the field value. An attempt is made to
97
- # set the correct type when this option is missing, although it must be
98
- # provided for `:geo` values. A field can have multiple values with same
99
- # or different types; however, it cannot have multiple `:datetime` or
100
- # `:number` values.
101
- #
102
- # The following values are supported:
103
- #
104
- # * `:default` - The value is a string. The format will be automatically
105
- # detected. This is the default value for strings.
106
- # * `:text` - The value is a string with maximum length 1024**2
107
- # characters.
108
- # * `:html` - The value is an HTML-formatted string with maximum length
109
- # 1024**2 characters.
110
- # * `:atom` - The value is a string with maximum length 500 characters.
111
- # * `:geo` - The value is a point on earth described by latitude and
112
- # longitude coordinates, represented in string with any of the listed
113
- # [ways of writing coordinates](http://en.wikipedia.org/wiki/Geographic_coordinate_conversion).
114
- # * `:datetime` - The value is a `DateTime`.
115
- # * `:number` - The value is a `Numeric` between -2,147,483,647 and
116
- # 2,147,483,647. The value will be stored as a double precision
117
- # floating point value in Cloud Search.
118
- # @param [String] lang The language of a string value. Must be a valid
119
- # [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
120
- #
121
- # @example
122
- # require "gcloud"
123
- #
124
- # gcloud = Gcloud.new
125
- # search = gcloud.search
126
- # index = search.index "products"
127
- #
128
- # document = index.document "product-sku-000001"
129
- # document.fields.add "sku", "product-sku-000001", type: :atom
130
- # document.fields.add "description", "The best T-shirt ever.",
131
- # type: :text, lang: "en"
132
- # document.fields.add "description", "<p>The best T-shirt ever.</p>",
133
- # type: :html, lang: "en"
134
- # document.fields.add "price", 24.95
135
- #
136
- def add name, value, type: nil, lang: nil
137
- @hash[name] ||= FieldValues.new name
138
- @hash[name].add value, type: type, lang: lang
139
- end
140
-
141
- ##
142
- # Deletes a field and all values.
143
- #
144
- # @param [String] name The name of the field.
145
- #
146
- # @example
147
- # require "gcloud"
148
- #
149
- # gcloud = Gcloud.new
150
- # search = gcloud.search
151
- # index = search.index "products"
152
- #
153
- # document = index.document "product-sku-000001"
154
- # document.fields.delete "description"
155
- #
156
- def delete name, &block
157
- @hash.delete name, &block
158
- end
159
-
160
- ##
161
- # Calls block once for each field, passing the field name and values pair
162
- # as parameters. If no block is given an enumerator is returned instead.
163
- #
164
- # @example
165
- # require "gcloud"
166
- #
167
- # gcloud = Gcloud.new
168
- # search = gcloud.search
169
- # index = search.index "products"
170
- #
171
- # document = index.document "product-sku-000001"
172
- # puts "The document #{document.doc_id} has the following fields:"
173
- # document.fields.each do |name, values|
174
- # puts "* #{name}:"
175
- # values.each do |value|
176
- # puts " * #{value} (#{value.type})"
177
- # end
178
- # end
179
- #
180
- def each &block
181
- # Only yield fields that have values.
182
- fields_with_values.each(&block)
183
- end
184
-
185
- ##
186
- # Returns a new array populated with all the field names.
187
- #
188
- # @example
189
- # require "gcloud"
190
- #
191
- # gcloud = Gcloud.new
192
- # search = gcloud.search
193
- # index = search.index "products"
194
- #
195
- # document = index.document "product-sku-000001"
196
- # puts "The document #{document.doc_id} has the following fields:"
197
- # document.fields.names.each do |name|
198
- # puts "* #{name}:"
199
- # end
200
- #
201
- def names
202
- # Only return fields that have values.
203
- fields_with_values.keys
204
- end
205
-
206
- ##
207
- # @private Create a new Fields instance from a raw Hash.
208
- def self.from_raw raw
209
- hsh = {}
210
- raw.each do |k, v|
211
- hsh[k] = FieldValues.from_raw k, v["values"]
212
- end unless raw.nil?
213
- fields = new
214
- fields.instance_variable_set "@hash", hsh
215
- fields
216
- end
217
-
218
- ##
219
- # @private Create a raw Hash object containing all the field names and
220
- # values.
221
- def to_raw
222
- hsh = {}
223
- @hash.each do |k, v|
224
- hsh[k] = v.to_raw unless v.empty?
225
- end
226
- hsh
227
- end
228
-
229
- protected
230
-
231
- ##
232
- # @private Find all the fields that have values. This is needed because a
233
- # field is required to have at least one value.
234
- #
235
- # Users can remove all values, and the empty FieldValues object will
236
- # remain in the internal hash. This is the same as not having that field.
237
- #
238
- # Users can also reference the field by name before adding a value. So we
239
- # have multiple valid use cases which add an empty FieldValues object to
240
- # the hash.
241
- def fields_with_values
242
- @hash.select { |_name, values| values.any? }
243
- end
244
- end
245
- end
246
- end
@@ -1,572 +0,0 @@
1
- # Copyright 2015 Google Inc. All rights reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
-
16
- require "gcloud/search/document"
17
- require "gcloud/search/index/list"
18
- require "gcloud/search/result"
19
-
20
- module Gcloud
21
- module Search
22
- ##
23
- # # Index
24
- #
25
- # An index manages {Document} instances for retrieval. Indexes cannot be
26
- # created, updated, or deleted directly on the server: They are derived from
27
- # the documents that reference them. You can manage groups of documents by
28
- # putting them into separate indexes.
29
- #
30
- # With an index, you can retrieve documents with
31
- # {Gcloud::Search::Index#find} and {Gcloud::Search::Index#documents}; manage
32
- # them with {Gcloud::Search::Index#document}, {Gcloud::Search::Index#save},
33
- # and {Gcloud::Search::Index#remove}; and perform searches over their fields
34
- # with {Gcloud::Search::Index#search}.
35
- #
36
- # @example
37
- # require "gcloud"
38
- #
39
- # gcloud = Gcloud.new
40
- # search = gcloud.search
41
- # index = search.index "books"
42
- #
43
- # results = index.search "dark stormy"
44
- # results.each do |result|
45
- # puts result.doc_id
46
- # end
47
- #
48
- # @see https://cloud.google.com/search/documents_indexes Documents and
49
- # Indexes
50
- #
51
- class Index
52
- ##
53
- # @private The Connection object.
54
- attr_accessor :connection
55
-
56
- ##
57
- # @private The raw data object.
58
- attr_accessor :raw
59
-
60
- ##
61
- # @private Creates a new Index instance.
62
- #
63
- def initialize
64
- @connection = nil
65
- @raw = nil
66
- end
67
-
68
- ##
69
- # The index identifier. May be defined by the server or by the client.
70
- # Must be unique within the project. It cannot be an empty string. It must
71
- # contain only visible, printable ASCII characters (ASCII codes 33 through
72
- # 126 inclusive) and be no longer than 100 characters. It cannot begin
73
- # with an exclamation point (<code>!</code>), and it cannot begin and end
74
- # with double underscores (<code>__</code>).
75
- def index_id
76
- @raw["indexId"]
77
- end
78
-
79
- ##
80
- # The names of fields in which TEXT values are stored.
81
- # @see https://cloud.google.com/search/documents_indexes#index_schemas
82
- # Index schemas
83
- def text_fields
84
- return @raw["indexedField"]["textFields"] if @raw["indexedField"]
85
- []
86
- end
87
-
88
- ##
89
- # The names of fields in which HTML values are stored.
90
- # @see https://cloud.google.com/search/documents_indexes#index_schemas
91
- # Index schemas
92
- def html_fields
93
- return @raw["indexedField"]["htmlFields"] if @raw["indexedField"]
94
- []
95
- end
96
-
97
- ##
98
- # The names of fields in which ATOM values are stored.
99
- # @see https://cloud.google.com/search/documents_indexes#index_schemas
100
- # Index schemas
101
- def atom_fields
102
- return @raw["indexedField"]["atomFields"] if @raw["indexedField"]
103
- []
104
- end
105
-
106
- ##
107
- # The names of fields in which DATE values are stored.
108
- # @see https://cloud.google.com/search/documents_indexes#index_schemas
109
- # Index schemas
110
- def datetime_fields
111
- return @raw["indexedField"]["dateFields"] if @raw["indexedField"]
112
- []
113
- end
114
-
115
- ##
116
- # The names of fields in which NUMBER values are stored.
117
- # @see https://cloud.google.com/search/documents_indexes#index_schemas
118
- # Index schemas
119
- def number_fields
120
- return @raw["indexedField"]["numberFields"] if @raw["indexedField"]
121
- []
122
- end
123
-
124
- ##
125
- # The names of fields in which GEO values are stored.
126
- # @see https://cloud.google.com/search/documents_indexes#index_schemas
127
- # Index schemas
128
- def geo_fields
129
- return @raw["indexedField"]["geoFields"] if @raw["indexedField"]
130
- []
131
- end
132
-
133
- ##
134
- # The names of all the fields that are stored on the index.
135
- def field_names
136
- (text_fields + html_fields + atom_fields + datetime_fields +
137
- number_fields + geo_fields).uniq
138
- end
139
-
140
- ##
141
- # The field value types that are stored on the field name.
142
- def field_types_for name
143
- {
144
- text: text_fields.include?(name),
145
- html: html_fields.include?(name),
146
- atom: atom_fields.include?(name),
147
- datetime: datetime_fields.include?(name),
148
- number: number_fields.include?(name),
149
- geo: geo_fields.include?(name)
150
- }.delete_if { |_k, v| !v }.keys
151
- end
152
-
153
- ##
154
- # Retrieves an existing document by id.
155
- #
156
- # @param [String, Gcloud::Search::Document] doc_id The id of a document or
157
- # a Document instance.
158
- # @return [Gcloud::Search::Document, nil] Returns `nil` if the document
159
- # does not exist
160
- #
161
- # @example
162
- # require "gcloud"
163
- #
164
- # gcloud = Gcloud.new
165
- # search = gcloud.search
166
- # index = search.index "products"
167
- #
168
- # document = index.find "product-sku-000001"
169
- # puts document.doc_id
170
- #
171
- def find doc_id
172
- # Get the id if passes a Document object
173
- doc_id = doc_id.doc_id if doc_id.respond_to? :doc_id
174
- ensure_connection!
175
- resp = connection.get_doc index_id, doc_id
176
- return Document.from_hash(JSON.parse(resp.body)) if resp.success?
177
- return nil if resp.status == 404
178
- fail ApiError.from_response(resp)
179
- rescue JSON::ParserError
180
- raise ApiError.from_response(resp)
181
- end
182
- alias_method :get, :find
183
-
184
- ##
185
- # Helper for creating a new Document instance. The returned instance is
186
- # local: It is either not yet saved to the service (see
187
- # {Gcloud::Search::Index#save}), or if it has been given the id of an
188
- # existing document, it is not yet populated with the document's data (see
189
- # {Gcloud::Search::Index#find}).
190
- #
191
- # @param [String, nil] doc_id An optional unique ID for the new document.
192
- # When the document is saved, this value must contain only visible,
193
- # printable ASCII characters (ASCII codes 33 through 126 inclusive) and
194
- # be no longer than 500 characters. It cannot begin with an exclamation
195
- # point (<code>!</code>), and it cannot begin and end with double
196
- # underscores (<code>__</code>).
197
- # @param [Integer, nil] rank An optional rank for the new document. An
198
- # integer which determines the default ordering of documents returned
199
- # from a search. It is a bad idea to assign the same rank to many
200
- # documents, and the same rank should never be assigned to more than
201
- # 10,000 documents. By default (when it is not specified or set to 0),
202
- # it is set at the time the document is saved to the number of seconds
203
- # since January 1, 2011. The rank can be used in the `expressions`,
204
- # `order`, and `fields` options in {Gcloud::Search::Index#search}, where
205
- # it should referenced as `rank`.
206
- #
207
- # @return [Gcloud::Search::Document]
208
- #
209
- # @example
210
- # require "gcloud"
211
- #
212
- # gcloud = Gcloud.new
213
- # search = gcloud.search
214
- # index = search.index "products"
215
- #
216
- # document = index.document "product-sku-000001"
217
- # document.doc_id #=> nil
218
- # document.rank #=> nil
219
- #
220
- # @example To check if an index already contains a document:
221
- # require "gcloud"
222
- #
223
- # gcloud = Gcloud.new
224
- # search = gcloud.search
225
- # index = search.index "products"
226
- #
227
- # document = index.document "product-sku-000001"
228
- # document = index.find document # returns nil if not present
229
- #
230
- def document doc_id = nil, rank = nil
231
- Document.new.tap do |d|
232
- d.doc_id = doc_id
233
- d.rank = rank
234
- end
235
- end
236
-
237
- ##
238
- # Retrieves the list of documents belonging to the index.
239
- #
240
- # @param [String] token A previously-returned page token representing part
241
- # of the larger set of results to view.
242
- # @param [Integer] max Maximum number of documents to return. The default
243
- # is `100`.
244
- # @return [Array<Gcloud::Search::Document>] See
245
- # {Gcloud::Search::Document::List})
246
- #
247
- # @example
248
- # require "gcloud"
249
- #
250
- # gcloud = Gcloud.new
251
- # search = gcloud.search
252
- # index = search.index "products"
253
- #
254
- # documents = index.documents
255
- # documents.each do |index|
256
- # puts index.index_id
257
- # end
258
- #
259
- # @example With pagination: (See {Gcloud::Search::Document::List})
260
- # require "gcloud"
261
- #
262
- # gcloud = Gcloud.new
263
- # search = gcloud.search
264
- # index = search.index "products"
265
- #
266
- # documents = index.documents
267
- # loop do
268
- # documents.each do |index|
269
- # puts index.index_id
270
- # end
271
- # break unless documents.next?
272
- # documents = documents.next
273
- # end
274
- #
275
- def documents token: nil, max: nil, view: nil
276
- ensure_connection!
277
- options = { token: token, max: max, view: view }
278
- resp = connection.list_docs index_id, options
279
- return Document::List.from_response(resp, self) if resp.success?
280
- fail ApiError.from_response(resp)
281
- end
282
-
283
- ##
284
- # Saves a new or existing document to the index. If the document instance
285
- # is new and has been given an id (see {Gcloud::Search::Index#document}),
286
- # it will replace an existing document in the index that has the same
287
- # unique id.
288
- #
289
- # @param [Gcloud::Search::Document] document A Document instance, either
290
- # new (see {Gcloud::Search::Index#document}) or existing (see
291
- # {Gcloud::Search::Index#find}).
292
- #
293
- # @return [Gcloud::Search::Document]
294
- #
295
- # @example
296
- # require "gcloud"
297
- #
298
- # gcloud = Gcloud.new
299
- # search = gcloud.search
300
- # index = search.index "products"
301
- #
302
- # document = index.document "product-sku-000001"
303
- # document.doc_id #=> nil
304
- # document.rank #=> nil
305
- #
306
- # document = index.save document
307
- # document.doc_id #=> "-2486020449015432113"
308
- # document.rank #=> 154223228
309
- #
310
- def save document
311
- ensure_connection!
312
- resp = connection.create_doc index_id, document.to_hash
313
- if resp.success?
314
- raw = document.instance_variable_get "@raw"
315
- raw.merge! JSON.parse(resp.body)
316
- return document
317
- end
318
- fail ApiError.from_response(resp)
319
- rescue JSON::ParserError
320
- raise ApiError.from_response(resp)
321
- end
322
-
323
- ##
324
- # Permanently deletes the document from the index.
325
- #
326
- # @param [String] doc_id The id of the document.
327
- # @return [Boolean] `true` if successful
328
- #
329
- # @example
330
- # require "gcloud"
331
- #
332
- # gcloud = Gcloud.new
333
- # search = gcloud.search
334
- # index = search.index "products"
335
- #
336
- # index.remove "product-sku-000001"
337
- #
338
- def remove doc_id
339
- # Get the id if passes a Document object
340
- doc_id = doc_id.doc_id if doc_id.respond_to? :doc_id
341
- ensure_connection!
342
- resp = connection.delete_doc index_id, doc_id
343
- return true if resp.success?
344
- fail ApiError.from_response(resp)
345
- end
346
-
347
- ##
348
- # Permanently deletes the index by deleting its documents. (Indexes cannot
349
- # be created, updated, or deleted directly on the server: They are derived
350
- # from the documents that reference them.)
351
- #
352
- # @param [Boolean] force If `true`, ensures the deletion of the index by
353
- # first deleting all documents. If `false` and the index contains
354
- # documents, the request will fail. Default is `false`.
355
- #
356
- # @example
357
- # require "gcloud"
358
- #
359
- # gcloud = Gcloud.new
360
- # search = gcloud.search
361
- # index = search.index "books"
362
- # index.delete
363
- #
364
- # @example Deleting an index containing documents with the `force` option:
365
- # require "gcloud"
366
- #
367
- # gcloud = Gcloud.new
368
- # search = gcloud.search
369
- # index = search.index "books"
370
- # index.delete force: true
371
- #
372
- def delete force: false
373
- ensure_connection!
374
- docs_to_be_removed = documents view: "ID_ONLY"
375
- return if docs_to_be_removed.empty?
376
- unless force
377
- fail "Unable to delete because documents exist. Use force option."
378
- end
379
- while docs_to_be_removed
380
- docs_to_be_removed.each { |d| remove d }
381
- if docs_to_be_removed.next?
382
- docs_to_be_removed = documents token: docs_to_be_removed.token,
383
- view: "ID_ONLY"
384
- else
385
- docs_to_be_removed = nil
386
- end
387
- end
388
- end
389
-
390
- ##
391
- # @private New Index from a raw data object.
392
- def self.from_raw raw, conn
393
- new.tap do |f|
394
- f.raw = raw
395
- f.connection = conn
396
- end
397
- end
398
-
399
- # rubocop:disable Metrics/LineLength
400
- # Disabled because there are links in the docs that are long.
401
-
402
- ##
403
- # Runs a search against the documents in the index using the provided
404
- # query.
405
- #
406
- # By default, Result objects are sorted by document rank. For more information
407
- # see the [REST API documentation for Document.rank](https://cloud.google.com/search/reference/rest/v1/projects/indexes/documents#resource_representation.google.cloudsearch.v1.Document.rank).
408
- #
409
- # You can specify how to sort results with the `order` option. In the
410
- # example below, the <code>-</code> character before `avg_review` means
411
- # that results will be sorted in ascending order by `published` and then
412
- # in descending order by `avg_review`. You can add computed fields with
413
- # the `expressions` option, and limit the fields that are returned with
414
- # the `fields` option.
415
- #
416
- # @see https://cloud.google.com/search/reference/rest/v1/projects/indexes/search
417
- # The REST API documentation for indexes.search
418
- #
419
- # @param [String] query The query string in search query syntax. If the
420
- # query is `nil` or empty, all documents are returned. For more
421
- # information see [Query
422
- # Strings](https://cloud.google.com/search/query).
423
- # @param [Hash] expressions Customized expressions used in `order` or
424
- # `fields`. The expression can contain fields in Document, the built-in
425
- # fields ( `rank`, the document `rank`, and `score` if scoring is
426
- # enabled) and fields defined in `expressions`. All field expressions
427
- # expressed as a `Hash` with the keys as the `name` and the values as
428
- # the `expression`. The expression value can be a combination of
429
- # supported functions encoded in the string. Expressions involving
430
- # number fields can use the arithmetical operators (+, -, *, /) and the
431
- # built-in numeric functions (`max`, `min`, `pow`, `count`, `log`,
432
- # `abs`). Expressions involving geopoint fields can use the `geopoint`
433
- # and `distance` functions. Expressions for text and html fields can use
434
- # the `snippet` function.
435
- # @param [Integer] matched_count_accuracy Minimum accuracy requirement for
436
- # {Result::List#matched_count}. If specified, `matched_count` will be
437
- # accurate to at least that number. For example, when set to 100, any
438
- # <code>matched_count <= 100</code> is accurate. This option may add
439
- # considerable latency/expense. By default (when it is not specified or
440
- # set to 0), the accuracy is the same as `max`.
441
- # @param [Integer] offset Used to advance pagination to an arbitrary
442
- # result, independent of the previous results. Offsets are an
443
- # inefficient alternative to using `token`. (Both cannot be both set.)
444
- # The default is 0.
445
- # @param [String] order A comma-separated list of fields for sorting on
446
- # the search result, including fields from Document, the built-in fields
447
- # (`rank` and `score`), and fields defined in expressions. The default
448
- # sorting order is ascending. To specify descending order for a field, a
449
- # suffix <code>" desc"</code> should be appended to the field name. For
450
- # example: <code>orderBy="foo desc,bar"</code>. The default value for
451
- # text sort is the empty string, and the default value for numeric sort
452
- # is 0. If not specified, the search results are automatically sorted by
453
- # descending `rank`. Sorting by ascending `rank` is not allowed.
454
- # @param [String, Array<String>] fields The fields to return in the
455
- # {Search::Result} objects. These can be fields from {Document}, the
456
- # built-in fields `rank` and `score`, and fields defined in expressions.
457
- # The default is to return all fields.
458
- # @param [String, Symbol] scorer The scoring function to invoke on a
459
- # search result for this query. If scorer is not set, scoring is
460
- # disabled and `score` is 0 for all documents in the search result. To
461
- # enable document relevancy score based on term frequency, set `scorer`
462
- # to `:generic`.
463
- # @param [Integer] scorer_size Maximum number of top retrieved results to
464
- # score. It is valid only when `scorer` is set. The default is 100.
465
- # @param [String] token A previously-returned page token representing part
466
- # of the larger set
467
- # of results to view.
468
- # @param [Integer] max Maximum number of results to return per page.
469
- #
470
- # @return [Array<Gcloud::Search::Result>] (See
471
- # {Gcloud::Search::Result::List})
472
- #
473
- # @example
474
- # require "gcloud"
475
- #
476
- # gcloud = Gcloud.new
477
- # search = gcloud.search
478
- # index = search.index "books"
479
- #
480
- # results = index.search "dark stormy"
481
- # results.each do |result|
482
- # puts result.doc_id
483
- # end
484
- #
485
- # @example With pagination: (See {Gcloud::Search::Result::List})
486
- # require "gcloud"
487
- #
488
- # gcloud = Gcloud.new
489
- # search = gcloud.search
490
- # index = search.index "books"
491
- #
492
- # results = index.results
493
- # loop do
494
- # results.each do |result|
495
- # puts result.doc_id
496
- # end
497
- # break unless results.next?
498
- # results = results.next
499
- # end
500
- #
501
- # @example With the `order` option:
502
- # require "gcloud"
503
- #
504
- # gcloud = Gcloud.new
505
- # search = gcloud.search
506
- # index = search.index "books"
507
- #
508
- # results = index.search "dark stormy", order: "published, avg_review desc"
509
- # documents = index.search query # API call
510
- #
511
- # @example With the `fields` option:
512
- # require "gcloud"
513
- #
514
- # gcloud = Gcloud.new
515
- # search = gcloud.search
516
- # index = search.index "products"
517
- #
518
- # results = index.search "cotton T-shirt",
519
- # expressions: { total_price: "(price + tax)" },
520
- # fields: ["name", "total_price", "highlight"]
521
- #
522
- # @example Just as in documents, data is accessible via {Fields} methods:
523
- # require "gcloud"
524
- #
525
- # gcloud = Gcloud.new
526
- # search = gcloud.search
527
- # index = search.index "products"
528
- # document = index.find "product-sku-000001"
529
- # results = index.search "cotton T-shirt"
530
- # values = results[0]["description"]
531
- #
532
- # values[0] #=> "100% organic cotton ruby gem T-shirt"
533
- # values[0].type #=> :text
534
- # values[0].lang #=> "en"
535
- # values[1] #=> "<p>100% organic cotton ruby gem T-shirt</p>"
536
- # values[1].type #=> :html
537
- # values[1].lang #=> "en"
538
- #
539
- def search query, expressions: nil, matched_count_accuracy: nil,
540
- offset: nil, order: nil, fields: nil, scorer: nil,
541
- scorer_size: nil, token: nil, max: nil
542
- ensure_connection!
543
- options = { expressions: format_expressions(expressions),
544
- matched_count_accuracy: matched_count_accuracy,
545
- offset: offset, order: order, fields: fields,
546
- scorer: scorer, scorer_size: scorer_size, token: token,
547
- max: max }
548
- resp = connection.search index_id, query, options
549
- if resp.success?
550
- Result::List.from_response resp, self, query, options
551
- else
552
- fail ApiError.from_response(resp)
553
- end
554
- end
555
-
556
- # rubocop:enable Metrics/LineLength
557
-
558
- protected
559
-
560
- ##
561
- # Raise an error unless an active connection is available.
562
- def ensure_connection!
563
- fail "Must have active connection" unless connection
564
- end
565
-
566
- def format_expressions expressions
567
- return nil if expressions.nil?
568
- expressions.to_h.map { |k, v| { name: k, expression: v } }
569
- end
570
- end
571
- end
572
- end