solrsam 0.4.2
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 +5 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +22 -0
- data/LICENSE +23 -0
- data/README.rdoc +115 -0
- data/Rakefile +18 -0
- data/config/solr/conf/elevate.xml +31 -0
- data/config/solr/conf/mapping-ISOLatin1Accent.txt +246 -0
- data/config/solr/conf/protwords.txt +22 -0
- data/config/solr/conf/schema.xml +237 -0
- data/config/solr/conf/solrconfig.xml +430 -0
- data/config/solr/conf/spellings.txt +2 -0
- data/config/solr/conf/stopwords.txt +56 -0
- data/config/solr/conf/synonyms.txt +24 -0
- data/config/solr/conf/xslt/example.xsl +132 -0
- data/config/solr/conf/xslt/example_atom.xsl +67 -0
- data/config/solr/conf/xslt/example_rss.xsl +66 -0
- data/config/solr/conf/xslt/luke.xsl +337 -0
- data/config/solr.yml +12 -0
- data/config/solr.yml.example +13 -0
- data/lib/rails/generators/solrsan/config/config_generator.rb +23 -0
- data/lib/rails/generators/solrsan/config/templates/solr.yml +13 -0
- data/lib/rails/generators/solrsan/config/templates/solrsan.rb +5 -0
- data/lib/rails/generators/solrsan_generator.rb +11 -0
- data/lib/solrsam/capistrano.rb +31 -0
- data/lib/solrsam/config.rb +25 -0
- data/lib/solrsam/indexer.rb +83 -0
- data/lib/solrsam/search.rb +195 -0
- data/lib/solrsam/version.rb +3 -0
- data/lib/solrsam.rb +12 -0
- data/lib/tasks/solr.rake +71 -0
- data/solrsam.gemspec +25 -0
- data/test/models/document.rb +11 -0
- data/test/search_test_helper.rb +13 -0
- data/test/test_helper.rb +27 -0
- data/test/unit/indexer_test.rb +25 -0
- data/test/unit/search_test.rb +251 -0
- metadata +124 -0
@@ -0,0 +1,195 @@
|
|
1
|
+
module Solrsam
|
2
|
+
module Search
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
attr_accessor :solr_server
|
7
|
+
|
8
|
+
HL_START_TAG = "<mark>"
|
9
|
+
HL_END_TAG = "</mark>"
|
10
|
+
|
11
|
+
def class_name
|
12
|
+
to_s.underscore
|
13
|
+
end
|
14
|
+
|
15
|
+
def solr(method = :read)
|
16
|
+
@solr_server ||= :default
|
17
|
+
Solrsam::Config.instance.rsolr_object(@solr_server, method)
|
18
|
+
end
|
19
|
+
|
20
|
+
def perform_solr_command(method = :read)
|
21
|
+
yield(solr(method))
|
22
|
+
solr(method).commit
|
23
|
+
end
|
24
|
+
|
25
|
+
def search(search_params={})
|
26
|
+
start = search_params[:start] || 0
|
27
|
+
rows = search_params[:rows] || 20
|
28
|
+
|
29
|
+
solr_params = parse_params_for_solr(search_params)
|
30
|
+
|
31
|
+
begin
|
32
|
+
solr_response = solr.select :data => solr_params, :method => :post
|
33
|
+
parse_solr_response(solr_response)
|
34
|
+
rescue RSolr::Error::Http => e
|
35
|
+
{:docs => [],
|
36
|
+
:metadata =>
|
37
|
+
{:error => {:http_status_code => e.response[:status],
|
38
|
+
:http_message_status => RSolr::Error::Http::STATUS_CODES[e.response[:status].to_i],
|
39
|
+
:full_message => e.message}}}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_params_for_solr(search_params={})
|
44
|
+
solr_params = { :echoParams => 'explicit',
|
45
|
+
:q => "*:*",
|
46
|
+
:facet => "on",
|
47
|
+
:'facet.mincount' => 1}.merge(search_params)
|
48
|
+
|
49
|
+
solr_params[:hl] = true unless search_params[:'hl.fl'].blank?
|
50
|
+
solr_params[:fq] = parse_fq(search_params[:fq]) + ( search_params[:untyped] ? [] : ["type:#{class_name}"])
|
51
|
+
solr_params
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_solr_response(solr_response)
|
55
|
+
docs = solr_response['response']['docs']
|
56
|
+
parsed_facet_counts = parse_facet_counts(solr_response['facet_counts'])
|
57
|
+
highlighting = solr_response['highlighting']
|
58
|
+
suggestions = solr_response['spellcheck']['suggestions'] rescue {}
|
59
|
+
|
60
|
+
metadata = {
|
61
|
+
:total_count => solr_response['response']['numFound'],
|
62
|
+
:start => solr_response['response']['start'],
|
63
|
+
:rows => solr_response['responseHeader']['params']['rows'],
|
64
|
+
:time => solr_response['responseHeader']['QTime'],
|
65
|
+
:status => solr_response['responseHeader']['status'],
|
66
|
+
:sort => solr_response['responseHeader']['params']['sort'],
|
67
|
+
:debug => solr_response['debug']
|
68
|
+
}
|
69
|
+
response = {:docs => docs, :metadata => metadata,
|
70
|
+
:facet_counts => parsed_facet_counts, :highlighting => highlighting}
|
71
|
+
response[:stats] = solr_response['stats'] if solr_response['stats']
|
72
|
+
response[:suggestions] = suggestions
|
73
|
+
|
74
|
+
embed_highlighting(response)
|
75
|
+
end
|
76
|
+
|
77
|
+
def parse_fq(fq)
|
78
|
+
return [] if fq.nil?
|
79
|
+
if fq.is_a?(Hash)
|
80
|
+
fq.map{|k,v| parse_element_in_fq({k => v})}.flatten
|
81
|
+
elsif fq.is_a?(Array)
|
82
|
+
fq.map{|ele| parse_element_in_fq(ele)}.flatten
|
83
|
+
else
|
84
|
+
raise "fq must be a hash or array"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_element_in_fq(element)
|
89
|
+
if element.is_a?(String)
|
90
|
+
element
|
91
|
+
elsif element.is_a?(Hash)
|
92
|
+
element.map do |k,values|
|
93
|
+
if values.is_a?(String)
|
94
|
+
key_value_query(k,values)
|
95
|
+
else
|
96
|
+
values.map{|value| key_value_query(k,value) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
else
|
100
|
+
raise "each fq parameter must be a string or hash"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def key_value_query(key, value)
|
105
|
+
if value.starts_with?("[")
|
106
|
+
"#{key}:#{value}"
|
107
|
+
elsif value.starts_with?("(")
|
108
|
+
# we don't want to escape double quotes
|
109
|
+
"#{key}:" + value
|
110
|
+
else
|
111
|
+
"#{key}:\"#{value}\""
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def parse_facet_counts(facet_counts)
|
116
|
+
return {} unless facet_counts
|
117
|
+
|
118
|
+
if facet_counts['facet_fields']
|
119
|
+
facet_counts['facet_fields'] = facet_counts['facet_fields'].reduce({}) do |acc, facet_collection|
|
120
|
+
acc[facet_collection[0]] = map_facet_array_to_facet_hash(facet_collection[1])
|
121
|
+
acc
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if facet_counts['facet_queries']
|
126
|
+
facet_counts['facet_queries'] = facet_counts['facet_queries'].group_by{|k,v| k.split(":").first}.reduce({}) do |acc, facet_collection|
|
127
|
+
facet_name = facet_collection[0]
|
128
|
+
values = facet_collection[1]
|
129
|
+
|
130
|
+
acc[facet_name] = values.reduce({}) do |inner_acc, tuple|
|
131
|
+
range = tuple[0].split(":")[1]
|
132
|
+
inner_acc[range] = tuple[1]
|
133
|
+
inner_acc
|
134
|
+
end
|
135
|
+
acc
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
facet_counts
|
140
|
+
end
|
141
|
+
|
142
|
+
# solr facet_fields comes in tuple array format []
|
143
|
+
def map_facet_array_to_facet_hash(facet_collection)
|
144
|
+
if facet_collection.is_a?(Array)
|
145
|
+
facet_collection.each_slice(2).reduce({}){|acc, tuple| acc[tuple[0]] = tuple[1]; acc}
|
146
|
+
else
|
147
|
+
facet_collection
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def embed_highlighting(search_response)
|
152
|
+
return search_response unless search_response[:highlighting]
|
153
|
+
|
154
|
+
excluded_highlighting_fields = ['id', 'db_id', 'type']
|
155
|
+
|
156
|
+
highlighted_docs = search_response[:docs].map do |doc|
|
157
|
+
hl_metadata = search_response[:highlighting][doc['id']]
|
158
|
+
|
159
|
+
hl_metadata.drop_while{|k,v| excluded_highlighting_fields.include?(k) }.each do |k,v|
|
160
|
+
new_value = if doc[k].is_a?(Array)
|
161
|
+
matched = v.map{|t| t.gsub(HL_START_TAG,"").gsub(HL_END_TAG,"") }
|
162
|
+
v.concat(doc[k].drop_while{|text| matched.include?(text) })
|
163
|
+
else
|
164
|
+
v
|
165
|
+
end
|
166
|
+
doc[k] = new_value
|
167
|
+
end if hl_metadata
|
168
|
+
|
169
|
+
doc
|
170
|
+
end
|
171
|
+
|
172
|
+
search_response[:docs] = highlighted_docs
|
173
|
+
|
174
|
+
search_response[:docs].extend RSolr::Pagination::PaginatedDocSet
|
175
|
+
|
176
|
+
search_response
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# namespace test documents
|
184
|
+
if defined?(Rails) && Rails.env == "test"
|
185
|
+
module Solrsam
|
186
|
+
module Search
|
187
|
+
extend ActiveSupport::Concern
|
188
|
+
module ClassMethods
|
189
|
+
def class_name
|
190
|
+
"#{to_s.underscore}_test"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
data/lib/solrsam.rb
ADDED
data/lib/tasks/solr.rake
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'yaml'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
namespace :solr do
|
6
|
+
env = "development"
|
7
|
+
base_dir = File.join(File.dirname(__FILE__), "..", "..")
|
8
|
+
|
9
|
+
if defined? Rails
|
10
|
+
env = Rails.env
|
11
|
+
base_dir = Rails.root
|
12
|
+
end
|
13
|
+
|
14
|
+
solr_config = YAML::load( File.open( File.join(base_dir, "config", "solr.yml") ) )
|
15
|
+
solr_home = File.join(base_dir, "config", "solr")
|
16
|
+
solr_data_dir = solr_config[env]['solr_data_dir']
|
17
|
+
solr_server_url = solr_config[env]['solr_server_url']
|
18
|
+
java_opts = solr_config[env]['java_opts'] || ""
|
19
|
+
|
20
|
+
jetty_port = URI.parse(solr_server_url).port
|
21
|
+
jetty_path = solr_config[env]['jetty_path']
|
22
|
+
|
23
|
+
solr_server_dir = "cd #{jetty_path};"
|
24
|
+
start_solr_cmd = "java #{java_opts} -jar start.jar"
|
25
|
+
logging_xml = "etc/jetty-logging.xml"
|
26
|
+
jetty_port_opt = "jetty.port=#{jetty_port}"
|
27
|
+
solr_params = "#{jetty_port_opt} -Dsolr.solr.home=#{solr_home} -Dsolr.data.dir=#{solr_data_dir}"
|
28
|
+
|
29
|
+
desc "Start solr"
|
30
|
+
task(:start) do
|
31
|
+
# -Dsolr.clustering.enabled=true
|
32
|
+
cmd = kill_matching_process_cmd(jetty_port_opt)
|
33
|
+
stop_exit_status = run_system_command(cmd)
|
34
|
+
|
35
|
+
sleep(1)
|
36
|
+
|
37
|
+
cmd = "#{solr_server_dir} #{start_solr_cmd} #{logging_xml} #{solr_params} &"
|
38
|
+
run_system_command(cmd)
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Stop solr"
|
42
|
+
task(:stop) do
|
43
|
+
cmd = kill_matching_process_cmd(jetty_port_opt)
|
44
|
+
run_system_command(cmd)
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "update spelling dictionary"
|
48
|
+
task :build_dictionary do
|
49
|
+
open("#{solr_server_url}/select?q=facebok&qt=spell&spellcheck.build=true")
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_system_command(cmd)
|
53
|
+
puts cmd
|
54
|
+
status = system(cmd)
|
55
|
+
$?.exitstatus
|
56
|
+
end
|
57
|
+
|
58
|
+
def kill_matching_process_cmd(process_name)
|
59
|
+
cmd = "echo `ps -ef | grep -v grep | grep \"#{process_name.gsub("-", "\\-")}\" | awk '{print $2}'` | xargs kill"
|
60
|
+
end
|
61
|
+
|
62
|
+
# #example of a task to index all items
|
63
|
+
# desc "index food"
|
64
|
+
# task(:import_foods, :needs => :environment) do
|
65
|
+
# FoodDescription.find_in_batches do |batch|
|
66
|
+
# FoodIndexer.index(batch)
|
67
|
+
# puts "Done with batch of size: #{batch.size}"
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
end
|
71
|
+
|
data/solrsam.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "solrsam/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "solrsam"
|
7
|
+
s.version = Solrsam::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Tommy Chheng", "Sam Dalton"]
|
10
|
+
s.email = ["tommy.chheng@gmail.com", "sam@quid.com"]
|
11
|
+
s.homepage = "http://github.com/samdalton/solrsan"
|
12
|
+
s.summary = %q{Lightweight wrapper for using Apache Solr within a Ruby application including Rails and Sinatra.}
|
13
|
+
s.description = %q{solrsan is a lightweight wrapper for using Apache Solr within a Ruby application including Rails and Sinatra.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "solrsam"
|
16
|
+
|
17
|
+
s.add_dependency 'activesupport'
|
18
|
+
s.add_dependency 'activemodel'
|
19
|
+
s.add_dependency 'rsolr', '1.0.0'
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SearchTestHelper
|
2
|
+
def document_mock
|
3
|
+
doc = Document.new({:id => 500,
|
4
|
+
:title => "Solr test document",
|
5
|
+
:author => "Tommy Chheng",
|
6
|
+
:content => "ruby scala search",
|
7
|
+
:review_count => 4,
|
8
|
+
:scores => [1,2,3,4],
|
9
|
+
:created_at => Date.parse("Dec 10 2010")})
|
10
|
+
doc
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
3
|
+
|
4
|
+
MODELS = File.join(File.dirname(__FILE__), "models")
|
5
|
+
$LOAD_PATH.unshift(MODELS)
|
6
|
+
|
7
|
+
#simulate rails env
|
8
|
+
class Rails
|
9
|
+
def self.env
|
10
|
+
"test"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require "rubygems"
|
15
|
+
require "test/unit"
|
16
|
+
require 'solrsam'
|
17
|
+
|
18
|
+
#test models
|
19
|
+
require 'document'
|
20
|
+
|
21
|
+
solr_config = YAML::load( File.open( File.join(File.dirname(__FILE__), "..", "config", "solr.yml") ) )
|
22
|
+
solr_server_url = solr_config["test"]['solr_server_url']
|
23
|
+
|
24
|
+
Solrsam::Config.instance.add_server(:example, 'example.com', :read)
|
25
|
+
Solrsam::Config.instance.add_server(:example, 'example.com', :write)
|
26
|
+
Solrsam::Config.instance.add_server(:default, solr_server_url, :read)
|
27
|
+
Solrsam::Config.instance.add_server(:default, solr_server_url, :write)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'search_test_helper'
|
3
|
+
|
4
|
+
class IndexerTest < Test::Unit::TestCase
|
5
|
+
include SearchTestHelper
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@document = document_mock
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_indexed_fields
|
15
|
+
created_doc = @document.indexed_fields
|
16
|
+
assert_equal @document.attributes[:id], created_doc[:db_id]
|
17
|
+
assert_equal @document.attributes[:title], created_doc[:title]
|
18
|
+
assert_equal @document.attributes[:author], created_doc[:author]
|
19
|
+
assert_equal @document.attributes[:content], created_doc[:content]
|
20
|
+
assert_equal @document.attributes[:review_count], created_doc[:review_count]
|
21
|
+
assert_equal @document.attributes[:scores], created_doc[:scores]
|
22
|
+
assert_equal @document.attributes[:created_at].to_time.utc.xmlschema, created_doc[:created_at]
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'search_test_helper'
|
3
|
+
|
4
|
+
class SearchTest < Test::Unit::TestCase
|
5
|
+
include SearchTestHelper
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Document.destroy_all_index_documents!
|
9
|
+
@document = document_mock
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
Document.destroy_all_index_documents!
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_simple_query
|
17
|
+
Document.index(@document)
|
18
|
+
q = @document.attributes[:title]
|
19
|
+
|
20
|
+
response = Document.search(:q => q)
|
21
|
+
metadata = response[:metadata]
|
22
|
+
docs = response[:docs]
|
23
|
+
assert metadata[:total_count] > 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_sort
|
27
|
+
Document.index(Document.new(:id => 3, :title => "solar city",:review_count => 10))
|
28
|
+
Document.index(Document.new(:id => 4, :title => "city solar", :review_count => 5))
|
29
|
+
|
30
|
+
q = "solar"
|
31
|
+
response = Document.search(:q => q, :sort => "review_count asc")
|
32
|
+
docs = response[:docs]
|
33
|
+
|
34
|
+
assert_not_nil docs[0], "Not enough docs for #{q} to test."
|
35
|
+
first_result_name = docs[0][:title]
|
36
|
+
assert_not_nil docs[1], "Not enough docs for #{q} to test."
|
37
|
+
second_result_name = docs[1][:title]
|
38
|
+
|
39
|
+
assert_equal [second_result_name, first_result_name].sort, [first_result_name, second_result_name]
|
40
|
+
|
41
|
+
response = Document.search(:q => q, :sort => "review_count desc")
|
42
|
+
docs = response[:docs]
|
43
|
+
|
44
|
+
assert_not_nil docs[0], "Not enough docs for #{q} to test."
|
45
|
+
first_result_name = docs[0][:title]
|
46
|
+
assert_not_nil docs[1], "Not enough docs for #{q} to test."
|
47
|
+
second_result_name = docs[1][:title]
|
48
|
+
|
49
|
+
assert_equal [second_result_name, first_result_name].sort.reverse, [first_result_name, second_result_name]
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_invalid_query_should_return_error_message_in_metadata
|
53
|
+
response = Document.search(:q => "http://tommy.chheng.com")
|
54
|
+
docs = response[:docs]
|
55
|
+
metadata = response[:metadata]
|
56
|
+
|
57
|
+
assert_not_nil response[:metadata][:error]
|
58
|
+
assert_equal 400, response[:metadata][:error][:http_status_code]
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_parse_facet_fields
|
62
|
+
facet_counts = {'facet_queries'=>{},
|
63
|
+
'facet_fields' => {'language' => ["Scala", 2, "Ruby", 1, "Java", 0]},
|
64
|
+
'facet_dates'=>{}}
|
65
|
+
|
66
|
+
facet_counts = Document.parse_facet_counts(facet_counts)
|
67
|
+
|
68
|
+
assert_equal ["Scala", "Ruby", "Java"], facet_counts['facet_fields']['language'].keys
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_parse_facet_queries
|
72
|
+
facet_counts = {"facet_queries"=>{"funding:[0 TO 5000000]"=>1, "funding:[10000000 TO 50000000]"=>0}, "facet_fields"=>{}, "facet_dates"=>{}}
|
73
|
+
|
74
|
+
facet_counts = Document.parse_facet_counts(facet_counts)
|
75
|
+
|
76
|
+
expected = {"funding"=>{"[0 TO 5000000]"=>1, "[10000000 TO 50000000]"=>0}}
|
77
|
+
assert_equal expected, facet_counts['facet_queries']
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_parse_fq_with_hash
|
81
|
+
params = {:fq => {:tags => ["ruby", "scala"]}}
|
82
|
+
filters = Document.parse_fq(params[:fq])
|
83
|
+
|
84
|
+
expected = ["tags:\"ruby\"", "tags:\"scala\""]
|
85
|
+
assert_equal expected, filters
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_parse_fq_with_hash_multiple_entries
|
89
|
+
params = {:fq => {:tags => ["ruby", "scala"], :author => "Bert"}}
|
90
|
+
filters = Document.parse_fq(params[:fq])
|
91
|
+
|
92
|
+
expected = ["tags:\"ruby\"", "tags:\"scala\"", "author:\"Bert\""]
|
93
|
+
assert_equal expected, filters
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_parse_fq_with_hash_array_args
|
97
|
+
params = {:fq => [{:tags => ["ruby", "scala"]}]}
|
98
|
+
filters = Document.parse_fq(params[:fq])
|
99
|
+
|
100
|
+
expected = ["tags:\"ruby\"", "tags:\"scala\""]
|
101
|
+
assert_equal expected, filters
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_parse_fq_with_hash_string_args
|
105
|
+
params = {:fq => [{:tags => "ruby"}]}
|
106
|
+
filters = Document.parse_fq(params[:fq])
|
107
|
+
|
108
|
+
expected = ["tags:\"ruby\""]
|
109
|
+
assert_equal expected, filters
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_parse_fq_with_string_args
|
113
|
+
params = {:fq => ["tags:ruby"]}
|
114
|
+
filters = Document.parse_fq(params[:fq])
|
115
|
+
|
116
|
+
expected = ["tags:ruby"]
|
117
|
+
assert_equal expected, filters
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_parse_fq_with_empty
|
121
|
+
filters = Document.parse_fq([])
|
122
|
+
expected = []
|
123
|
+
assert_equal expected, filters
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def test_filter_query_mulitple_filters
|
128
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10, :tags => ['ruby']))
|
129
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5, :tags => ['ruby', 'scala']))
|
130
|
+
|
131
|
+
response = Document.search(:q => "solr", :fq => {:tags => ["scala"], :author => "Ernie"})
|
132
|
+
docs = response[:docs]
|
133
|
+
metadata = response[:metadata]
|
134
|
+
|
135
|
+
assert_equal 1, metadata[:total_count]
|
136
|
+
|
137
|
+
doc = docs.first
|
138
|
+
assert_not_nil doc['tags']
|
139
|
+
assert doc['tags'].include?("scala")
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_filter_query
|
143
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10, :tags => ['ruby']))
|
144
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5, :tags => ['ruby', 'scala']))
|
145
|
+
|
146
|
+
response = Document.search(:q => "solr", :fq => [{:tags => ["scala"]}])
|
147
|
+
docs = response[:docs]
|
148
|
+
metadata = response[:metadata]
|
149
|
+
|
150
|
+
assert_equal 1, metadata[:total_count]
|
151
|
+
|
152
|
+
doc = docs.first
|
153
|
+
assert_not_nil doc['tags']
|
154
|
+
assert doc['tags'].include?("scala")
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_text_faceting
|
158
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10))
|
159
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5))
|
160
|
+
|
161
|
+
response = Document.search(:q => "solr", :'facet.field' => ['author'])
|
162
|
+
docs = response[:docs]
|
163
|
+
facet_counts = response[:facet_counts]
|
164
|
+
assert_not_nil facet_counts["facet_fields"]["author"]
|
165
|
+
|
166
|
+
author_facet_entries = facet_counts["facet_fields"]["author"]
|
167
|
+
assert author_facet_entries.keys.include?("Bert") && author_facet_entries.keys.include?("Ernie")
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_range_faceting
|
171
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10))
|
172
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5))
|
173
|
+
|
174
|
+
response = Document.search(:q => "solr", :'facet.field' => ['author'], :'facet.query' => ["review_count:[1 TO 5]", "review_count:[6 TO 10]"])
|
175
|
+
docs = response[:docs]
|
176
|
+
facet_counts = response[:facet_counts]
|
177
|
+
|
178
|
+
assert_not_nil facet_counts["facet_fields"]["author"]
|
179
|
+
assert_not_nil facet_counts["facet_queries"]["review_count"]
|
180
|
+
assert_equal({"[1 TO 5]"=>1, "[6 TO 10]"=>1}, facet_counts["facet_queries"]["review_count"])
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_highlighting_support
|
184
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10, :tags => ["solr"]))
|
185
|
+
|
186
|
+
response = Document.search(:q => "solr",
|
187
|
+
:'hl.fl' => "*")
|
188
|
+
docs = response[:docs]
|
189
|
+
highlighting = response[:highlighting]
|
190
|
+
|
191
|
+
first_result = highlighting.first
|
192
|
+
assert first_result[1]['tags'].include?("<mark>solr</mark>")
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_embed_highlighting
|
196
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10, :tags => ["solr", "sphinx"]))
|
197
|
+
|
198
|
+
response = Document.search(:q => "solr",
|
199
|
+
:'hl.fl' => "*")
|
200
|
+
docs = response[:docs]
|
201
|
+
assert_equal ["<mark>solr</mark>","sphinx"], docs.first['tags']
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_debug_response
|
205
|
+
Document.index(@document)
|
206
|
+
q = @document.attributes[:title]
|
207
|
+
|
208
|
+
response = Document.search({:q => q, :debugQuery => true})
|
209
|
+
metadata = response[:metadata]
|
210
|
+
assert_not_nil metadata[:debug]
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_stats_response
|
214
|
+
Document.index(@document)
|
215
|
+
q = @document.attributes[:title]
|
216
|
+
|
217
|
+
response = Document.search({:q => q, :stats => true, :'stats.field' => 'review_count'})
|
218
|
+
assert_not_nil response[:stats]
|
219
|
+
assert_equal 1, response[:stats]['stats_fields']['review_count']['count']
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_will_paginate_support
|
223
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10))
|
224
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5))
|
225
|
+
|
226
|
+
response = Document.search(:q => "solr")
|
227
|
+
docs = response[:docs]
|
228
|
+
assert_not_nil docs.start
|
229
|
+
assert_not_nil docs.per_page
|
230
|
+
assert_not_nil docs.current_page
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_solr_server_attribute_writable
|
234
|
+
begin
|
235
|
+
Document.solr_server = :example
|
236
|
+
assert_equal :example, Document.solr_server
|
237
|
+
ensure
|
238
|
+
Document.solr_server = nil
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_rsolr_is_configured_with_the_set_solr_server
|
243
|
+
begin
|
244
|
+
Document.solr_server = :example
|
245
|
+
assert_equal "example.com/", Document.solr.options[:url]
|
246
|
+
ensure
|
247
|
+
Document.solr_server = nil
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|