tire 0.4.3 → 0.5.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.
- data/.gitignore +1 -1
- data/.yardopts +1 -0
- data/README.markdown +2 -2
- data/examples/rails-application-template.rb +20 -6
- data/lib/tire.rb +2 -0
- data/lib/tire/alias.rb +1 -1
- data/lib/tire/configuration.rb +8 -0
- data/lib/tire/dsl.rb +69 -2
- data/lib/tire/index.rb +33 -20
- data/lib/tire/model/indexing.rb +7 -1
- data/lib/tire/model/persistence.rb +7 -4
- data/lib/tire/model/persistence/attributes.rb +1 -1
- data/lib/tire/model/persistence/finders.rb +4 -16
- data/lib/tire/model/search.rb +21 -8
- data/lib/tire/multi_search.rb +263 -0
- data/lib/tire/results/collection.rb +78 -49
- data/lib/tire/results/item.rb +6 -3
- data/lib/tire/results/pagination.rb +15 -1
- data/lib/tire/rubyext/ruby_1_8.rb +1 -7
- data/lib/tire/rubyext/uri_escape.rb +74 -0
- data/lib/tire/search.rb +33 -11
- data/lib/tire/search/facet.rb +8 -3
- data/lib/tire/search/filter.rb +1 -1
- data/lib/tire/search/highlight.rb +1 -1
- data/lib/tire/search/queries/match.rb +40 -0
- data/lib/tire/search/query.rb +42 -6
- data/lib/tire/search/scan.rb +1 -1
- data/lib/tire/search/script_field.rb +1 -1
- data/lib/tire/search/sort.rb +1 -1
- data/lib/tire/tasks.rb +17 -14
- data/lib/tire/version.rb +26 -8
- data/test/integration/active_record_searchable_test.rb +248 -129
- data/test/integration/boosting_queries_test.rb +32 -0
- data/test/integration/custom_score_queries_test.rb +1 -0
- data/test/integration/dsl_search_test.rb +9 -1
- data/test/integration/facets_test.rb +19 -6
- data/test/integration/match_query_test.rb +79 -0
- data/test/integration/multi_search_test.rb +114 -0
- data/test/integration/persistent_model_test.rb +58 -0
- data/test/models/article.rb +1 -1
- data/test/models/persistent_article_in_index.rb +16 -0
- data/test/models/persistent_article_with_defaults.rb +4 -3
- data/test/test_helper.rb +3 -1
- data/test/unit/configuration_test.rb +10 -0
- data/test/unit/index_test.rb +69 -27
- data/test/unit/model_initialization_test.rb +31 -0
- data/test/unit/model_persistence_test.rb +21 -7
- data/test/unit/model_search_test.rb +56 -5
- data/test/unit/multi_search_test.rb +304 -0
- data/test/unit/results_collection_test.rb +42 -2
- data/test/unit/results_item_test.rb +4 -0
- data/test/unit/search_facet_test.rb +35 -11
- data/test/unit/search_query_test.rb +96 -0
- data/test/unit/search_test.rb +60 -3
- data/test/unit/tire_test.rb +14 -0
- data/tire.gemspec +0 -1
- metadata +75 -44
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
|
5
|
+
class BoostingQueriesIntegrationTest < Test::Unit::TestCase
|
6
|
+
include Test::Integration
|
7
|
+
|
8
|
+
context "Boosting queries" do
|
9
|
+
|
10
|
+
should "allow to set multiple queries per condition" do
|
11
|
+
s = Tire.search('articles-test') do
|
12
|
+
query do
|
13
|
+
boosting(:negative_boost => 0.2) do
|
14
|
+
positive do
|
15
|
+
string "Two One"
|
16
|
+
end
|
17
|
+
negative do
|
18
|
+
term :tags, 'python'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
assert_equal 'One', s.results[0].title
|
25
|
+
assert_equal 'Two', s.results[1].title
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -10,11 +10,19 @@ module Tire
|
|
10
10
|
should "allow passing search payload as a Hash" do
|
11
11
|
s = Tire.search 'articles-test', :query => { :query_string => { :query => 'ruby' } },
|
12
12
|
:facets => { 'tags' => { :filter => { :term => {:tags => 'ruby' } } } }
|
13
|
-
|
13
|
+
|
14
14
|
assert_equal 2, s.results.count
|
15
15
|
assert_equal 2, s.results.facets['tags']['count']
|
16
16
|
end
|
17
17
|
|
18
|
+
should "allow building search query iteratively" do
|
19
|
+
s = Tire.search 'articles-test'
|
20
|
+
s.query { string 'T*' }
|
21
|
+
s.filter :terms, :tags => ['java']
|
22
|
+
|
23
|
+
assert_equal 1, s.results.count
|
24
|
+
end
|
25
|
+
|
18
26
|
end
|
19
27
|
|
20
28
|
end
|
@@ -59,6 +59,21 @@ module Tire
|
|
59
59
|
assert_equal 1, s.results.facets['tags']['terms'].first['count'].to_i
|
60
60
|
end
|
61
61
|
|
62
|
+
should "allow to define the facet filter with DSL" do
|
63
|
+
s = Tire.search('articles-test', :search_type => 'count') do
|
64
|
+
facet 'tags' do
|
65
|
+
terms :tags
|
66
|
+
facet_filter :range, { :published_on => { :from => '2011-01-01', :to => '2011-01-01' } }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
assert_equal 1, s.results.facets.size
|
71
|
+
assert_equal 'ruby', s.results.facets['tags']['terms'].first['term']
|
72
|
+
assert_equal 1, s.results.facets['tags']['terms'].first['count'].to_i
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
62
77
|
context "terms" do
|
63
78
|
setup do
|
64
79
|
@s = Tire.search('articles-test') do
|
@@ -238,19 +253,17 @@ module Tire
|
|
238
253
|
end
|
239
254
|
|
240
255
|
context "filter" do
|
241
|
-
|
242
|
-
|
243
|
-
|
256
|
+
|
257
|
+
should "return a filter facet" do
|
258
|
+
s = Tire.search('articles-test', :search_type => 'count') do
|
244
259
|
facet 'filtered' do
|
245
|
-
filter :
|
260
|
+
filter :range, :words => { :from => 100, :to => 200 }
|
246
261
|
end
|
247
262
|
end
|
248
263
|
|
249
|
-
assert_equal 5, s.results.size, s.results.inspect
|
250
264
|
facets = s.results.facets["filtered"]
|
251
265
|
assert_equal 2, facets["count"], facets.inspect
|
252
266
|
end
|
253
|
-
end
|
254
267
|
|
255
268
|
end
|
256
269
|
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
|
5
|
+
class MatchQueryIntegrationTest < Test::Unit::TestCase
|
6
|
+
include Test::Integration
|
7
|
+
|
8
|
+
context "Match query" do
|
9
|
+
setup do
|
10
|
+
Tire.index 'match-query-test' do
|
11
|
+
delete
|
12
|
+
create settings: { index: { number_of_shards: 1, number_of_replicas: 0 } },
|
13
|
+
mappings: {
|
14
|
+
document: { properties: {
|
15
|
+
last_name: { type: 'string', analyzer: 'english' },
|
16
|
+
age: { type: 'integer' }
|
17
|
+
} }
|
18
|
+
}
|
19
|
+
|
20
|
+
store first_name: 'John', last_name: 'Smith', age: 30, gender: 'male'
|
21
|
+
store first_name: 'John', last_name: 'Smithson', age: 25, gender: 'male'
|
22
|
+
store first_name: 'Adam', last_name: 'Smith', age: 75, gender: 'male'
|
23
|
+
store first_name: 'Mary', last_name: 'John', age: 30, gender: 'female'
|
24
|
+
refresh
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
teardown do
|
29
|
+
Tire.index('match-query-test').delete
|
30
|
+
end
|
31
|
+
|
32
|
+
should "find documents by single field" do
|
33
|
+
s = Tire.search 'match-query-test' do
|
34
|
+
query do
|
35
|
+
match :last_name, 'Smith'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
assert_equal 2, s.results.count
|
40
|
+
end
|
41
|
+
|
42
|
+
should "find document by multiple fields with multi_match" do
|
43
|
+
s = Tire.search 'match-query-test' do
|
44
|
+
query do
|
45
|
+
match [:first_name, :last_name], 'John'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_equal 3, s.results.count
|
50
|
+
end
|
51
|
+
|
52
|
+
should "find documents by prefix" do
|
53
|
+
s = Tire.search 'match-query-test' do
|
54
|
+
query do
|
55
|
+
match :last_name, 'Smi', type: 'phrase_prefix'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
assert_equal 3, s.results.count
|
60
|
+
end
|
61
|
+
|
62
|
+
should "automatically create a boolean query when called repeatedly" do
|
63
|
+
s = Tire.search 'match-query-test' do
|
64
|
+
query do
|
65
|
+
match [:first_name, :last_name], 'John'
|
66
|
+
match :age, 30
|
67
|
+
match :gender, 'male'
|
68
|
+
end
|
69
|
+
# puts to_curl
|
70
|
+
end
|
71
|
+
|
72
|
+
assert_equal 1, s.results.count
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Tire
|
4
|
+
|
5
|
+
class MultiSearchIntegrationTest < Test::Unit::TestCase
|
6
|
+
include Test::Integration
|
7
|
+
|
8
|
+
context "Multi search" do
|
9
|
+
# Tire.configure { logger STDERR }
|
10
|
+
setup do
|
11
|
+
Tire.index 'multi-search-test-1' do
|
12
|
+
delete
|
13
|
+
create
|
14
|
+
store first_name: 'John', last_name: 'Smith', age: 30, gender: 'male'
|
15
|
+
store first_name: 'John', last_name: 'Smithson', age: 25, gender: 'male'
|
16
|
+
store first_name: 'Mary', last_name: 'Smith', age: 20, gender: 'female'
|
17
|
+
refresh
|
18
|
+
end
|
19
|
+
Tire.index 'multi-search-test-2' do
|
20
|
+
delete
|
21
|
+
create
|
22
|
+
store first_name: 'John', last_name: 'Milton', age: 35, gender: 'male'
|
23
|
+
store first_name: 'Mary', last_name: 'Milson', age: 44, gender: 'female'
|
24
|
+
store first_name: 'Mary', last_name: 'Reilly', age: 55, gender: 'female'
|
25
|
+
refresh
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
teardown do
|
30
|
+
Tire.index('multi-search-test-1').delete
|
31
|
+
Tire.index('multi-search-test-2').delete
|
32
|
+
end
|
33
|
+
|
34
|
+
should "return multiple results" do
|
35
|
+
s = Tire.multi_search 'multi-search-test-1' do
|
36
|
+
search :johns do
|
37
|
+
query { match :_all, 'john' }
|
38
|
+
end
|
39
|
+
search :males do
|
40
|
+
query { match :gender, 'male' }
|
41
|
+
end
|
42
|
+
search :facets, search_type: 'count' do
|
43
|
+
facet('age') { statistical :age }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
assert_equal 3, s.results.size
|
48
|
+
|
49
|
+
assert_equal 2, s.results[:johns].size
|
50
|
+
assert_equal 2, s.results[:males].size
|
51
|
+
|
52
|
+
assert s.results[:facets].results.empty?, "Results not empty? #{s.results[:facets].results}"
|
53
|
+
assert_equal 75.0, s.results[:facets].facets['age']['total']
|
54
|
+
end
|
55
|
+
|
56
|
+
should "mix named and numbered searches" do
|
57
|
+
s = Tire.multi_search 'multi-search-test-1' do
|
58
|
+
search(:johns) { query { match :_all, 'john' } }
|
59
|
+
search { query { match :_all, 'mary' } }
|
60
|
+
end
|
61
|
+
|
62
|
+
assert_equal 2, s.results.size
|
63
|
+
|
64
|
+
assert_equal 2, s.results[:johns].size
|
65
|
+
assert_equal 1, s.results[1].size
|
66
|
+
end
|
67
|
+
|
68
|
+
should "iterate over mixed searches" do
|
69
|
+
s = Tire.multi_search 'multi-search-test-1' do
|
70
|
+
search(:johns) { query { match :_all, 'john' } }
|
71
|
+
search { query { match :_all, 'mary' } }
|
72
|
+
end
|
73
|
+
|
74
|
+
assert_equal [:johns, 1], s.searches.names
|
75
|
+
assert_equal [:johns, 1], s.results.to_hash.keys
|
76
|
+
|
77
|
+
s.results.each_with_index do |results, i|
|
78
|
+
assert_equal 2, results.size if i == 0
|
79
|
+
assert_equal 1, results.size if i == 1
|
80
|
+
end
|
81
|
+
|
82
|
+
s.results.each_pair do |name, results|
|
83
|
+
assert_equal 2, results.size if name == :johns
|
84
|
+
assert_equal 1, results.size if name == 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
should "return results from different indices" do
|
89
|
+
s = Tire.multi_search do
|
90
|
+
search( index: 'multi-search-test-1' ) { query { match :_all, 'john' } }
|
91
|
+
search( index: 'multi-search-test-2' ) { query { match :_all, 'john' } }
|
92
|
+
end
|
93
|
+
|
94
|
+
assert_equal 2, s.results[0].size
|
95
|
+
assert_equal 1, s.results[1].size
|
96
|
+
end
|
97
|
+
|
98
|
+
should "return error for failed searches" do
|
99
|
+
s = Tire.multi_search 'multi-search-test-1' do
|
100
|
+
search() { query { match :_all, 'john' } }
|
101
|
+
search() { query { string '[x' } }
|
102
|
+
end
|
103
|
+
|
104
|
+
assert_equal 2, s.results[0].size
|
105
|
+
assert s.results[0].success?
|
106
|
+
|
107
|
+
assert_equal 0, s.results[1].size
|
108
|
+
assert s.results[1].failure?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -124,6 +124,64 @@ module Tire
|
|
124
124
|
|
125
125
|
end
|
126
126
|
|
127
|
+
context "multi search" do
|
128
|
+
setup do
|
129
|
+
# Tire.configure { logger STDERR }
|
130
|
+
PersistentArticle.create :title => 'Test'
|
131
|
+
PersistentArticle.create :title => 'Pest'
|
132
|
+
PersistentArticle.index.refresh
|
133
|
+
end
|
134
|
+
|
135
|
+
should "return multiple result sets" do
|
136
|
+
results = PersistentArticle.multi_search do
|
137
|
+
search do
|
138
|
+
query { match :title, 'test' }
|
139
|
+
end
|
140
|
+
search search_type: 'count' do
|
141
|
+
query { match :title, 'pest' }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
assert_equal 2, results.size
|
146
|
+
|
147
|
+
assert_equal 1, results[0].size
|
148
|
+
assert_equal 1, results[0].total
|
149
|
+
|
150
|
+
assert_equal 0, results[1].size
|
151
|
+
assert_equal 1, results[1].total
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "with multiple types within single index" do
|
156
|
+
|
157
|
+
setup do
|
158
|
+
# Create documents of two types within single index
|
159
|
+
PersistentArticleInIndex.create :title => "TestInIndex", :tags => ['in_index']
|
160
|
+
PersistentArticle.create :title => "Test", :tags => []
|
161
|
+
PersistentArticle.index.refresh
|
162
|
+
end
|
163
|
+
|
164
|
+
should "returns all documents with proper type" do
|
165
|
+
results = PersistentArticle.all
|
166
|
+
|
167
|
+
assert_equal 1, results.size
|
168
|
+
assert results.all? { |r| r.tags == [] }, "Incorrect results? " + results.to_a.inspect
|
169
|
+
|
170
|
+
results = PersistentArticleInIndex.all
|
171
|
+
|
172
|
+
assert_equal 1, results.size
|
173
|
+
assert results.all? { |r| r.tags == ['in_index'] }, "Incorrect results? " + results.to_a.inspect
|
174
|
+
end
|
175
|
+
|
176
|
+
should "returns first document with proper type" do
|
177
|
+
assert_instance_of PersistentArticle, PersistentArticle.first
|
178
|
+
assert_instance_of PersistentArticleInIndex, PersistentArticleInIndex.first
|
179
|
+
|
180
|
+
assert_equal [], PersistentArticle.first.tags
|
181
|
+
assert_equal ['in_index'], PersistentArticleInIndex.first.tags
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
127
185
|
end
|
128
186
|
|
129
187
|
end
|
data/test/models/article.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Example class with ElasticSearch persistence in index `persistent_articles`
|
2
|
+
#
|
3
|
+
# The `index` is `persistent_articles`
|
4
|
+
#
|
5
|
+
|
6
|
+
class PersistentArticleInIndex
|
7
|
+
|
8
|
+
include Tire::Model::Persistence
|
9
|
+
|
10
|
+
property :title
|
11
|
+
property :published_on
|
12
|
+
property :tags
|
13
|
+
|
14
|
+
index_name "persistent_articles"
|
15
|
+
|
16
|
+
end
|
@@ -4,8 +4,9 @@ class PersistentArticleWithDefaults
|
|
4
4
|
|
5
5
|
property :title
|
6
6
|
property :published_on
|
7
|
-
property :tags,
|
8
|
-
property :hidden,
|
9
|
-
property :options,
|
7
|
+
property :tags, :default => []
|
8
|
+
property :hidden, :default => false
|
9
|
+
property :options, :default => {:switches => []}
|
10
|
+
property :created_at, :default => lambda { Time.now }
|
10
11
|
|
11
12
|
end
|
data/test/test_helper.rb
CHANGED
@@ -24,6 +24,7 @@ require File.dirname(__FILE__) + '/models/active_model_article_with_custom_index
|
|
24
24
|
require File.dirname(__FILE__) + '/models/active_record_models'
|
25
25
|
require File.dirname(__FILE__) + '/models/article'
|
26
26
|
require File.dirname(__FILE__) + '/models/persistent_article'
|
27
|
+
require File.dirname(__FILE__) + '/models/persistent_article_in_index'
|
27
28
|
require File.dirname(__FILE__) + '/models/persistent_article_in_namespace'
|
28
29
|
require File.dirname(__FILE__) + '/models/persistent_article_with_casting'
|
29
30
|
require File.dirname(__FILE__) + '/models/persistent_article_with_defaults'
|
@@ -86,7 +87,8 @@ module Test::Integration
|
|
86
87
|
mongoid_class_with_tire_methods
|
87
88
|
supermodel_articles
|
88
89
|
dynamic_index
|
89
|
-
model_with_nested_documents
|
90
|
+
model_with_nested_documents
|
91
|
+
model_with_incorrect_mappings ].each do |index|
|
90
92
|
::RestClient.delete "#{URL}/#{index}" rescue nil
|
91
93
|
end
|
92
94
|
end
|
@@ -52,6 +52,16 @@ module Tire
|
|
52
52
|
assert_instance_of Tire::Logger, Configuration.logger
|
53
53
|
end
|
54
54
|
|
55
|
+
should "set pretty option to true by default" do
|
56
|
+
assert_not_nil Configuration.pretty
|
57
|
+
assert Configuration.pretty, "Should be true, but is: #{Configuration.pretty.inspect}"
|
58
|
+
end
|
59
|
+
|
60
|
+
should "set the pretty option to false" do
|
61
|
+
Configuration.pretty(false)
|
62
|
+
assert ! Configuration.pretty, "Should be falsy, but is: #{Configuration.pretty.inspect}"
|
63
|
+
end
|
64
|
+
|
55
65
|
should "allow to reset the configuration for specific property" do
|
56
66
|
Configuration.url 'http://example.com'
|
57
67
|
assert_equal 'http://example.com', Configuration.url
|