gcloud 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|