acts_as_solr 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/CHANGE_LOG +233 -0
- data/FORKED_CHANGES +3 -0
- data/LICENSE +19 -0
- data/README.markdown +94 -0
- data/README.rdoc +84 -0
- data/Rakefile +57 -0
- data/TESTING_THE_PLUGIN +25 -0
- data/VERSION +1 -0
- data/acts_as_solr.gemspec +237 -0
- data/config/solr.yml +15 -0
- data/config/solr_environment.rb +22 -0
- data/init.rb +21 -0
- data/install.rb +11 -0
- data/lib/acts_as_solr.rb +61 -0
- data/lib/acts_methods.rb +284 -0
- data/lib/class_methods.rb +239 -0
- data/lib/common_methods.rb +89 -0
- data/lib/deprecation.rb +61 -0
- data/lib/instance_methods.rb +181 -0
- data/lib/lazy_document.rb +18 -0
- data/lib/parser_methods.rb +230 -0
- data/lib/search_results.rb +69 -0
- data/lib/solr/connection.rb +191 -0
- data/lib/solr/document.rb +78 -0
- data/lib/solr/exception.rb +13 -0
- data/lib/solr/field.rb +39 -0
- data/lib/solr/importer/array_mapper.rb +26 -0
- data/lib/solr/importer/delimited_file_source.rb +38 -0
- data/lib/solr/importer/hpricot_mapper.rb +27 -0
- data/lib/solr/importer/mapper.rb +51 -0
- data/lib/solr/importer/solr_source.rb +43 -0
- data/lib/solr/importer/xpath_mapper.rb +35 -0
- data/lib/solr/importer.rb +19 -0
- data/lib/solr/indexer.rb +52 -0
- data/lib/solr/request/add_document.rb +63 -0
- data/lib/solr/request/base.rb +36 -0
- data/lib/solr/request/commit.rb +31 -0
- data/lib/solr/request/delete.rb +50 -0
- data/lib/solr/request/dismax.rb +46 -0
- data/lib/solr/request/index_info.rb +22 -0
- data/lib/solr/request/modify_document.rb +51 -0
- data/lib/solr/request/optimize.rb +21 -0
- data/lib/solr/request/ping.rb +36 -0
- data/lib/solr/request/select.rb +56 -0
- data/lib/solr/request/spellcheck.rb +30 -0
- data/lib/solr/request/standard.rb +402 -0
- data/lib/solr/request/update.rb +23 -0
- data/lib/solr/request.rb +26 -0
- data/lib/solr/response/add_document.rb +17 -0
- data/lib/solr/response/base.rb +42 -0
- data/lib/solr/response/commit.rb +17 -0
- data/lib/solr/response/delete.rb +13 -0
- data/lib/solr/response/dismax.rb +8 -0
- data/lib/solr/response/index_info.rb +26 -0
- data/lib/solr/response/modify_document.rb +17 -0
- data/lib/solr/response/optimize.rb +14 -0
- data/lib/solr/response/ping.rb +28 -0
- data/lib/solr/response/ruby.rb +42 -0
- data/lib/solr/response/select.rb +17 -0
- data/lib/solr/response/spellcheck.rb +20 -0
- data/lib/solr/response/standard.rb +64 -0
- data/lib/solr/response/xml.rb +42 -0
- data/lib/solr/response.rb +27 -0
- data/lib/solr/solrtasks.rb +27 -0
- data/lib/solr/util.rb +32 -0
- data/lib/solr/xml.rb +44 -0
- data/lib/solr.rb +21 -0
- data/lib/solr_fixtures.rb +13 -0
- data/lib/tasks/database.rake +18 -0
- data/lib/tasks/solr.rake +137 -0
- data/lib/tasks/test.rake +7 -0
- data/lib/will_paginate_support.rb +12 -0
- data/solr/CHANGES.txt +1207 -0
- data/solr/LICENSE.txt +712 -0
- data/solr/NOTICE.txt +90 -0
- data/solr/etc/jetty.xml +205 -0
- data/solr/etc/webdefault.xml +379 -0
- data/solr/lib/easymock.jar +0 -0
- data/solr/lib/jetty-6.1.3.jar +0 -0
- data/solr/lib/jetty-util-6.1.3.jar +0 -0
- data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
- data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
- data/solr/lib/servlet-api-2.4.jar +0 -0
- data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
- data/solr/lib/xpp3-1.1.3.4.O.jar +0 -0
- data/solr/logs/.empty-dir-for-git +0 -0
- data/solr/solr/README.txt +52 -0
- data/solr/solr/bin/abc +176 -0
- data/solr/solr/bin/abo +176 -0
- data/solr/solr/bin/backup +108 -0
- data/solr/solr/bin/backupcleaner +142 -0
- data/solr/solr/bin/commit +128 -0
- data/solr/solr/bin/optimize +129 -0
- data/solr/solr/bin/readercycle +129 -0
- data/solr/solr/bin/rsyncd-disable +77 -0
- data/solr/solr/bin/rsyncd-enable +76 -0
- data/solr/solr/bin/rsyncd-start +145 -0
- data/solr/solr/bin/rsyncd-stop +105 -0
- data/solr/solr/bin/scripts-util +83 -0
- data/solr/solr/bin/snapcleaner +148 -0
- data/solr/solr/bin/snapinstaller +168 -0
- data/solr/solr/bin/snappuller +248 -0
- data/solr/solr/bin/snappuller-disable +77 -0
- data/solr/solr/bin/snappuller-enable +77 -0
- data/solr/solr/bin/snapshooter +109 -0
- data/solr/solr/conf/admin-extra.html +31 -0
- data/solr/solr/conf/protwords.txt +21 -0
- data/solr/solr/conf/schema.xml +126 -0
- data/solr/solr/conf/scripts.conf +24 -0
- data/solr/solr/conf/solrconfig.xml +458 -0
- data/solr/solr/conf/stopwords.txt +57 -0
- data/solr/solr/conf/synonyms.txt +31 -0
- data/solr/solr/conf/xslt/example.xsl +132 -0
- data/solr/solr/conf/xslt/example_atom.xsl +63 -0
- data/solr/solr/conf/xslt/example_rss.xsl +62 -0
- data/solr/start.jar +0 -0
- data/solr/tmp/.empty-dir-for-git +0 -0
- data/solr/webapps/solr.war +0 -0
- data/test/config/solr.yml +2 -0
- data/test/db/connections/mysql/connection.rb +10 -0
- data/test/db/connections/sqlite/connection.rb +8 -0
- data/test/db/migrate/001_create_books.rb +15 -0
- data/test/db/migrate/002_create_movies.rb +12 -0
- data/test/db/migrate/003_create_categories.rb +11 -0
- data/test/db/migrate/004_create_electronics.rb +16 -0
- data/test/db/migrate/005_create_authors.rb +12 -0
- data/test/db/migrate/006_create_postings.rb +9 -0
- data/test/db/migrate/007_create_posts.rb +13 -0
- data/test/db/migrate/008_create_gadgets.rb +11 -0
- data/test/fixtures/authors.yml +9 -0
- data/test/fixtures/books.yml +13 -0
- data/test/fixtures/categories.yml +7 -0
- data/test/fixtures/db_definitions/mysql.sql +41 -0
- data/test/fixtures/electronics.yml +49 -0
- data/test/fixtures/movies.yml +9 -0
- data/test/fixtures/postings.yml +10 -0
- data/test/functional/acts_as_solr_test.rb +413 -0
- data/test/functional/association_indexing_test.rb +37 -0
- data/test/functional/faceted_search_test.rb +163 -0
- data/test/functional/multi_solr_search_test.rb +51 -0
- data/test/models/author.rb +10 -0
- data/test/models/book.rb +10 -0
- data/test/models/category.rb +8 -0
- data/test/models/electronic.rb +21 -0
- data/test/models/gadget.rb +9 -0
- data/test/models/movie.rb +17 -0
- data/test/models/novel.rb +2 -0
- data/test/models/post.rb +3 -0
- data/test/models/posting.rb +11 -0
- data/test/test_helper.rb +51 -0
- data/test/unit/acts_methods_shoulda.rb +70 -0
- data/test/unit/class_methods_shoulda.rb +90 -0
- data/test/unit/common_methods_shoulda.rb +112 -0
- data/test/unit/instance_methods_shoulda.rb +326 -0
- data/test/unit/lazy_document_shoulda.rb +35 -0
- data/test/unit/parser_instance.rb +19 -0
- data/test/unit/parser_methods_shoulda.rb +279 -0
- data/test/unit/solr_instance.rb +46 -0
- data/test/unit/test_helper.rb +26 -0
- metadata +259 -0
@@ -0,0 +1,413 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "#{File.dirname(File.expand_path(__FILE__))}/../test_helper"
|
3
|
+
|
4
|
+
class ActsAsSolrTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
fixtures :books, :movies, :electronics, :postings, :authors
|
7
|
+
|
8
|
+
# Inserting new data into Solr and making sure it's getting indexed
|
9
|
+
def test_insert_new_data
|
10
|
+
assert_equal 2, Book.count_by_solr('ruby OR splinter OR bob')
|
11
|
+
b = Book.create(:name => "Fuze in action", :author => "Bob Bobber", :category_id => 1)
|
12
|
+
assert b.valid?
|
13
|
+
assert_equal 3, Book.count_by_solr('ruby OR splinter OR bob')
|
14
|
+
end
|
15
|
+
|
16
|
+
# Check the type column stored in the index isn't stemmed by SOLR. If it is stemmed,
|
17
|
+
# then both Post and Posting will be stored as type:Post, so a query for Posts will
|
18
|
+
# return Postings and vice versa
|
19
|
+
|
20
|
+
def test_insert_new_data_doesnt_stem_type
|
21
|
+
assert_equal 0, Post.count_by_solr('aardvark')
|
22
|
+
p = Posting.new :name => 'aardvark', :description => "An interesting animal"
|
23
|
+
p.guid = '12AB'
|
24
|
+
p.save!
|
25
|
+
assert_equal 0, Post.count_by_solr('aardvark')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_type_determined_from_database_if_not_explicitly_set
|
29
|
+
assert Post.configuration[:solr_fields][:posted_at][:type] == :date
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_search_includes_subclasses
|
33
|
+
Novel.create! :name => 'Wuthering Heights', :author => 'Emily Bronte'
|
34
|
+
Book.create! :name => 'Jane Eyre', :author => 'Charlotte Bronte'
|
35
|
+
assert_equal 1, Novel.find_by_solr('Bronte').total_hits
|
36
|
+
assert_equal 2, Book.find_by_solr('Bronte').total_hits
|
37
|
+
end
|
38
|
+
|
39
|
+
# Testing basic solr search:
|
40
|
+
# Model.find_by_solr 'term'
|
41
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
42
|
+
def test_find_by_solr_ruby
|
43
|
+
['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
|
44
|
+
'author:peter AND ruby', 'peter dummy'].each do |term|
|
45
|
+
records = Book.find_by_solr term
|
46
|
+
assert_equal 1, records.total
|
47
|
+
assert_equal "Peter McPeterson", records.docs.first.author
|
48
|
+
assert_equal "Ruby for Dummies", records.docs.first.name
|
49
|
+
assert_equal ({"id" => 2,
|
50
|
+
"category_id" => 2,
|
51
|
+
"name" => "Ruby for Dummies",
|
52
|
+
"author" => "Peter McPeterson", "published_on" => (Date.today - 2.years), "type" => nil}), records.docs.first.attributes
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Testing basic solr search:
|
57
|
+
# Model.find_by_solr 'term'
|
58
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
59
|
+
def test_find_by_solr_splinter
|
60
|
+
['splinter', 'name:splinter', 'name:splinter AND author:clancy',
|
61
|
+
'author:clancy AND splinter', 'cell tom'].each do |term|
|
62
|
+
records = Book.find_by_solr term
|
63
|
+
assert_equal 1, records.total
|
64
|
+
assert_equal "Splinter Cell", records.docs.first.name
|
65
|
+
assert_equal "Tom Clancy", records.docs.first.author
|
66
|
+
assert_equal ({"id" => 1, "category_id" => 1, "name" => "Splinter Cell",
|
67
|
+
"author" => "Tom Clancy", "published_on" => (Date.today - 1.year), "type" => nil}), records.docs.first.attributes
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Testing basic solr search:
|
72
|
+
# Model.find_by_solr 'term'
|
73
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
74
|
+
def test_find_by_solr_ruby_or_splinter
|
75
|
+
['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term|
|
76
|
+
records = Book.find_by_solr term
|
77
|
+
assert_equal 2, records.total
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Testing search in indexed field methods:
|
82
|
+
#
|
83
|
+
# class Movie < ActiveRecord::Base
|
84
|
+
# acts_as_solr :fields => [:name, :description, :current_time]
|
85
|
+
#
|
86
|
+
# def current_time
|
87
|
+
# Time.now.to_s
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# The method current_time above gets indexed as being part of the
|
93
|
+
# Movie model and it's available for search as well
|
94
|
+
def test_find_with_dynamic_fields
|
95
|
+
date = Time.now.strftime('%b %d %Y')
|
96
|
+
["dynamite AND #{date}", "description:goofy AND #{date}", "goofy napoleon #{date}",
|
97
|
+
"goofiness #{date}"].each do |term|
|
98
|
+
records = Movie.find_by_solr term
|
99
|
+
assert_equal 1, records.total
|
100
|
+
assert_equal ({"id" => 1, "name" => "Napoleon Dynamite",
|
101
|
+
"description" => "Cool movie about a goofy guy"}), records.docs.first.attributes
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Testing basic solr search that returns just the ids instead of the objects:
|
106
|
+
# Model.find_id_by_solr 'term'
|
107
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
108
|
+
def test_find_id_by_solr_ruby
|
109
|
+
['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
|
110
|
+
'author:peter AND ruby'].each do |term|
|
111
|
+
records = Book.find_id_by_solr term
|
112
|
+
assert_equal 1, records.docs.size
|
113
|
+
assert_equal [2], records.docs
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Testing basic solr search that returns just the ids instead of the objects:
|
118
|
+
# Model.find_id_by_solr 'term'
|
119
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
120
|
+
def test_find_id_by_solr_splinter
|
121
|
+
['splinter', 'name:splinter', 'name:splinter AND author:clancy',
|
122
|
+
'author:clancy AND splinter'].each do |term|
|
123
|
+
records = Book.find_id_by_solr term
|
124
|
+
assert_equal 1, records.docs.size
|
125
|
+
assert_equal [1], records.docs
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Testing basic solr search that returns just the ids instead of the objects:
|
130
|
+
# Model.find_id_by_solr 'term'
|
131
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
132
|
+
def test_find_id_by_solr_ruby_or_splinter
|
133
|
+
['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter',
|
134
|
+
'dummy OR cell'].each do |term|
|
135
|
+
records = Book.find_id_by_solr term
|
136
|
+
assert_equal 2, records.docs.size
|
137
|
+
assert_equal [1,2], records.docs
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Testing basic solr search that returns the total number of records found:
|
142
|
+
# Model.find_count_by_solr 'term'
|
143
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
144
|
+
def test_count_by_solr
|
145
|
+
['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter',
|
146
|
+
'author:peter AND ruby'].each do |term|
|
147
|
+
assert_equal 1, Book.count_by_solr(term), "there should only be 1 result for search: #{term}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Testing basic solr search that returns the total number of records found:
|
152
|
+
# Model.find_count_by_solr 'term'
|
153
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
154
|
+
def test_count_by_solr_splinter
|
155
|
+
['splinter', 'name:splinter', 'name:splinter AND author:clancy',
|
156
|
+
'author:clancy AND splinter', 'author:clancy cell'].each do |term|
|
157
|
+
assert_equal 1, Book.count_by_solr(term)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Testing basic solr search that returns the total number of records found:
|
162
|
+
# Model.find_count_by_solr 'term'
|
163
|
+
# Note that you're able to mix free-search with fields and boolean operators
|
164
|
+
def test_count_by_solr_ruby_or_splinter
|
165
|
+
['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term|
|
166
|
+
assert_equal 2, Book.count_by_solr(term)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Testing basic solr search with additional options:
|
171
|
+
# Model.find_count_by_solr 'term', :limit => 10, :offset => 0
|
172
|
+
def test_find_with_options
|
173
|
+
[1,2].each do |count|
|
174
|
+
records = Book.find_by_solr 'ruby OR splinter', :limit => count
|
175
|
+
assert_equal count, records.docs.size
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Testing self.rebuild_solr_index
|
180
|
+
# - It makes sure the index is rebuilt after a data has been lost
|
181
|
+
def test_rebuild_solr_index
|
182
|
+
assert_equal 1, Book.count_by_solr('splinter')
|
183
|
+
|
184
|
+
Book.find(:first).solr_destroy
|
185
|
+
assert_equal 0, Book.count_by_solr('splinter')
|
186
|
+
|
187
|
+
Book.rebuild_solr_index
|
188
|
+
assert_equal 1, Book.count_by_solr('splinter')
|
189
|
+
end
|
190
|
+
|
191
|
+
# Testing instance methods:
|
192
|
+
# - solr_save
|
193
|
+
# - solr_destroy
|
194
|
+
def test_solr_save_and_solr_destroy
|
195
|
+
assert_equal 1, Book.count_by_solr('splinter')
|
196
|
+
|
197
|
+
Book.find(:first).solr_destroy
|
198
|
+
assert_equal 0, Book.count_by_solr('splinter')
|
199
|
+
|
200
|
+
Book.find(:first).solr_save
|
201
|
+
assert_equal 1, Book.count_by_solr('splinter')
|
202
|
+
end
|
203
|
+
|
204
|
+
# Testing the order of results
|
205
|
+
def test_find_returns_records_in_order
|
206
|
+
records = Book.find_by_solr 'ruby^5 OR splinter'
|
207
|
+
# we boosted ruby so ruby should come first
|
208
|
+
|
209
|
+
assert_equal 2, records.total
|
210
|
+
assert_equal 'Ruby for Dummies', records.docs.first.name
|
211
|
+
assert_equal 'Splinter Cell', records.docs.last.name
|
212
|
+
end
|
213
|
+
|
214
|
+
# Testing solr search with optional :order argument
|
215
|
+
def _test_with_order_option
|
216
|
+
records = Movie.find_by_solr 'office^5 OR goofiness'
|
217
|
+
assert_equal 'Hypnotized dude loves fishing but not working', records.docs.first.description
|
218
|
+
assert_equal 'Cool movie about a goofy guy', records.docs.last.description
|
219
|
+
|
220
|
+
records = Movie.find_by_solr 'office^5 OR goofiness', :order => 'description asc'
|
221
|
+
assert_equal 'Cool movie about a goofy guy', records.docs.first.description
|
222
|
+
assert_equal 'Hypnotized dude loves fishing but not working', records.docs.last.description
|
223
|
+
end
|
224
|
+
|
225
|
+
# Testing search with omitted :field_types should
|
226
|
+
# return the same result set as if when we use it
|
227
|
+
def test_omit_field_types_in_search
|
228
|
+
records = Electronic.find_by_solr "price:[200 TO 599.99]"
|
229
|
+
assert_match(/599/, records.docs.first.price)
|
230
|
+
assert_match(/319/, records.docs.last.price)
|
231
|
+
|
232
|
+
records = Electronic.find_by_solr "price:[200 TO 599.99]", :order => 'price asc'
|
233
|
+
assert_match(/319/, records.docs.first.price)
|
234
|
+
assert_match(/599/, records.docs.last.price)
|
235
|
+
|
236
|
+
end
|
237
|
+
|
238
|
+
# Test to make sure the result returned when no matches
|
239
|
+
# are found has the same structure when there are results
|
240
|
+
def test_returns_no_matches
|
241
|
+
records = Book.find_by_solr 'rubyist'
|
242
|
+
assert_equal [], records.docs
|
243
|
+
assert_equal 0, records.total
|
244
|
+
|
245
|
+
records = Book.find_id_by_solr 'rubyist'
|
246
|
+
assert_equal [], records.docs
|
247
|
+
assert_equal 0, records.total
|
248
|
+
|
249
|
+
records = Book.find_by_solr 'rubyist', :facets => {}
|
250
|
+
assert_equal [], records.docs
|
251
|
+
assert_equal 0, records.total
|
252
|
+
assert_equal({"facet_fields"=>[]}, records.facets)
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
# Testing the :exclude_fields option when set in the
|
257
|
+
# model to make sure it doesn't get indexed
|
258
|
+
def test_exclude_fields_option
|
259
|
+
records = Electronic.find_by_solr 'audiobooks OR latency'
|
260
|
+
assert records.docs.empty?
|
261
|
+
assert_equal 0, records.total
|
262
|
+
|
263
|
+
assert_nothing_raised{
|
264
|
+
records = Electronic.find_by_solr 'features:audiobooks'
|
265
|
+
assert records.docs.empty?
|
266
|
+
assert_equal 0, records.total
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
# Testing the :auto_commit option set to false in the model
|
271
|
+
# should not send the commit command to Solr
|
272
|
+
def test_auto_commit_turned_off
|
273
|
+
assert_equal 0, Author.count_by_solr('raymond chandler')
|
274
|
+
|
275
|
+
original_count = Author.count
|
276
|
+
Author.create(:name => 'Raymond Chandler', :biography => 'Writes noirish detective stories')
|
277
|
+
|
278
|
+
assert_equal original_count + 1, Author.count
|
279
|
+
assert_equal 0, Author.count_by_solr('raymond chandler')
|
280
|
+
end
|
281
|
+
|
282
|
+
# Testing models that use a different key as the primary key
|
283
|
+
def test_search_on_model_with_string_id_field
|
284
|
+
records = Posting.find_by_solr 'first^5 OR second'
|
285
|
+
assert_equal 2, records.total
|
286
|
+
assert_equal 'ABC-123', records.docs.first.guid
|
287
|
+
assert_equal 'DEF-456', records.docs.last.guid
|
288
|
+
end
|
289
|
+
|
290
|
+
# Making sure the result set is ordered correctly even on
|
291
|
+
# models that use a different key as the primary key
|
292
|
+
def test_records_in_order_on_model_with_string_id_field
|
293
|
+
records = Posting.find_by_solr 'first OR second^5'
|
294
|
+
assert_equal 2, records.total
|
295
|
+
assert_equal 'DEF-456', records.docs.first.guid
|
296
|
+
assert_equal 'ABC-123', records.docs.last.guid
|
297
|
+
end
|
298
|
+
|
299
|
+
# Making sure the records are added when passing a batch size
|
300
|
+
# to rebuild_solr_index
|
301
|
+
def test_using_rebuild_solr_index_with_batch
|
302
|
+
assert_equal 2, Movie.count_by_solr('office OR napoleon')
|
303
|
+
Movie.find(:all).each(&:solr_destroy)
|
304
|
+
assert_equal 0, Movie.count_by_solr('office OR napoleon')
|
305
|
+
|
306
|
+
Movie.rebuild_solr_index 100
|
307
|
+
assert_equal 2, Movie.count_by_solr('office OR napoleon')
|
308
|
+
end
|
309
|
+
|
310
|
+
# Making sure find_by_solr with scores actually return the scores
|
311
|
+
# for each individual record
|
312
|
+
def test_find_by_solr_with_score
|
313
|
+
books = Book.find_by_solr 'ruby^10 OR splinter', :scores => true
|
314
|
+
assert_equal 2, books.total
|
315
|
+
assert_equal 0.41763234, books.max_score
|
316
|
+
|
317
|
+
books.records.each { |book| assert_not_nil book.solr_score }
|
318
|
+
assert_equal 0.41763234, books.docs.first.solr_score
|
319
|
+
assert_equal 0.14354616, books.docs.last.solr_score
|
320
|
+
end
|
321
|
+
|
322
|
+
# Making sure nothing breaks when html entities are inside
|
323
|
+
# the content to be indexed; and on the search as well.
|
324
|
+
def test_index_and_search_with_html_entities
|
325
|
+
description = "
|
326
|
+
inverted exclamation mark ¡ ¡
|
327
|
+
¤ currency ¤ ¤
|
328
|
+
¢ cent ¢ ¢
|
329
|
+
£ pound £ £
|
330
|
+
¥ yen ¥ ¥
|
331
|
+
¦ broken vertical bar ¦ ¦
|
332
|
+
§ section § §
|
333
|
+
¨ spacing diaeresis ¨ ¨
|
334
|
+
© copyright © ©
|
335
|
+
ª feminine ordinal indicator ª ª
|
336
|
+
« angle quotation mark (left) « «
|
337
|
+
¬ negation ¬ ¬
|
338
|
+
soft hyphen ­ ­
|
339
|
+
® registered trademark ® ®
|
340
|
+
™ trademark ™ ™
|
341
|
+
¯ spacing macron ¯ ¯
|
342
|
+
° degree ° °
|
343
|
+
± plus-or-minus ± ±
|
344
|
+
² superscript 2 ² ²
|
345
|
+
³ superscript 3 ³ ³
|
346
|
+
´ spacing acute ´ ´
|
347
|
+
µ micro µ µ
|
348
|
+
¶ paragraph ¶ ¶
|
349
|
+
· middle dot · ·
|
350
|
+
¸ spacing cedilla ¸ ¸
|
351
|
+
¹ superscript 1 ¹ ¹
|
352
|
+
º masculine ordinal indicator º º
|
353
|
+
» angle quotation mark (right) » »
|
354
|
+
¼ fraction 1/4 ¼ ¼
|
355
|
+
½ fraction 1/2 ½ ½
|
356
|
+
¾ fraction 3/4 ¾ ¾
|
357
|
+
¿ inverted question mark ¿ ¿
|
358
|
+
× multiplication × ×
|
359
|
+
÷ division ÷ ÷
|
360
|
+
♥ ♦ ♣ ♠"
|
361
|
+
|
362
|
+
author = Author.create(:name => "Test in Action™ - Copyright © Bob", :biography => description)
|
363
|
+
assert author.valid?
|
364
|
+
author.solr_commit
|
365
|
+
|
366
|
+
author = Author.find_by_solr 'trademark © ¾ ¡ £'
|
367
|
+
assert_equal 1, author.total
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_operator_search_option
|
371
|
+
assert_nothing_raised {
|
372
|
+
books = Movie.find_by_solr "office napoleon", :operator => :or
|
373
|
+
assert_equal 2, books.total
|
374
|
+
|
375
|
+
books = Movie.find_by_solr "office napoleon", :operator => :and
|
376
|
+
assert_equal 0, books.total
|
377
|
+
}
|
378
|
+
|
379
|
+
assert_raise RuntimeError do
|
380
|
+
Movie.find_by_solr "office napoleon", :operator => :bad
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# Making sure find_by_solr with scores actually return the scores
|
385
|
+
# for each individual record and orders them accordingly
|
386
|
+
def test_find_by_solr_order_by_score
|
387
|
+
books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score asc' }
|
388
|
+
assert (books.docs.collect(&:solr_score).compact.size == books.docs.size), "Each book should have a score"
|
389
|
+
assert_equal 0.41763234, books.docs.last.solr_score
|
390
|
+
|
391
|
+
books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score desc' }
|
392
|
+
assert_equal 0.41763234, books.docs.first.solr_score
|
393
|
+
assert_equal 0.14354616, books.docs.last.solr_score
|
394
|
+
end
|
395
|
+
|
396
|
+
# Search based on fields with the :date format
|
397
|
+
def test_indexed_date_field_format
|
398
|
+
movies = Movie.find_by_solr 'time_on_xml:[NOW-1DAY TO NOW]'
|
399
|
+
assert_equal 2, movies.total
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_query_time_is_returned
|
403
|
+
results = Book.find_by_solr('ruby')
|
404
|
+
assert_not_nil(results.query_time)
|
405
|
+
assert_equal(results.query_time.class,Fixnum)
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_should_not_index_the_record_when_offline_proc_returns_true
|
409
|
+
Gadget.search_disabled = true
|
410
|
+
gadget = Gadget.create(:name => "flipvideo mino")
|
411
|
+
assert_equal 0, Gadget.find_id_by_solr('flipvideo').total
|
412
|
+
end
|
413
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
|
3
|
+
class AssociationIndexingTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
fixtures :categories, :books
|
6
|
+
|
7
|
+
# Testing the association indexing with has_many:
|
8
|
+
#
|
9
|
+
# class Category < ActiveRecord::Base
|
10
|
+
# has_many :books
|
11
|
+
# acts_as_solr :include => [:books]
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# Note that some of the search terms below are from the 'books'
|
15
|
+
# table, but get indexed as being a part of Category
|
16
|
+
def test_search_on_fields_in_has_many_association
|
17
|
+
['thriller', 'novel', 'splinter', 'clancy', 'tom clancy thriller'].each do |term|
|
18
|
+
assert_equal 1, Category.count_by_solr(term), "expected one result: #{term}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Testing the association indexing with belongs_to:
|
23
|
+
#
|
24
|
+
# class Book < ActiveRecord::Base
|
25
|
+
# belongs_to :category
|
26
|
+
# acts_as_solr :include => [:category]
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# Note that some of the search terms below are from the 'categories'
|
30
|
+
# table, but get indexed as being a part of Book
|
31
|
+
def test_search_on_fields_in_belongs_to_association
|
32
|
+
['splinter', 'clancy', 'tom clancy thriller', 'splinter novel'].each do |term|
|
33
|
+
assert_equal 1, Book.count_by_solr(term), "expected one result: #{term}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
|
3
|
+
class FacetedSearchTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
fixtures :electronics
|
6
|
+
|
7
|
+
# The tests below are for faceted search, but make sure you setup
|
8
|
+
# the fields on your model you'd like to index as a facet field:
|
9
|
+
#
|
10
|
+
# class Electronic < ActiveRecord::Base
|
11
|
+
# acts_as_solr :facets => [:category, :manufacturer]
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# A basic faceted search using just one facet field
|
15
|
+
def test_faceted_search_basic
|
16
|
+
records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category]}
|
17
|
+
assert_equal 4, records.docs.size
|
18
|
+
assert_match /Apple 60 GB Memory iPod/, records.docs.first.name
|
19
|
+
assert_equal({"category_facet" => {"Electronics" => 1,
|
20
|
+
"Memory" => 2,
|
21
|
+
"Hard Drive" => 1}},
|
22
|
+
records.facets['facet_fields'])
|
23
|
+
end
|
24
|
+
|
25
|
+
# Making sure the empty result returned what we expected
|
26
|
+
def test_faceted_search_no_matches
|
27
|
+
records = Electronic.find_by_solr "not found", :facets => { :fields => [:category]}
|
28
|
+
assert_equal [], records.docs
|
29
|
+
assert_equal [], records.facets['facet_fields']
|
30
|
+
end
|
31
|
+
|
32
|
+
# A basic faceted search using multiple facet fields
|
33
|
+
def test_faceted_search_multiple_fields
|
34
|
+
records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category, :manufacturer]}
|
35
|
+
assert_equal 4, records.docs.size
|
36
|
+
assert_equal({"category_facet" => {"Electronics" => 1,
|
37
|
+
"Memory" => 2,
|
38
|
+
"Hard Drive" => 1},
|
39
|
+
"manufacturer_facet" => {"Dell, Inc" => 0,
|
40
|
+
"Samsung Electronics Co. Ltd." => 1,
|
41
|
+
"Corsair Microsystems Inc." => 1,
|
42
|
+
"A-DATA Technology Inc." => 1,
|
43
|
+
"Apple Computer Inc." => 1}}, records.facets['facet_fields'])
|
44
|
+
end
|
45
|
+
|
46
|
+
# A basic faceted search using facet queries to get counts.
|
47
|
+
# Here are the facets search query meaning:
|
48
|
+
# "price:[* TO 200]" - Price up to 200
|
49
|
+
# "price:[200 TO 500]" - Price from 200 to 500
|
50
|
+
# "price:[500 TO *]" - Price higher than 500
|
51
|
+
def test_facet_search_with_query
|
52
|
+
records = Electronic.find_by_solr "memory", :facets => {:query => ["price:[* TO 200.00]",
|
53
|
+
"price:[200.00 TO 500.00]",
|
54
|
+
"price:[500.00 TO *]"]}
|
55
|
+
assert_equal 4, records.docs.size
|
56
|
+
assert_equal({"facet_queries" => {"price_rf:[* TO 200.00]"=>2,
|
57
|
+
"price_rf:[200.00 TO 500.00]"=>1,
|
58
|
+
"price_rf:[500.00 TO *]"=>1},
|
59
|
+
"facet_fields" => {}, "facet_dates" => {}}, records.facets)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Faceted search specifying the query and fields
|
63
|
+
def test_facet_search_with_query_and_field
|
64
|
+
records = Electronic.find_by_solr "memory", :facets => {:query => ["price:[* TO 200.00]",
|
65
|
+
"price:[200.00 TO 500.00]",
|
66
|
+
"price:[500.00 TO *]"],
|
67
|
+
:fields => [:category, :manufacturer]}
|
68
|
+
|
69
|
+
q = records.facets["facet_queries"]
|
70
|
+
assert_equal 2, q["price_rf:[* TO 200.00]"]
|
71
|
+
assert_equal 1, q["price_rf:[500.00 TO *]"]
|
72
|
+
assert_equal 1, q["price_rf:[200.00 TO 500.00]"]
|
73
|
+
|
74
|
+
f = records.facets["facet_fields"]
|
75
|
+
assert_equal 1, f["category_facet"]["Electronics"]
|
76
|
+
assert_equal 2, f["category_facet"]["Memory"]
|
77
|
+
assert_equal 1, f["category_facet"]["Hard Drive"]
|
78
|
+
assert_equal 1, f["manufacturer_facet"]["Samsung Electronics Co. Ltd."]
|
79
|
+
assert_equal 1, f["manufacturer_facet"]["Corsair Microsystems Inc."]
|
80
|
+
assert_equal 1, f["manufacturer_facet"]["A-DATA Technology Inc."]
|
81
|
+
assert_equal 1, f["manufacturer_facet"]["Apple Computer Inc."]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Faceted searches with :sort and :zeros options turned on/off
|
85
|
+
def test_faceted_search_using_zero_and_sort
|
86
|
+
records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category]}
|
87
|
+
assert_equal({"category_facet"=>{"Electronics"=>1, "Memory"=>2, "Hard Drive"=>1}}, records.facets['facet_fields'])
|
88
|
+
|
89
|
+
records = Electronic.find_by_solr "memory", :facets => {:sort => true, :fields =>[:category]}
|
90
|
+
assert_equal({"category_facet"=>{"Memory"=>2, "Electronics"=>1, "Hard Drive"=>1}}, records.facets['facet_fields'])
|
91
|
+
|
92
|
+
records = Electronic.find_by_solr "memory", :facets => {:fields =>[:manufacturer]}
|
93
|
+
assert_equal({"manufacturer_facet" => {"Dell, Inc" => 0,
|
94
|
+
"Samsung Electronics Co. Ltd." => 1,
|
95
|
+
"Corsair Microsystems Inc." => 1,
|
96
|
+
"A-DATA Technology Inc." => 1,
|
97
|
+
"Apple Computer Inc." => 1}}, records.facets['facet_fields'])
|
98
|
+
|
99
|
+
records = Electronic.find_by_solr "memory", :facets => {:zeros => false, :fields =>[:manufacturer]}
|
100
|
+
assert_equal({"manufacturer_facet" => {"Samsung Electronics Co. Ltd." => 1,
|
101
|
+
"Corsair Microsystems Inc." => 1,
|
102
|
+
"A-DATA Technology Inc." => 1,
|
103
|
+
"Apple Computer Inc." => 1}}, records.facets['facet_fields'])
|
104
|
+
end
|
105
|
+
|
106
|
+
# Faceted search with 'drill-down' option being passed.
|
107
|
+
# The :browse option receives the argument in the format:
|
108
|
+
# "facet_field:term". You can drill-down to as many
|
109
|
+
# facet fields as you like
|
110
|
+
def test_faceted_search_with_drill_down
|
111
|
+
records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category]}
|
112
|
+
assert_equal 4, records.docs.size
|
113
|
+
assert_equal({"category_facet"=>{"Electronics"=>1, "Memory"=>2, "Hard Drive"=>1}}, records.facets['facet_fields'])
|
114
|
+
|
115
|
+
records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category],
|
116
|
+
:browse => "category:Memory",
|
117
|
+
:zeros => false}
|
118
|
+
assert_equal 2, records.docs.size
|
119
|
+
assert_equal({"category_facet"=>{"Memory"=>2}}, records.facets['facet_fields'])
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_faceted_search_with_dates
|
123
|
+
records = Electronic.find_by_solr "memory", :facets => {:dates => {:fields => [:created_at, :updated_at],
|
124
|
+
:start => (Date.today - 7.years).strftime("%Y-%m-%dT%H:%M:%SZ"), :end => Date.today.strftime("%Y-%m-%dT%H:%M:%SZ"), :gap => '+1YEAR', :other => :all}}
|
125
|
+
|
126
|
+
assert_equal 4, records.docs.size
|
127
|
+
|
128
|
+
assert_equal 0, records.facets["facet_dates"]["created_at_d"]["after"]
|
129
|
+
assert_equal 1, records.facets["facet_dates"]["created_at_d"]["before"]
|
130
|
+
assert_equal 3, records.facets["facet_dates"]["created_at_d"]["between"]
|
131
|
+
|
132
|
+
assert_equal 0, records.facets["facet_dates"]["updated_at_d"]["after"]
|
133
|
+
assert_equal 0, records.facets["facet_dates"]["updated_at_d"]["before"]
|
134
|
+
assert_equal 4, records.facets["facet_dates"]["updated_at_d"]["between"]
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_faceted_search_with_dates_filter
|
138
|
+
records = Electronic.find_by_solr "memory", :facets => {:dates => {:filter => ["updated_at:[#{(Date.today - 3.months).strftime("%Y-%m-%dT%H:%M:%SZ")} TO NOW-1MONTH/DAY]"]}}
|
139
|
+
|
140
|
+
assert_equal 2, records.docs.size
|
141
|
+
|
142
|
+
records.docs.each { |r|
|
143
|
+
assert r.updated_at >= (Date.today - 3.month)
|
144
|
+
assert r.updated_at <= (Date.today - 1.month)
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_faceted_search_with_dates_filter_and_facets
|
149
|
+
# this is a very contrived example but gives us data to validate
|
150
|
+
records = Electronic.find_by_solr "memory", :facets => {:dates => {:filter => ["updated_at:[#{(Date.today - 3.months).strftime("%Y-%m-%dT%H:%M:%SZ")} TO NOW-1MONTH/DAY]"],
|
151
|
+
:fields => [:created_at, :updated_at], :start => 'NOW-2MONTHS/DAY', :end => 'NOW-1MONTH/DAY', :gap => '+1MONTH', :other => :all}}
|
152
|
+
|
153
|
+
assert_equal 2, records.docs.size
|
154
|
+
|
155
|
+
assert_equal 0, records.facets["facet_dates"]["created_at_d"]["after"]
|
156
|
+
assert_equal 2, records.facets["facet_dates"]["created_at_d"]["before"]
|
157
|
+
assert_equal 0, records.facets["facet_dates"]["created_at_d"]["between"]
|
158
|
+
|
159
|
+
assert_equal 0, records.facets["facet_dates"]["updated_at_d"]["after"]
|
160
|
+
assert_equal 1, records.facets["facet_dates"]["updated_at_d"]["before"]
|
161
|
+
assert_equal 1, records.facets["facet_dates"]["updated_at_d"]["between"]
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '../test_helper')
|
2
|
+
|
3
|
+
class ActsAsSolrTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
fixtures :books, :movies
|
6
|
+
|
7
|
+
# Testing the multi_solr_search with the returning results being objects
|
8
|
+
def test_multi_solr_search_return_objects
|
9
|
+
records = Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :objects
|
10
|
+
assert_equal 2, records.total
|
11
|
+
assert_equal Movie, records.docs.first.class
|
12
|
+
assert_equal Book, records.docs.last.class
|
13
|
+
end
|
14
|
+
|
15
|
+
# Testing the multi_solr_search with the returning results being ids
|
16
|
+
def test_multi_solr_search_return_ids
|
17
|
+
records = Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :ids
|
18
|
+
assert_equal 2, records.total
|
19
|
+
assert records.docs.include?({"id" => "Movie:1"})
|
20
|
+
assert records.docs.include?({"id" => "Book:1"})
|
21
|
+
end
|
22
|
+
|
23
|
+
# Testing the multi_solr_search with multiple models
|
24
|
+
def test_multi_solr_search_multiple_models
|
25
|
+
records = Book.multi_solr_search "Napoleon OR Tom OR Thriller", :models => [Movie, Category], :results_format => :ids
|
26
|
+
assert_equal 4, records.total
|
27
|
+
[{"id" => "Category:1"}, {"id" =>"Book:1"}, {"id" => "Movie:1"}, {"id" =>"Book:3"}].each do |result|
|
28
|
+
assert records.docs.include?(result)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Testing empty result set format
|
33
|
+
def test_returns_no_matches
|
34
|
+
records = Book.multi_solr_search "not found", :models => [Movie, Category]
|
35
|
+
assert_equal [], records.docs
|
36
|
+
assert_equal 0, records.total
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_search_on_empty_string_does_not_return_nil
|
40
|
+
records = Book.multi_solr_search('', :models => [Movie, Category])
|
41
|
+
assert_not_nil records
|
42
|
+
assert_equal [], records.docs
|
43
|
+
assert_equal 0, records.total
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_search_with_score_should_set_score
|
47
|
+
records = Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :objects, :scores => true
|
48
|
+
assert_equal 1.0112731, records.docs.first.solr_score
|
49
|
+
assert_equal 0.6723396, records.docs.last.solr_score
|
50
|
+
end
|
51
|
+
end
|