tire 0.5.8 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -28,13 +28,6 @@ module Tire
28
28
  @value = { :range => { field => value } }
29
29
  end
30
30
 
31
- def text(field, value, options={})
32
- Tire.warn "The 'text' query has been deprecated, please use a 'match' query."
33
- query_options = { :query => value }.update(options)
34
- @value = { :text => { field => query_options } }
35
- @value
36
- end
37
-
38
31
  def string(value, options={})
39
32
  @value = { :query_string => { :query => value } }
40
33
  @value[:query_string].update(options)
@@ -98,8 +91,10 @@ module Tire
98
91
  @value
99
92
  end
100
93
 
101
- def ids(values, type)
102
- @value = { :ids => { :values => values, :type => type } }
94
+ def ids(values, type=nil)
95
+ @value = { :ids => { :values => Array(values) } }
96
+ @value[:ids].update(:type => type) if type
97
+ @value
103
98
  end
104
99
 
105
100
  def boosting(options={}, &block)
@@ -193,7 +188,10 @@ module Tire
193
188
  end
194
189
 
195
190
  def filter(type, *options)
196
- @value.update(:filter => Filter.new(type, *options).to_hash)
191
+ @value[:filter] ||= {}
192
+ @value[:filter][:and] ||= []
193
+ @value[:filter][:and] << Filter.new(type, *options).to_hash
194
+ @value
197
195
  end
198
196
 
199
197
  def query(&block)
data/lib/tire/tasks.rb CHANGED
@@ -87,11 +87,6 @@ namespace :tire do
87
87
  namespace :import do
88
88
  desc import_model_desc
89
89
  task :model do
90
- if defined?(Rails)
91
- puts "[IMPORT] Rails detected, loading environment..."
92
- Rake::Task["environment"].invoke
93
- end
94
-
95
90
  if ENV['CLASS'].to_s == ''
96
91
  puts '='*90, 'USAGE', '='*90, import_model_desc, ""
97
92
  exit(1)
@@ -121,11 +116,6 @@ namespace :tire do
121
116
 
122
117
  desc import_all_desc
123
118
  task :all do
124
- if defined?(Rails)
125
- puts "[IMPORT] Rails detected, loading environment..."
126
- Rake::Task["environment"].invoke
127
- end
128
-
129
119
  dir = ENV['DIR'].to_s != '' ? ENV['DIR'] : Rails.root.join("app/models")
130
120
  params = eval(ENV['PARAMS'].to_s) || {}
131
121
 
@@ -134,7 +124,7 @@ namespace :tire do
134
124
  require path
135
125
 
