tire 0.4.2 → 0.4.3
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/.travis.yml +18 -2
- data/README.markdown +2 -2
- data/examples/tire-dsl.rb +1 -1
- data/lib/tire.rb +1 -0
- data/lib/tire/http/clients/faraday.rb +71 -0
- data/lib/tire/index.rb +30 -7
- data/lib/tire/logger.rb +1 -1
- data/lib/tire/model/persistence.rb +2 -3
- data/lib/tire/model/persistence/finders.rb +2 -2
- data/lib/tire/model/persistence/storage.rb +3 -5
- data/lib/tire/model/search.rb +2 -0
- data/lib/tire/results/collection.rb +8 -8
- data/lib/tire/results/item.rb +4 -1
- data/lib/tire/search.rb +30 -2
- data/lib/tire/search/facet.rb +5 -1
- data/lib/tire/search/query.rb +36 -1
- data/lib/tire/search/script_field.rb +23 -0
- data/lib/tire/tasks.rb +1 -1
- data/lib/tire/version.rb +8 -15
- data/test/integration/dis_max_queries_test.rb +68 -0
- data/test/integration/facets_test.rb +27 -0
- data/test/integration/index_store_test.rb +17 -1
- data/test/integration/index_update_document_test.rb +111 -0
- data/test/integration/persistent_model_test.rb +13 -0
- data/test/integration/prefix_query_test.rb +43 -0
- data/test/integration/reindex_test.rb +10 -0
- data/test/integration/script_fields_test.rb +38 -0
- data/test/test_helper.rb +6 -1
- data/test/unit/index_test.rb +58 -5
- data/test/unit/model_persistence_test.rb +14 -2
- data/test/unit/model_search_test.rb +14 -0
- data/test/unit/results_item_test.rb +9 -2
- data/test/unit/rubyext_test.rb +6 -0
- data/test/unit/search_query_test.rb +61 -2
- data/test/unit/search_script_field_test.rb +26 -0
- data/test/unit/search_test.rb +46 -2
- data/tire.gemspec +1 -1
- metadata +62 -53
data/.travis.yml
CHANGED
@@ -2,12 +2,28 @@
|
|
2
2
|
# Configuration file for http://travis-ci.org/#!/karmi/tire
|
3
3
|
# ---------------------------------------------------------
|
4
4
|
|
5
|
-
|
5
|
+
language: ruby
|
6
6
|
|
7
7
|
rvm:
|
8
|
-
- 1.8.7
|
9
8
|
- 1.9.3
|
9
|
+
- 1.8.7
|
10
10
|
- ree
|
11
11
|
|
12
|
+
env:
|
13
|
+
- TEST_COMMAND="rake test:unit"
|
14
|
+
- TEST_COMMAND="rake test:integration"
|
15
|
+
|
16
|
+
script: "bundle exec $TEST_COMMAND"
|
17
|
+
|
18
|
+
before_install:
|
19
|
+
- sudo service elasticsearch start
|
20
|
+
|
21
|
+
matrix:
|
22
|
+
exclude:
|
23
|
+
- rvm: 1.8.7
|
24
|
+
env: TEST_COMMAND="rake test:integration"
|
25
|
+
- rvm: ree
|
26
|
+
env: TEST_COMMAND="rake test:integration"
|
27
|
+
|
12
28
|
notifications:
|
13
29
|
disable: true
|
data/README.markdown
CHANGED
@@ -675,7 +675,7 @@ OK. All this time we have been talking about `ActiveRecord` models, since
|
|
675
675
|
it is a reasonable _Rails_' default for the storage layer.
|
676
676
|
|
677
677
|
But what if you use another database such as [MongoDB](http://www.mongodb.org/),
|
678
|
-
another object mapping library, such as [Mongoid](http://mongoid.org/)?
|
678
|
+
another object mapping library, such as [Mongoid](http://mongoid.org/) or [MongoMapper](http://mongomapper.com/)?
|
679
679
|
|
680
680
|
Well, things stay mostly the same:
|
681
681
|
|
@@ -691,7 +691,7 @@ Well, things stay mostly the same:
|
|
691
691
|
# These Mongo guys sure do get funky with their IDs in +serializable_hash+, let's fix it.
|
692
692
|
#
|
693
693
|
def to_indexed_json
|
694
|
-
self.
|
694
|
+
self.to_json
|
695
695
|
end
|
696
696
|
|
697
697
|
end
|
data/examples/tire-dsl.rb
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
# from <https://github.com/karmi/tire>.
|
13
13
|
#
|
14
14
|
# By following these instructions you should have the search running
|
15
|
-
# on a sane
|
15
|
+
# on a sane operating system in less then 10 minutes.
|
16
16
|
|
17
17
|
# Note, that this file can be executed directly:
|
18
18
|
#
|
data/lib/tire.rb
CHANGED
@@ -25,6 +25,7 @@ require 'tire/search/facet'
|
|
25
25
|
require 'tire/search/filter'
|
26
26
|
require 'tire/search/highlight'
|
27
27
|
require 'tire/search/scan'
|
28
|
+
require 'tire/search/script_field'
|
28
29
|
require 'tire/results/pagination'
|
29
30
|
require 'tire/results/collection'
|
30
31
|
require 'tire/results/item'
|
@@ -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
|
data/lib/tire/index.rb
CHANGED
@@ -103,9 +103,9 @@ module Tire
|
|
103
103
|
count = 0
|
104
104
|
|
105
105
|
begin
|
106
|
-
response = Configuration.client.post("#{url}/_bulk", payload.join("\n"))
|
107
|
-
raise RuntimeError, "#{response.code} > #{response.body}" if response.failure?
|
108
|
-
response
|
106
|
+
@response = Configuration.client.post("#{url}/_bulk", payload.join("\n"))
|
107
|
+
raise RuntimeError, "#{@response.code} > #{@response.body}" if @response && @response.failure?
|
108
|
+
@response
|
109
109
|
rescue StandardError => error
|
110
110
|
if count < tries
|
111
111
|
count += 1
|
@@ -149,10 +149,17 @@ module Tire
|
|
149
149
|
new_index = Index.new(name)
|
150
150
|
new_index.create(options) unless new_index.exists?
|
151
151
|
|
152
|
+
transform = options.delete(:transform)
|
153
|
+
|
152
154
|
Search::Scan.new(self.name, &block).each do |results|
|
153
|
-
|
154
|
-
|
155
|
+
|
156
|
+
documents = results.map do |document|
|
157
|
+
document = document.to_hash.except(:type, :_index, :_explanation, :_score, :_version, :highlight, :sort)
|
158
|
+
document = transform.call(document) if transform
|
159
|
+
document
|
155
160
|
end
|
161
|
+
|
162
|
+
new_index.bulk_store documents
|
156
163
|
end
|
157
164
|
end
|
158
165
|
|
@@ -198,6 +205,22 @@ module Tire
|
|
198
205
|
logged(id, curl)
|
199
206
|
end
|
200
207
|
|
208
|
+
def update(type, id, payload={}, options={})
|
209
|
+
raise ArgumentError, "Please pass a document type" unless type
|
210
|
+
raise ArgumentError, "Please pass a document ID" unless id
|
211
|
+
raise ArgumentError, "Please pass a script in the payload hash" unless payload[:script]
|
212
|
+
|
213
|
+
type = Utils.escape(type)
|
214
|
+
url = "#{self.url}/#{type}/#{id}/_update"
|
215
|
+
url += "?#{options.to_param}" unless options.keys.empty?
|
216
|
+
@response = Configuration.client.post url, MultiJson.encode(payload)
|
217
|
+
MultiJson.decode(@response.body)
|
218
|
+
|
219
|
+
ensure
|
220
|
+
curl = %Q|curl -X POST "#{url}" -d '#{MultiJson.encode(payload)}'|
|
221
|
+
logged(id, curl)
|
222
|
+
end
|
223
|
+
|
201
224
|
def refresh
|
202
225
|
@response = Configuration.client.post "#{url}/_refresh", ''
|
203
226
|
|
@@ -243,7 +266,7 @@ module Tire
|
|
243
266
|
MultiJson.decode(@response.body)['ok']
|
244
267
|
|
245
268
|
ensure
|
246
|
-
curl = %Q|curl -X PUT "#{Configuration.url}/_percolator/#{@name}
|
269
|
+
curl = %Q|curl -X PUT "#{Configuration.url}/_percolator/#{@name}/#{name}?pretty=1" -d '#{MultiJson.encode(options)}'|
|
247
270
|
logged('_percolator', curl)
|
248
271
|
end
|
249
272
|
|
@@ -281,7 +304,7 @@ module Tire
|
|
281
304
|
|
282
305
|
Configuration.logger.log_request endpoint, @name, curl
|
283
306
|
|
284
|
-
code = @response ? @response.code : error.class rescue
|
307
|
+
code = @response ? @response.code : error.class rescue 'N/A'
|
285
308
|
|
286
309
|
if Configuration.logger.level.to_s == 'debug'
|
287
310
|
body = if @response
|
data/lib/tire/logger.rb
CHANGED
@@ -9,7 +9,7 @@ module Tire
|
|
9
9
|
end
|
10
10
|
@device.sync = true if @device.respond_to?(:sync)
|
11
11
|
@options = options
|
12
|
-
at_exit { @device.close unless @device.closed? } if @device.respond_to?(:closed?) && @device.respond_to?(:close)
|
12
|
+
# at_exit { @device.close unless @device.closed? } if @device.respond_to?(:closed?) && @device.respond_to?(:close)
|
13
13
|
end
|
14
14
|
|
15
15
|
def level
|
@@ -51,9 +51,8 @@ module Tire
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def self.search(*args, &block)
|
54
|
-
|
55
|
-
args
|
56
|
-
args << { :wrapper => self } unless args.any? { |a| a.is_a? Hash }
|
54
|
+
args.last.update(:wrapper => self, :version => true) if args.last.is_a? Hash
|
55
|
+
args << { :wrapper => self, :version => true } unless args.any? { |a| a.is_a? Hash }
|
57
56
|
|
58
57
|
self.__search_without_persistence(*args, &block)
|
59
58
|
end
|
@@ -41,7 +41,7 @@ module Tire
|
|
41
41
|
old_wrapper = Tire::Configuration.wrapper
|
42
42
|
Tire::Configuration.wrapper self
|
43
43
|
s = Tire::Search::Search.new(index.name).query { all }
|
44
|
-
s.results
|
44
|
+
s.version(true).results
|
45
45
|
ensure
|
46
46
|
Tire::Configuration.wrapper old_wrapper
|
47
47
|
end
|
@@ -51,7 +51,7 @@ module Tire
|
|
51
51
|
old_wrapper = Tire::Configuration.wrapper
|
52
52
|
Tire::Configuration.wrapper self
|
53
53
|
s = Tire::Search::Search.new(index.name).query { all }.size(1)
|
54
|
-
s.results.first
|
54
|
+
s.version(true).results.first
|
55
55
|
ensure
|
56
56
|
Tire::Configuration.wrapper old_wrapper
|
57
57
|
end
|
@@ -55,11 +55,9 @@ module Tire
|
|
55
55
|
self.freeze
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
def
|
61
|
-
|
62
|
-
def persisted?; !!id; end
|
58
|
+
def destroyed? ; !!@destroyed; end
|
59
|
+
def persisted? ; !!id && !!_version; end
|
60
|
+
def new_record? ; !persisted?; end
|
63
61
|
|
64
62
|
end
|
65
63
|
|
data/lib/tire/model/search.rb
CHANGED
@@ -25,17 +25,17 @@ module Tire
|
|
25
25
|
hits
|
26
26
|
else
|
27
27
|
hits.map do |h|
|
28
|
-
|
28
|
+
document = {}
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
# Update the document with content and ID
|
31
|
+
document = h['_source'] ? document.update( h['_source'] || {} ) : document.update( __parse_fields__(h['fields']) )
|
32
|
+
document.update( {'id' => h['_id']} )
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
# Update the document with meta information
|
35
|
+
['_score', '_type', '_index', '_version', 'sort', 'highlight', '_explanation'].each { |key| document.update( {key => h[key]} || {} ) }
|
36
36
|
|
37
|
-
|
38
|
-
|
37
|
+
# Return an instance of the "wrapper" class
|
38
|
+
@wrapper.new(document)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
data/lib/tire/results/item.rb
CHANGED
data/lib/tire/search.rb
CHANGED
@@ -4,10 +4,15 @@ module Tire
|
|
4
4
|
|
5
5
|
class Search
|
6
6
|
|
7
|
-
attr_reader :indices, :
|
7
|
+
attr_reader :indices, :query, :facets, :filters, :options, :explain, :script_fields
|
8
8
|
|
9
9
|
def initialize(indices=nil, options={}, &block)
|
10
|
-
|
10
|
+
if indices.is_a?(Hash)
|
11
|
+
set_indices_options(indices)
|
12
|
+
@indices = indices.keys
|
13
|
+
else
|
14
|
+
@indices = Array(indices)
|
15
|
+
end
|
11
16
|
@types = Array(options.delete(:type)).map { |type| Utils.escape(type) }
|
12
17
|
@options = options
|
13
18
|
|
@@ -16,6 +21,16 @@ module Tire
|
|
16
21
|
block.arity < 1 ? instance_eval(&block) : block.call(self) if block_given?
|
17
22
|
end
|
18
23
|
|
24
|
+
|
25
|
+
def set_indices_options(indices)
|
26
|
+
indices.each do |index, index_options|
|
27
|
+
if index_options[:boost]
|
28
|
+
@indices_boost ||= {}
|
29
|
+
@indices_boost[index] = index_options[:boost]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
19
34
|
def results
|
20
35
|
@results || (perform; @results)
|
21
36
|
end
|
@@ -24,6 +39,10 @@ module Tire
|
|
24
39
|
@response || (perform; @response)
|
25
40
|
end
|
26
41
|
|
42
|
+
def json
|
43
|
+
@json || (perform; @json)
|
44
|
+
end
|
45
|
+
|
27
46
|
def url
|
28
47
|
Configuration.url + @path
|
29
48
|
end
|
@@ -55,6 +74,12 @@ module Tire
|
|
55
74
|
self
|
56
75
|
end
|
57
76
|
|
77
|
+
def script_field(name, options={})
|
78
|
+
@script_fields ||= {}
|
79
|
+
@script_fields.merge! ScriptField.new(name, options).to_hash
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
58
83
|
def highlight(*args)
|
59
84
|
unless args.empty?
|
60
85
|
@highlight = Highlight.new(*args)
|
@@ -88,6 +113,7 @@ module Tire
|
|
88
113
|
|
89
114
|
def version(value)
|
90
115
|
@version = value
|
116
|
+
self
|
91
117
|
end
|
92
118
|
|
93
119
|
def perform
|
@@ -110,6 +136,7 @@ module Tire
|
|
110
136
|
def to_hash
|
111
137
|
@options.delete(:payload) || begin
|
112
138
|
request = {}
|
139
|
+
request.update( { :indices_boost => @indices_boost } ) if @indices_boost
|
113
140
|
request.update( { :query => @query.to_hash } ) if @query
|
114
141
|
request.update( { :sort => @sort.to_ary } ) if @sort
|
115
142
|
request.update( { :facets => @facets.to_hash } ) if @facets
|
@@ -119,6 +146,7 @@ module Tire
|
|
119
146
|
request.update( { :size => @size } ) if @size
|
120
147
|
request.update( { :from => @from } ) if @from
|
121
148
|
request.update( { :fields => @fields } ) if @fields
|
149
|
+
request.update( { :script_fields => @script_fields } ) if @script_fields
|
122
150
|
request.update( { :version => @version } ) if @version
|
123
151
|
request.update( { :explain => @explain } ) if @explain
|
124
152
|
request
|
data/lib/tire/search/facet.rb
CHANGED
@@ -17,7 +17,11 @@ module Tire
|
|
17
17
|
def terms(field, options={})
|
18
18
|
size = options.delete(:size) || 10
|
19
19
|
all_terms = options.delete(:all_terms) || false
|
20
|
-
@value =
|
20
|
+
@value = if field.is_a?(Enumerable) and not field.is_a?(String)
|
21
|
+
{ :terms => { :fields => field }.update({ :size => size, :all_terms => all_terms }).update(options) }
|
22
|
+
else
|
23
|
+
{ :terms => { :field => field }.update({ :size => size, :all_terms => all_terms }).update(options) }
|
24
|
+
end
|
21
25
|
self
|
22
26
|
end
|
23
27
|
|
data/lib/tire/search/query.rb
CHANGED
@@ -34,6 +34,14 @@ module Tire
|
|
34
34
|
@value
|
35
35
|
end
|
36
36
|
|
37
|
+
def prefix(field, value, options={})
|
38
|
+
if options[:boost]
|
39
|
+
@value = { :prefix => { field => { :prefix => value, :boost => options[:boost] } } }
|
40
|
+
else
|
41
|
+
@value = { :prefix => { field => value } }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
37
45
|
def custom_score(options={}, &block)
|
38
46
|
@custom_score ||= Query.new(&block)
|
39
47
|
@value[:custom_score] = options
|
@@ -60,6 +68,13 @@ module Tire
|
|
60
68
|
@value
|
61
69
|
end
|
62
70
|
|
71
|
+
def dis_max(options={}, &block)
|
72
|
+
@dis_max ||= DisMaxQuery.new(options)
|
73
|
+
block.arity < 1 ? @dis_max.instance_eval(&block) : block.call(@dis_max) if block_given?
|
74
|
+
@value[:dis_max] = @dis_max.to_hash
|
75
|
+
@value
|
76
|
+
end
|
77
|
+
|
63
78
|
def all
|
64
79
|
@value = { :match_all => {} }
|
65
80
|
@value
|
@@ -119,7 +134,6 @@ module Tire
|
|
119
134
|
end
|
120
135
|
end
|
121
136
|
|
122
|
-
|
123
137
|
class FilteredQuery
|
124
138
|
def initialize(&block)
|
125
139
|
@value = {}
|
@@ -147,5 +161,26 @@ module Tire
|
|
147
161
|
end
|
148
162
|
end
|
149
163
|
|
164
|
+
class DisMaxQuery
|
165
|
+
def initialize(options={}, &block)
|
166
|
+
@options = options
|
167
|
+
@value = {}
|
168
|
+
block.arity < 1 ? self.instance_eval(&block) : block.call(self) if block_given?
|
169
|
+
end
|
170
|
+
|
171
|
+
def query(&block)
|
172
|
+
(@value[:queries] ||= []) << Query.new(&block).to_hash
|
173
|
+
@value
|
174
|
+
end
|
175
|
+
|
176
|
+
def to_hash
|
177
|
+
@value.update(@options)
|
178
|
+
end
|
179
|
+
|
180
|
+
def to_json
|
181
|
+
to_hash.to_json
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
150
185
|
end
|
151
186
|
end
|