load_balanced_tire 0.1
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.
- data/.gitignore +14 -0
- data/.travis.yml +29 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.markdown +760 -0
- data/Rakefile +78 -0
- data/examples/rails-application-template.rb +249 -0
- data/examples/tire-dsl.rb +876 -0
- data/lib/tire.rb +55 -0
- data/lib/tire/alias.rb +296 -0
- data/lib/tire/configuration.rb +30 -0
- data/lib/tire/dsl.rb +43 -0
- data/lib/tire/http/client.rb +62 -0
- data/lib/tire/http/clients/curb.rb +61 -0
- data/lib/tire/http/clients/faraday.rb +71 -0
- data/lib/tire/http/response.rb +27 -0
- data/lib/tire/index.rb +361 -0
- data/lib/tire/logger.rb +60 -0
- data/lib/tire/model/callbacks.rb +40 -0
- data/lib/tire/model/import.rb +26 -0
- data/lib/tire/model/indexing.rb +128 -0
- data/lib/tire/model/naming.rb +100 -0
- data/lib/tire/model/percolate.rb +99 -0
- data/lib/tire/model/persistence.rb +71 -0
- data/lib/tire/model/persistence/attributes.rb +143 -0
- data/lib/tire/model/persistence/finders.rb +66 -0
- data/lib/tire/model/persistence/storage.rb +69 -0
- data/lib/tire/model/search.rb +307 -0
- data/lib/tire/results/collection.rb +114 -0
- data/lib/tire/results/item.rb +86 -0
- data/lib/tire/results/pagination.rb +54 -0
- data/lib/tire/rubyext/hash.rb +8 -0
- data/lib/tire/rubyext/ruby_1_8.rb +7 -0
- data/lib/tire/rubyext/symbol.rb +11 -0
- data/lib/tire/search.rb +188 -0
- data/lib/tire/search/facet.rb +74 -0
- data/lib/tire/search/filter.rb +28 -0
- data/lib/tire/search/highlight.rb +37 -0
- data/lib/tire/search/query.rb +186 -0
- data/lib/tire/search/scan.rb +114 -0
- data/lib/tire/search/script_field.rb +23 -0
- data/lib/tire/search/sort.rb +25 -0
- data/lib/tire/tasks.rb +135 -0
- data/lib/tire/utils.rb +17 -0
- data/lib/tire/version.rb +22 -0
- data/test/fixtures/articles/1.json +1 -0
- data/test/fixtures/articles/2.json +1 -0
- data/test/fixtures/articles/3.json +1 -0
- data/test/fixtures/articles/4.json +1 -0
- data/test/fixtures/articles/5.json +1 -0
- data/test/integration/active_model_indexing_test.rb +51 -0
- data/test/integration/active_model_searchable_test.rb +114 -0
- data/test/integration/active_record_searchable_test.rb +446 -0
- data/test/integration/boolean_queries_test.rb +43 -0
- data/test/integration/count_test.rb +34 -0
- data/test/integration/custom_score_queries_test.rb +88 -0
- data/test/integration/dis_max_queries_test.rb +68 -0
- data/test/integration/dsl_search_test.rb +22 -0
- data/test/integration/explanation_test.rb +44 -0
- data/test/integration/facets_test.rb +259 -0
- data/test/integration/filtered_queries_test.rb +66 -0
- data/test/integration/filters_test.rb +63 -0
- data/test/integration/fuzzy_queries_test.rb +20 -0
- data/test/integration/highlight_test.rb +64 -0
- data/test/integration/index_aliases_test.rb +122 -0
- data/test/integration/index_mapping_test.rb +43 -0
- data/test/integration/index_store_test.rb +96 -0
- data/test/integration/index_update_document_test.rb +111 -0
- data/test/integration/mongoid_searchable_test.rb +309 -0
- data/test/integration/percolator_test.rb +111 -0
- data/test/integration/persistent_model_test.rb +130 -0
- data/test/integration/prefix_query_test.rb +43 -0
- data/test/integration/query_return_version_test.rb +70 -0
- data/test/integration/query_string_test.rb +52 -0
- data/test/integration/range_queries_test.rb +36 -0
- data/test/integration/reindex_test.rb +46 -0
- data/test/integration/results_test.rb +39 -0
- data/test/integration/scan_test.rb +56 -0
- data/test/integration/script_fields_test.rb +38 -0
- data/test/integration/sort_test.rb +36 -0
- data/test/integration/text_query_test.rb +39 -0
- data/test/models/active_model_article.rb +31 -0
- data/test/models/active_model_article_with_callbacks.rb +49 -0
- data/test/models/active_model_article_with_custom_document_type.rb +7 -0
- data/test/models/active_model_article_with_custom_index_name.rb +7 -0
- data/test/models/active_record_models.rb +122 -0
- data/test/models/article.rb +15 -0
- data/test/models/mongoid_models.rb +97 -0
- data/test/models/persistent_article.rb +11 -0
- data/test/models/persistent_article_in_namespace.rb +12 -0
- data/test/models/persistent_article_with_casting.rb +28 -0
- data/test/models/persistent_article_with_defaults.rb +11 -0
- data/test/models/persistent_articles_with_custom_index_name.rb +10 -0
- data/test/models/supermodel_article.rb +17 -0
- data/test/models/validated_model.rb +11 -0
- data/test/test_helper.rb +93 -0
- data/test/unit/active_model_lint_test.rb +17 -0
- data/test/unit/configuration_test.rb +74 -0
- data/test/unit/http_client_test.rb +76 -0
- data/test/unit/http_response_test.rb +49 -0
- data/test/unit/index_alias_test.rb +275 -0
- data/test/unit/index_test.rb +894 -0
- data/test/unit/logger_test.rb +125 -0
- data/test/unit/model_callbacks_test.rb +116 -0
- data/test/unit/model_import_test.rb +71 -0
- data/test/unit/model_persistence_test.rb +528 -0
- data/test/unit/model_search_test.rb +913 -0
- data/test/unit/results_collection_test.rb +281 -0
- data/test/unit/results_item_test.rb +162 -0
- data/test/unit/rubyext_test.rb +66 -0
- data/test/unit/search_facet_test.rb +153 -0
- data/test/unit/search_filter_test.rb +42 -0
- data/test/unit/search_highlight_test.rb +46 -0
- data/test/unit/search_query_test.rb +301 -0
- data/test/unit/search_scan_test.rb +113 -0
- data/test/unit/search_script_field_test.rb +26 -0
- data/test/unit/search_sort_test.rb +50 -0
- data/test/unit/search_test.rb +499 -0
- data/test/unit/tire_test.rb +126 -0
- data/tire.gemspec +90 -0
- metadata +549 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'curb'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
|
5
|
+
module HTTP
|
6
|
+
|
7
|
+
module Client
|
8
|
+
|
9
|
+
class Curb
|
10
|
+
@client = ::Curl::Easy.new
|
11
|
+
@client.resolve_mode = :ipv4
|
12
|
+
|
13
|
+
# @client.verbose = true
|
14
|
+
|
15
|
+
def self.get(url, data=nil)
|
16
|
+
@client.url = url
|
17
|
+
|
18
|
+
# FIXME: Curb cannot post bodies with GET requests?
|
19
|
+
# Roy Fielding seems to approve:
|
20
|
+
# <http://tech.groups.yahoo.com/group/rest-discuss/message/9962>
|
21
|
+
if data
|
22
|
+
@client.post_body = data
|
23
|
+
@client.http_post
|
24
|
+
else
|
25
|
+
@client.http_get
|
26
|
+
end
|
27
|
+
Response.new @client.body_str, @client.response_code
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.post(url, data)
|
31
|
+
@client.url = url
|
32
|
+
@client.post_body = data
|
33
|
+
@client.http_post
|
34
|
+
Response.new @client.body_str, @client.response_code
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.put(url, data)
|
38
|
+
@client.url = url
|
39
|
+
@client.http_put data
|
40
|
+
Response.new @client.body_str, @client.response_code
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.delete(url)
|
44
|
+
@client.url = url
|
45
|
+
@client.http_delete
|
46
|
+
Response.new @client.body_str, @client.response_code
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.head(url)
|
50
|
+
@client.url = url
|
51
|
+
@client.http_head
|
52
|
+
Response.new @client.body_str, @client.response_code
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
# A Faraday-based HTTP client, which allows you to choose a HTTP client.
|
4
|
+
#
|
5
|
+
# See <https://github.com/technoweenie/faraday/tree/master/lib/faraday/adapter>
|
6
|
+
#
|
7
|
+
# NOTE: Tire will switch to Faraday for the HTTP abstraction layer. This client is a temporary solution.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
# --------
|
11
|
+
#
|
12
|
+
# require 'typhoeus'
|
13
|
+
# require 'tire/http/clients/faraday'
|
14
|
+
#
|
15
|
+
# Tire.configure do |config|
|
16
|
+
#
|
17
|
+
# # Unless specified, tire will use Faraday.default_adapter and no middleware
|
18
|
+
# Tire::HTTP::Client::Faraday.faraday_middleware = Proc.new do |builder|
|
19
|
+
# builder.adapter :typhoeus
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# config.client(Tire::HTTP::Client::Faraday)
|
23
|
+
#
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
#
|
27
|
+
module Tire
|
28
|
+
module HTTP
|
29
|
+
module Client
|
30
|
+
class Faraday
|
31
|
+
|
32
|
+
# Default middleware stack.
|
33
|
+
DEFAULT_MIDDLEWARE = Proc.new do |builder|
|
34
|
+
builder.adapter ::Faraday.default_adapter
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
# A customized stack of Faraday middleware that will be used to make each request.
|
39
|
+
attr_accessor :faraday_middleware
|
40
|
+
|
41
|
+
def get(url, data = nil)
|
42
|
+
request(:get, url, data)
|
43
|
+
end
|
44
|
+
|
45
|
+
def post(url, data)
|
46
|
+
request(:post, url, data)
|
47
|
+
end
|
48
|
+
|
49
|
+
def put(url, data)
|
50
|
+
request(:put, url, data)
|
51
|
+
end
|
52
|
+
|
53
|
+
def delete(url, data = nil)
|
54
|
+
request(:delete, url, data)
|
55
|
+
end
|
56
|
+
|
57
|
+
def head(url)
|
58
|
+
request(:head, url)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def request(method, url, data = nil)
|
63
|
+
conn = ::Faraday.new( &(faraday_middleware || DEFAULT_MIDDLEWARE) )
|
64
|
+
response = conn.run_request(method, url, data, nil)
|
65
|
+
Response.new(response.body, response.status, response.headers)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Tire
|
2
|
+
|
3
|
+
module HTTP
|
4
|
+
|
5
|
+
class Response
|
6
|
+
attr_reader :body, :code, :headers
|
7
|
+
|
8
|
+
def initialize(body, code, headers={})
|
9
|
+
@body, @code, @headers = body, code.to_i, headers
|
10
|
+
end
|
11
|
+
|
12
|
+
def success?
|
13
|
+
code > 0 && code < 400
|
14
|
+
end
|
15
|
+
|
16
|
+
def failure?
|
17
|
+
! success?
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
[code, body].join(' : ')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/tire/index.rb
ADDED
@@ -0,0 +1,361 @@
|
|
1
|
+
module Tire
|
2
|
+
class Index
|
3
|
+
|
4
|
+
attr_reader :name, :response
|
5
|
+
|
6
|
+
def initialize(name, &block)
|
7
|
+
@name = name
|
8
|
+
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def url
|
12
|
+
"#{Configuration.url}/#{@name}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def exists?
|
16
|
+
@response = Configuration.client.head("#{url}")
|
17
|
+
@response.success?
|
18
|
+
|
19
|
+
ensure
|
20
|
+
curl = %Q|curl -I "#{url}"|
|
21
|
+
logged('HEAD', curl)
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete
|
25
|
+
@response = Configuration.client.delete url
|
26
|
+
@response.success?
|
27
|
+
|
28
|
+
ensure
|
29
|
+
curl = %Q|curl -X DELETE #{url}|
|
30
|
+
logged('DELETE', curl)
|
31
|
+
end
|
32
|
+
|
33
|
+
def create(options={})
|
34
|
+
@options = options
|
35
|
+
@response = Configuration.client.post url, MultiJson.encode(options)
|
36
|
+
@response.success? ? @response : false
|
37
|
+
|
38
|
+
ensure
|
39
|
+
curl = %Q|curl -X POST #{url} -d '#{MultiJson.encode(options)}'|
|
40
|
+
logged('CREATE', curl)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_alias(alias_name, configuration={})
|
44
|
+
Alias.create(configuration.merge( :name => alias_name, :index => @name ) )
|
45
|
+
end
|
46
|
+
|
47
|
+
def remove_alias(alias_name)
|
48
|
+
Alias.find(alias_name) { |a| a.indices.delete @name }.save
|
49
|
+
end
|
50
|
+
|
51
|
+
def aliases(alias_name=nil)
|
52
|
+
alias_name ? Alias.all(@name).select { |a| a.name == alias_name }.first : Alias.all(@name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def mapping
|
56
|
+
@response = Configuration.client.get("#{url}/_mapping")
|
57
|
+
MultiJson.decode(@response.body)[@name]
|
58
|
+
end
|
59
|
+
|
60
|
+
def settings
|
61
|
+
@response = Configuration.client.get("#{url}/_settings")
|
62
|
+
MultiJson.decode(@response.body)[@name]['settings']
|
63
|
+
end
|
64
|
+
|
65
|
+
def store(*args)
|
66
|
+
document, options = args
|
67
|
+
type = get_type_from_document(document)
|
68
|
+
|
69
|
+
if options
|
70
|
+
percolate = options[:percolate]
|
71
|
+
percolate = "*" if percolate === true
|
72
|
+
end
|
73
|
+
|
74
|
+
id = get_id_from_document(document)
|
75
|
+
document = convert_document_to_json(document)
|
76
|
+
|
77
|
+
url = id ? "#{self.url}/#{type}/#{id}" : "#{self.url}/#{type}/"
|
78
|
+
url += "?percolate=#{percolate}" if percolate
|
79
|
+
|
80
|
+
@response = Configuration.client.post url, document
|
81
|
+
MultiJson.decode(@response.body)
|
82
|
+
|
83
|
+
ensure
|
84
|
+
curl = %Q|curl -X POST "#{url}" -d '#{document}'|
|
85
|
+
logged([type, id].join('/'), curl)
|
86
|
+
end
|
87
|
+
|
88
|
+
def bulk_store(documents, options={})
|
89
|
+
payload = documents.map do |document|
|
90
|
+
type = get_type_from_document(document, :escape => false) # Do not URL-escape the _type
|
91
|
+
id = get_id_from_document(document)
|
92
|
+
|
93
|
+
STDERR.puts "[ERROR] Document #{document.inspect} does not have ID" unless id
|
94
|
+
|
95
|
+
output = []
|
96
|
+
output << %Q|{"index":{"_index":"#{@name}","_type":"#{type}","_id":"#{id}"}}|
|
97
|
+
output << convert_document_to_json(document)
|
98
|
+
output.join("\n")
|
99
|
+
end
|
100
|
+
payload << ""
|
101
|
+
|
102
|
+
tries = 5
|
103
|
+
count = 0
|
104
|
+
|
105
|
+
begin
|
106
|
+
@response = Configuration.client.post("#{url}/_bulk", payload.join("\n"))
|
107
|
+
raise RuntimeError, "#{@response.code} > #{@response.body}" if @response && @response.failure?
|
108
|
+
@response
|
109
|
+
rescue StandardError => error
|
110
|
+
if count < tries
|
111
|
+
count += 1
|
112
|
+
STDERR.puts "[ERROR] #{error.message}, retrying (#{count})..."
|
113
|
+
retry
|
114
|
+
else
|
115
|
+
STDERR.puts "[ERROR] Too many exceptions occured, giving up. The HTTP response was: #{error.message}"
|
116
|
+
raise if options[:raise]
|
117
|
+
end
|
118
|
+
|
119
|
+
ensure
|
120
|
+
curl = %Q|curl -X POST "#{url}/_bulk" -d '{... data omitted ...}'|
|
121
|
+
logged('BULK', curl)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def import(klass_or_collection, options={})
|
126
|
+
case
|
127
|
+
when method = options.delete(:method)
|
128
|
+
options = {:page => 1, :per_page => 1000}.merge options
|
129
|
+
while documents = klass_or_collection.send(method.to_sym, options.merge(:page => options[:page])) \
|
130
|
+
and documents.to_a.length > 0
|
131
|
+
|
132
|
+
documents = yield documents if block_given?
|
133
|
+
|
134
|
+
bulk_store documents, options
|
135
|
+
options[:page] += 1
|
136
|
+
end
|
137
|
+
|
138
|
+
when klass_or_collection.respond_to?(:map)
|
139
|
+
documents = block_given? ? yield(klass_or_collection) : klass_or_collection
|
140
|
+
bulk_store documents, options
|
141
|
+
|
142
|
+
else
|
143
|
+
raise ArgumentError, "Please pass either an Enumerable compatible class, or a collection object" +
|
144
|
+
"with a method for fetching records in batches (such as 'paginate')"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def reindex(name, options={}, &block)
|
149
|
+
new_index = Index.new(name)
|
150
|
+
new_index.create(options) unless new_index.exists?
|
151
|
+
|
152
|
+
Search::Scan.new(self.name, &block).each do |results|
|
153
|
+
new_index.bulk_store results.map do |document|
|
154
|
+
document.to_hash.except(:type, :_index, :_explanation, :_score, :_version, :highlight, :sort)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def remove(*args)
|
160
|
+
if args.size > 1
|
161
|
+
type, document = args
|
162
|
+
type = Utils.escape(type)
|
163
|
+
id = get_id_from_document(document) || document
|
164
|
+
else
|
165
|
+
document = args.pop
|
166
|
+
type = get_type_from_document(document)
|
167
|
+
id = get_id_from_document(document) || document
|
168
|
+
end
|
169
|
+
raise ArgumentError, "Please pass a document ID" unless id
|
170
|
+
|
171
|
+
url = "#{self.url}/#{type}/#{id}"
|
172
|
+
result = Configuration.client.delete url
|
173
|
+
MultiJson.decode(result.body) if result.success?
|
174
|
+
|
175
|
+
ensure
|
176
|
+
curl = %Q|curl -X DELETE "#{url}"|
|
177
|
+
logged(id, curl)
|
178
|
+
end
|
179
|
+
|
180
|
+
def retrieve(type, id)
|
181
|
+
raise ArgumentError, "Please pass a document ID" unless id
|
182
|
+
|
183
|
+
type = Utils.escape(type)
|
184
|
+
url = "#{self.url}/#{type}/#{id}"
|
185
|
+
@response = Configuration.client.get url
|
186
|
+
|
187
|
+
h = MultiJson.decode(@response.body)
|
188
|
+
if Configuration.wrapper == Hash then h
|
189
|
+
else
|
190
|
+
return nil if h['exists'] == false
|
191
|
+
document = h['_source'] || h['fields'] || {}
|
192
|
+
document.update('id' => h['_id'], '_type' => h['_type'], '_index' => h['_index'], '_version' => h['_version'])
|
193
|
+
Configuration.wrapper.new(document)
|
194
|
+
end
|
195
|
+
|
196
|
+
ensure
|
197
|
+
curl = %Q|curl -X GET "#{url}"|
|
198
|
+
logged(id, curl)
|
199
|
+
end
|
200
|
+
|
201
|
+
def update(type, id, payload={}, options={})
|
202
|
+
raise ArgumentError, "Please pass a document type" unless type
|
203
|
+
raise ArgumentError, "Please pass a document ID" unless id
|
204
|
+
raise ArgumentError, "Please pass a script in the payload hash" unless payload[:script]
|
205
|
+
|
206
|
+
type = Utils.escape(type)
|
207
|
+
url = "#{self.url}/#{type}/#{id}/_update"
|
208
|
+
url += "?#{options.to_param}" unless options.keys.empty?
|
209
|
+
@response = Configuration.client.post url, MultiJson.encode(payload)
|
210
|
+
MultiJson.decode(@response.body)
|
211
|
+
|
212
|
+
ensure
|
213
|
+
curl = %Q|curl -X POST "#{url}" -d '#{MultiJson.encode(payload)}'|
|
214
|
+
logged(id, curl)
|
215
|
+
end
|
216
|
+
|
217
|
+
def refresh
|
218
|
+
@response = Configuration.client.post "#{url}/_refresh", ''
|
219
|
+
|
220
|
+
ensure
|
221
|
+
curl = %Q|curl -X POST "#{url}/_refresh"|
|
222
|
+
logged('_refresh', curl)
|
223
|
+
end
|
224
|
+
|
225
|
+
def open(options={})
|
226
|
+
# TODO: Remove the duplication in the execute > rescue > ensure chain
|
227
|
+
@response = Configuration.client.post "#{url}/_open", MultiJson.encode(options)
|
228
|
+
MultiJson.decode(@response.body)['ok']
|
229
|
+
|
230
|
+
ensure
|
231
|
+
curl = %Q|curl -X POST "#{url}/_open"|
|
232
|
+
logged('_open', curl)
|
233
|
+
end
|
234
|
+
|
235
|
+
def close(options={})
|
236
|
+
@response = Configuration.client.post "#{url}/_close", MultiJson.encode(options)
|
237
|
+
MultiJson.decode(@response.body)['ok']
|
238
|
+
|
239
|
+
ensure
|
240
|
+
curl = %Q|curl -X POST "#{url}/_close"|
|
241
|
+
logged('_close', curl)
|
242
|
+
end
|
243
|
+
|
244
|
+
def analyze(text, options={})
|
245
|
+
options = {:pretty => true}.update(options)
|
246
|
+
params = options.to_param
|
247
|
+
@response = Configuration.client.get "#{url}/_analyze?#{params}", text
|
248
|
+
@response.success? ? MultiJson.decode(@response.body) : false
|
249
|
+
|
250
|
+
ensure
|
251
|
+
curl = %Q|curl -X GET "#{url}/_analyze?#{params}" -d '#{text}'|
|
252
|
+
logged('_analyze', curl)
|
253
|
+
end
|
254
|
+
|
255
|
+
def register_percolator_query(name, options={}, &block)
|
256
|
+
options[:query] = Search::Query.new(&block).to_hash if block_given?
|
257
|
+
|
258
|
+
@response = Configuration.client.put "#{Configuration.url}/_percolator/#{@name}/#{name}", MultiJson.encode(options)
|
259
|
+
MultiJson.decode(@response.body)['ok']
|
260
|
+
|
261
|
+
ensure
|
262
|
+
curl = %Q|curl -X PUT "#{Configuration.url}/_percolator/#{@name}/#{name}?pretty=1" -d '#{MultiJson.encode(options)}'|
|
263
|
+
logged('_percolator', curl)
|
264
|
+
end
|
265
|
+
|
266
|
+
def unregister_percolator_query(name)
|
267
|
+
@response = Configuration.client.delete "#{Configuration.url}/_percolator/#{@name}/#{name}"
|
268
|
+
MultiJson.decode(@response.body)['ok']
|
269
|
+
|
270
|
+
ensure
|
271
|
+
curl = %Q|curl -X DELETE "#{Configuration.url}/_percolator/#{@name}"|
|
272
|
+
logged('_percolator', curl)
|
273
|
+
end
|
274
|
+
|
275
|
+
def percolate(*args, &block)
|
276
|
+
document = args.shift
|
277
|
+
type = get_type_from_document(document)
|
278
|
+
|
279
|
+
document = MultiJson.decode convert_document_to_json(document)
|
280
|
+
|
281
|
+
query = Search::Query.new(&block).to_hash if block_given?
|
282
|
+
|
283
|
+
payload = { :doc => document }
|
284
|
+
payload.update( :query => query ) if query
|
285
|
+
|
286
|
+
@response = Configuration.client.get "#{url}/#{type}/_percolate", MultiJson.encode(payload)
|
287
|
+
MultiJson.decode(@response.body)['matches']
|
288
|
+
|
289
|
+
ensure
|
290
|
+
curl = %Q|curl -X GET "#{url}/#{type}/_percolate?pretty=1" -d '#{payload.to_json}'|
|
291
|
+
logged('_percolate', curl)
|
292
|
+
end
|
293
|
+
|
294
|
+
def logged(endpoint='/', curl='')
|
295
|
+
if Configuration.logger
|
296
|
+
error = $!
|
297
|
+
|
298
|
+
Configuration.logger.log_request endpoint, @name, curl
|
299
|
+
|
300
|
+
code = @response ? @response.code : error.class rescue 'N/A'
|
301
|
+
|
302
|
+
if Configuration.logger.level.to_s == 'debug'
|
303
|
+
body = if @response
|
304
|
+
defined?(Yajl) ? Yajl::Encoder.encode(@response.body, :pretty => true) : MultiJson.encode(@response.body)
|
305
|
+
else
|
306
|
+
error.message rescue ''
|
307
|
+
end
|
308
|
+
else
|
309
|
+
body = ''
|
310
|
+
end
|
311
|
+
|
312
|
+
Configuration.logger.log_response code, nil, body
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def get_type_from_document(document, options={})
|
317
|
+
options = {:escape => true}.merge(options)
|
318
|
+
|
319
|
+
old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#type deprecation warnings
|
320
|
+
type = case
|
321
|
+
when document.respond_to?(:document_type)
|
322
|
+
document.document_type
|
323
|
+
when document.is_a?(Hash)
|
324
|
+
document[:_type] || document['_type'] || document[:type] || document['type']
|
325
|
+
when document.respond_to?(:_type)
|
326
|
+
document._type
|
327
|
+
when document.respond_to?(:type) && document.type != document.class
|
328
|
+
document.type
|
329
|
+
end
|
330
|
+
$VERBOSE = old_verbose
|
331
|
+
|
332
|
+
type ||= 'document'
|
333
|
+
options[:escape] ? Utils.escape(type) : type
|
334
|
+
end
|
335
|
+
|
336
|
+
def get_id_from_document(document)
|
337
|
+
old_verbose, $VERBOSE = $VERBOSE, nil # Silence Object#id deprecation warnings
|
338
|
+
id = case
|
339
|
+
when document.is_a?(Hash)
|
340
|
+
document[:_id] || document['_id'] || document[:id] || document['id']
|
341
|
+
when document.respond_to?(:id) && document.id != document.object_id
|
342
|
+
document.id
|
343
|
+
end
|
344
|
+
$VERBOSE = old_verbose
|
345
|
+
id
|
346
|
+
end
|
347
|
+
|
348
|
+
def convert_document_to_json(document)
|
349
|
+
document = case
|
350
|
+
when document.is_a?(String)
|
351
|
+
Tire.warn "Passing the document as JSON string in Index#store has been deprecated, " +
|
352
|
+
"please pass an object which responds to `to_indexed_json` or a plain Hash."
|
353
|
+
document
|
354
|
+
when document.respond_to?(:to_indexed_json) then document.to_indexed_json
|
355
|
+
else raise ArgumentError, "Please pass a JSON string or object with a 'to_indexed_json' method," +
|
356
|
+
"'#{document.class}' given."
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
end
|