136
126
  model_filename = path[/#{Regexp.escape(dir.to_s)}\/([^\.]+).rb/, 1]
137
- klass = model_filename.classify.constantize
127
+ klass = model_filename.camelize.constantize
138
128
 
139
129
  # Skip if the class doesn't have Tire integration
140
130
  next unless klass.respond_to?(:tire)
data/lib/tire/version.rb CHANGED
@@ -1,14 +1,20 @@
1
1
  module Tire
2
- VERSION = "0.5.8"
2
+ VERSION = "0.6.0"
3
3
 
4
4
  CHANGELOG =<<-END
5
5
  IMPORTANT CHANGES LATELY:
6
6
 
7
- * Fixed, that Model::Persistence uses "string" as the default mapping type
8
- * Fixed, that Model::Persistence returns true/false for #save and #destroy operations
9
- * Fixed the `uninitialized constant HRULE` in Rake tasks
10
- * Fixed `Item#to_hash` functionality to work with Arrays
11
- * Updated the Rails application template and install instructions
12
- * Improved the test suite for Travis
7
+ * Fixed incorrect inflection in the Rake import tasks
8
+ * Added support for `geo_distance` facets
9
+ * Added support for the `custom_filters_score` query
10
+ * Added a custom strategy option to <Model.import>
11
+ * Allow the `:wrapper` option to be passed to Tire.search consistently
12
+ * Improved the Mongoid importing strategy
13
+ * Merge returned `fields` with `_source` if both are returned
14
+ * Removed the deprecated `text` query
15
+ * [FIX] Rescue HTTP client specific connection errors in MyModel#create_elasticsearch_index
16
+ * Added support for passing `version` in Tire::Index#store
17
+ * Added support for `_version_type` in Tire::Index#bulk
18
+ * Added ActiveModel::Serializers compatibility
13
19
  END
14
20
  end
@@ -79,6 +79,19 @@ module Tire
79
79
  end
80
80
  end
81
81
  end
82
+
83
+ should "take external versioning into account" do
84
+ # Tire.configure { logger STDERR, level: 'verbose' }
85
+ index = Tire.index 'bulk-test-external-versioning' do
86
+ delete
87
+ create
88
+ store id: '1', title: 'A', _version: 10, _version_type: 'external'
89
+ end
90
+
91
+ response = index.bulk_store [ { id: '1', title: 'A', _version: 0, _version_type: 'external'} ]
92
+
93
+ assert_match /VersionConflictEngineException/, MultiJson.load(response.body)['items'][0]['index']['error']
94
+ end
82
95
  end
83
96
 
84
97
  end
@@ -0,0 +1,105 @@
1
+ require 'test_helper'
2
+
3
+ module Tire
4
+
5
+ class CustomFiltersScoreQueriesIntegrationTest < Test::Unit::TestCase
6
+ include Test::Integration
7
+
8
+ context "Custom filters score queries" do
9
+
10
+ should "score the document based on a matching filter" do
11
+ s = Tire.search('articles-test') do
12
+ query do
13
+ custom_filters_score do
14
+ query { all }
15
+
16
+ # Give documents over 300 words a score of 3
17
+ filter do
18
+ filter :range, words: { gt: 300 }
19
+ boost 3
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ assert_equal 3, s.results[0]._score
26
+ assert_equal 1, s.results[1]._score
27
+ end
28
+
29
+ should "allow to use a script based boost factor" do
30
+ s = Tire.search('articles-test') do
31
+ query do
32
+ custom_filters_score do
33
+ query { all }
34
+
35
+ # Give documents over 300 words a score of 3
36
+ filter do
37
+ filter :range, words: { gt: 300 }
38
+ script 'doc.words.value * 2'
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ # p s.results.to_a.map { |r| [r.title, r.words, r._score] }
45
+
46
+ assert_equal 750, s.results[0]._score
47
+ assert_equal 1, s.results[1]._score
48
+ end
49
+
50
+ should "allow to define multiple score factors" do
51
+ s = Tire.search('articles-test') do
52
+ query do
53
+ custom_filters_score do
54
+ query { all }
55
+
56
+ # The more words a document contains, the more its score is boosted
57
+
58
+ filter do
59
+ filter :range, words: { to: 10 }
60
+ boost 1
61
+ end
62
+
63
+ filter do
64
+ filter :range, words: { to: 100 }
65
+ boost 2
66
+ end
67
+
68
+ filter do
69
+ filter :range, words: { to: 150 }
70
+ boost 3
71
+ end
72
+
73
+ filter do
74
+ filter :range, words: { to: 250 }
75
+ boost 5
76
+ end
77
+
78
+ filter do
79
+ filter :range, words: { to: 350 }
80
+ boost 7
81
+ end
82
+
83
+ filter do
84
+ filter :range, words: { from: 350 }
85
+ boost 10
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ # p s.results.to_a.map { |r| [r.title, r.words, r._score] }
92
+
93
+ assert_equal 'Three', s.results[0].title
94
+ assert_equal 375, s.results[0].words
95
+ assert_equal 10, s.results[0]._score
96
+
97
+ assert_equal 5, s.results[1]._score
98
+ assert_equal 5, s.results[2]._score
99
+ assert_equal 3, s.results[3]._score
100
+ assert_equal 3, s.results[4]._score
101
+ end
102
+ end
103
+ end
104
+
105
+ end
@@ -39,6 +39,38 @@ module Tire
39
39
  assert_equal 1, s.results.count
40
40
  end
41
41
 
42
+ context "when passing the wrapper option" do
43
+ class ::MyCustomWrapper < Tire::Results::Item
44
+ def title_size
45
+ self.title.size
46
+ end
47
+ end
48
+
49
+ should "be allowed when passing a block" do
50
+ s = Tire.search 'articles-test', wrapper: ::MyCustomWrapper do
51
+ query { match :title, 'one' }
52
+ end
53
+
54
+ assert_equal ::MyCustomWrapper, s.options[:wrapper]
55
+
56
+ assert_instance_of ::MyCustomWrapper, s.results.first
57
+ assert_equal 3, s.results.first.title_size
58
+ end
59
+
60
+ should "be allowed when not passing a block" do
61
+ s = Tire.search(
62
+ 'articles-test',
63
+ payload: { query: { match: { title: 'one' } } },
64
+ wrapper: ::MyCustomWrapper
65
+ )
66
+
67
+ assert_equal ::MyCustomWrapper, s.options[:wrapper]
68
+
69
+ assert_instance_of ::MyCustomWrapper, s.results.first
70
+ assert_equal 3, s.results.first.title_size
71
+ end
72
+ end
73
+
42
74
  end
43
75
 
44
76
  end
@@ -194,6 +194,53 @@ module Tire
194
194
 
195
195
  end
196
196
 
197
+ context "geo distance" do
198
+ setup do
199
+ @index = Tire.index('bars-test') do
200
+ delete
201
+ create :mappings => {
202
+ :bar => {
203
+ :properties => {
204
+ :name => { :type => 'string' },
205
+ :location => { :type => 'geo_point', :lat_lon => true }
206
+ }
207
+ }
208
+ }
209
+
210
+ store :type => 'bar',
211
+ :name => 'one',
212
+ :location => {:lat => 53.54412, :lon => 9.94021}
213
+ store :type => 'bar',
214
+ :name => 'two',
215
+ :location => {:lat => 53.54421, :lon => 9.94673}
216
+ store :type => 'bar',
217
+ :name => 'three',
218
+ :location => {:lat => 53.55099, :lon => 10.02527}
219
+ refresh
220
+ end
221
+ end
222
+
223
+ teardown { @index.delete }
224
+
225
+ should "return aggregated values for all results" do
226
+ s = Tire.search('bars-test') do
227
+ query { all }
228
+ facet 'geo' do
229
+ geo_distance :location,
230
+ {:lat => 53.54507, :lon => 9.95309},
231
+ [{:to => 1}, {:from => 1, :to => 10}, {:from => 50}],
232
+ unit: 'km'
233
+ end
234
+ end
235
+
236
+ facets = s.results.facets['geo']['ranges']
237
+ assert_equal 3, facets.size, facets.inspect
238
+ assert_equal 2, facets.entries[0]['total_count'], facets.inspect
239
+ assert_equal 1, facets.entries[1]['total_count'], facets.inspect
240
+ assert_equal 0, facets.entries[2]['total_count'], facets.inspect
241
+ end
242
+ end
243
+
197
244
  context "statistical" do
198
245
 
199
246
  should "return computed statistical data on a numeric field" do
@@ -10,13 +10,18 @@ module Tire
10
10
  should "allow easy access to returned documents" do
11
11
  q = 'title:one'
12
12
  s = Tire.search('articles-test') { query { string q } }
13
+
13
14
  assert_equal 'One', s.results.first.title
14
15
  assert_equal 'ruby', s.results.first.tags[0]
15
16
  end
16
17
 
17
18
  should "allow easy access to returned documents with limited fields" do
18
19
  q = 'title:one'
19
- s = Tire.search('articles-test') { query { string q }.fields :title }
20
+ s = Tire.search('articles-test') do
21
+ query { string q }
22
+ fields :title
23
+ end
24
+
20
25
  assert_equal 'One', s.results.first.title
21
26
  assert_nil s.results.first.tags
22
27
  end
@@ -27,11 +32,36 @@ module Tire
27
32
  query { string q }
28
33
  fields 'title', 'tags'
29
34
  end
35
+
30
36
  assert_equal 'One', s.results.first.title
31
37
  assert_equal 'ruby', s.results.first.tags[0]
32
38
  assert_nil s.results.first.published_on
33
39
  end
34
40
 
41
+ should "return script fields" do
42
+ s = Tire.search('articles-test') do
43
+ query { string 'title:one' }
44
+ fields :title
45
+ script_field :words_double, :script => "doc.words.value * 2"
46
+ end
47
+
48
+ assert_equal 'One', s.results.first.title
49
+ assert_equal 250, s.results.first.words_double
50
+ end
51
+
52
+ should "return specific fields, script fields and _source fields" do
53
+ # Tire.configure { logger STDERR, level: 'debug' }
54
+
55
+ s = Tire.search('articles-test') do
56
+ query { string 'title:one' }
57
+ fields :title, :_source
58
+ script_field :words_double, :script => "doc.words.value * 2"
59
+ end
60
+
61
+ assert_equal 'One', s.results.first.title
62
+ assert_equal 250, s.results.first.words_double
63
+ end
64
+
35
65
  should "iterate results with hits" do
36
66
  s = Tire.search('articles-test') { query { string 'title:one' } }
37
67
 
@@ -43,6 +43,10 @@ module Tire
43
43
  end
44
44
  end
45
45
 
46
+ should "have __host_unreachable_exceptions" do
47
+ assert_respond_to Client::RestClient, :__host_unreachable_exceptions
48
+ end
49
+
46
50
  end
47
51
 
48
52
  if defined?(Curl)
@@ -81,6 +85,10 @@ module Tire
81
85
  threads.each { |t| t.join() }
82
86
  end
83
87
 
88
+ should "have __host_unreachable_exceptions" do
89
+ assert_respond_to Client::RestClient, :__host_unreachable_exceptions
90
+ end
91
+
84
92
  end
85
93
 
86
94
  end
@@ -335,6 +335,16 @@ module Tire
335
335
  @index.store({:title => 'Test'}, {:replication => 'async'})
336
336
  end
337
337
 
338
+ should "extract the version from options" do
339
+ Configuration.client.expects(:post).
340
+ with do |url, payload|
341
+ assert_equal "#{Configuration.url}/dummy/document/?version=123", url
342
+ end.
343
+ returns(mock_response('{"ok":true,"_id":"test"}'))
344
+
345
+ @index.store({:title => 'Test'}, {:version => 123})
346
+ end
347
+
338
348
  context "document with ID" do
339
349
 
340
350
  should "store a Hash under its ID property" do
@@ -671,26 +681,44 @@ module Tire
671
681
  @index.bulk :delete, [ {:id => '1', :title => 'One'}, {:id => '2', :title => 'Two'} ]
672
682
  end
673
683
 
674
- should "serialize meta parameters such as routing into payload header" do
684
+ should "serialize meta parameters into payload header" do
675
685
  Configuration.client.
676
686
  expects(:post).
677
687
  with do |url, payload|
678
688
  # print payload
679
689
  lines = payload.split("\n")
680
- assert_match /"_routing":"A"/, lines[0]
681
- assert_match /"_routing":"B"/, lines[2]
682
- assert_match /"_ttl":"1d"/, lines[2]
683
- assert ! lines[4].include?('"_routing"')
690
+
691
+ assert_match /"_routing":"A"/, lines[0]
692
+
693
+ assert_match /"_ttl":"1d"/, lines[2]
694
+ assert ! lines[2].include?('"_:parent"')
695
+
696
+ assert_match /"_version":"1234"/, lines[4]
697
+ assert ! lines[4].include?('"_:routing"')
698
+
699
+ assert_match /"_version_type":"external"/, lines[6]
700
+ assert ! lines[6].include?('"_:garbage"')
701
+
702
+ assert_match /"_percolate":"color:green"/, lines[8]
703
+
704
+ assert_match /"_parent":"5678"/, lines[10]
705
+
706
+ assert_match /"_timestamp":"2013-02-15 11:00:33"/, lines[12]
707
+
708
+ true
684
709
  end.
685
710
  returns(mock_response('{}'), 200)
686
711
 
687
712
  @index.bulk :index,
688
713
  [
689
- {:id => '1', :title => 'One', :_routing => 'A'},
690
- {:id => '2', :title => 'Two', :_routing => 'B', :_ttl => '1d'},
691
- {:id => '3', :title => 'Three'}
714
+ {:id => '1', :title => 'One', :_routing => 'A'},
715
+ {:id => '2', :title => 'Two', :_ttl => '1d', :_parent => false},
716
+ {:id => '3', :title => 'Three', :_version => '1234', :_routing => ""},
717
+ {:id => '4', :title => 'Four', :_version_type => 'external', :_garbage => "stuff"},
718
+ {:id => '5', :title => 'Five', :_percolate => 'color:green'},
719
+ {:id => '6', :title => 'Six', :_parent => '5678'},
720
+ {:id => '7', :title => 'Seven', :_timestamp => '2013-02-15 11:00:33'},
692
721
  ]
693
-
694
722
  end
695
723
 
696
724
  should "pass URL parameters such as refresh or consistency" do