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