solrsan 0.0.20
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +26 -0
- data/LICENSE +23 -0
- data/README.markdown +54 -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 +30 -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/solrsan/config.rb +10 -0
- data/lib/solrsan/indexer.rb +83 -0
- data/lib/solrsan/search.rb +149 -0
- data/lib/solrsan/version.rb +3 -0
- data/lib/solrsan.rb +12 -0
- data/lib/tasks/solr.rake +63 -0
- data/solrsan.gemspec +25 -0
- data/test/models/document.rb +11 -0
- data/test/search_test_helper.rb +13 -0
- data/test/test_helper.rb +24 -0
- data/test/unit/indexer_test.rb +25 -0
- data/test/unit/search_test.rb +171 -0
- metadata +123 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
module Solrsan
|
2
|
+
module Search
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
module ClassMethods
|
5
|
+
def class_name
|
6
|
+
to_s.underscore
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform_solr_command
|
10
|
+
@rsolr = Solrsan::Config.instance.rsolr_object
|
11
|
+
yield(@rsolr)
|
12
|
+
@rsolr.commit
|
13
|
+
end
|
14
|
+
|
15
|
+
def search(search_params={})
|
16
|
+
@rsolr ||= Solrsan::Config.instance.rsolr_object
|
17
|
+
|
18
|
+
start = search_params[:start] || 0
|
19
|
+
rows = search_params[:rows] || 20
|
20
|
+
|
21
|
+
solr_params = parse_params_for_solr(search_params)
|
22
|
+
|
23
|
+
begin
|
24
|
+
solr_response = @rsolr.paginate(start, rows, 'select', :params => solr_params)
|
25
|
+
parse_solr_response(solr_response)
|
26
|
+
rescue RSolr::Error::Http => e
|
27
|
+
{:docs => [],
|
28
|
+
:metadata =>
|
29
|
+
{:error => {:http_status_code => e.response[:status],
|
30
|
+
:http_message_status => RSolr::Error::Http::STATUS_CODES[e.response[:status].to_i],
|
31
|
+
:full_message => e.message}}}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_params_for_solr(search_params={})
|
36
|
+
solr_params = { :echoParams => 'explicit',
|
37
|
+
:q => "*:*",
|
38
|
+
:facet => "on",
|
39
|
+
:'facet.mincount' => 1}.merge(search_params)
|
40
|
+
solr_params[:hl] = true unless search_params[:'hl.fl'].blank?
|
41
|
+
solr_params[:fq] = ["type:#{class_name}"] + parse_fq(search_params[:fq])
|
42
|
+
solr_params
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_solr_response(solr_response)
|
46
|
+
docs = solr_response['response']['docs']
|
47
|
+
parsed_facet_counts = parse_facet_counts(solr_response['facet_counts'])
|
48
|
+
highlighting = solr_response['highlighting']
|
49
|
+
|
50
|
+
metadata = {
|
51
|
+
:total_count => solr_response['response']['numFound'],
|
52
|
+
:start => solr_response['response']['start'],
|
53
|
+
:rows => solr_response['responseHeader']['params']['rows'],
|
54
|
+
:time => solr_response['responseHeader']['QTime'],
|
55
|
+
:status => solr_response['responseHeader']['status']
|
56
|
+
}
|
57
|
+
|
58
|
+
{:docs => docs, :metadata => metadata,
|
59
|
+
:facet_counts => parsed_facet_counts, :highlighting => highlighting}
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse_fq(fq)
|
63
|
+
return [] if fq.nil?
|
64
|
+
if fq.is_a?(Hash)
|
65
|
+
fq.map{|k,v| parse_element_in_fq({k => v})}.flatten
|
66
|
+
elsif fq.is_a?(Array)
|
67
|
+
fq.map{|ele| parse_element_in_fq(ele)}.flatten
|
68
|
+
else
|
69
|
+
raise "fq must be a hash or array"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_element_in_fq(element)
|
74
|
+
if element.is_a?(String)
|
75
|
+
element
|
76
|
+
elsif element.is_a?(Hash)
|
77
|
+
element.map do |k,values|
|
78
|
+
if values.is_a?(String)
|
79
|
+
key_value_query(k,values)
|
80
|
+
else
|
81
|
+
values.map{|value| key_value_query(k,value) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
raise "each fq parameter must be a string or hash"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def key_value_query(key, value)
|
90
|
+
if value.starts_with?("[")
|
91
|
+
"#{key}:#{value}"
|
92
|
+
else
|
93
|
+
"#{key}:\"#{value}\""
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def parse_facet_counts(facet_counts)
|
98
|
+
return {} unless facet_counts
|
99
|
+
|
100
|
+
if facet_counts['facet_fields']
|
101
|
+
facet_counts['facet_fields'] = facet_counts['facet_fields'].reduce({}) do |acc, facet_collection|
|
102
|
+
acc[facet_collection[0]] = map_facet_array_to_facet_hash(facet_collection[1])
|
103
|
+
acc
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
if facet_counts['facet_queries']
|
108
|
+
facet_counts['facet_queries'] = facet_counts['facet_queries'].group_by{|k,v| k.split(":").first}.reduce({}) do |acc, facet_collection|
|
109
|
+
facet_name = facet_collection[0]
|
110
|
+
values = facet_collection[1]
|
111
|
+
|
112
|
+
acc[facet_name] = values.reduce({}) do |inner_acc, tuple|
|
113
|
+
range = tuple[0].split(":")[1]
|
114
|
+
inner_acc[range] = tuple[1]
|
115
|
+
inner_acc
|
116
|
+
end
|
117
|
+
acc
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
facet_counts
|
122
|
+
end
|
123
|
+
|
124
|
+
# solr facet_fields comes in tuple array format []
|
125
|
+
def map_facet_array_to_facet_hash(facet_collection)
|
126
|
+
if facet_collection.is_a?(Array)
|
127
|
+
facet_collection.each_slice(2).reduce({}){|acc, tuple| acc[tuple[0]] = tuple[1]; acc}
|
128
|
+
else
|
129
|
+
facet_collection
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# namespace test documents
|
138
|
+
if defined?(Rails) && Rails.env == "test"
|
139
|
+
module Solrsan
|
140
|
+
module Search
|
141
|
+
extend ActiveSupport::Concern
|
142
|
+
module ClassMethods
|
143
|
+
def class_name
|
144
|
+
"#{to_s.underscore}_test"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/solrsan.rb
ADDED
data/lib/tasks/solr.rake
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
namespace :solr do
|
5
|
+
env = "development"
|
6
|
+
base_dir = File.join(File.dirname(__FILE__), "..", "..")
|
7
|
+
|
8
|
+
if defined? Rails
|
9
|
+
env = Rails.env
|
10
|
+
base_dir = Rails.root
|
11
|
+
end
|
12
|
+
|
13
|
+
solr_config = YAML::load( File.open( File.join(base_dir, "config", "solr.yml") ) )
|
14
|
+
solr_home = File.join(base_dir, "config", "solr")
|
15
|
+
solr_data_dir = solr_config[env]['solr_data_dir']
|
16
|
+
solr_server_url = solr_config[env]['solr_server_url']
|
17
|
+
|
18
|
+
jetty_port = URI.parse(solr_server_url).port
|
19
|
+
jetty_path = solr_config[env]['jetty_path']
|
20
|
+
|
21
|
+
solr_server_dir = "cd #{jetty_path};"
|
22
|
+
start_solr_cmd = "java -jar start.jar"
|
23
|
+
jetty_port_opt = "jetty.port=#{jetty_port}"
|
24
|
+
solr_params = "#{jetty_port_opt} -Dsolr.solr.home=#{solr_home} -Dsolr.data.dir=#{solr_data_dir}"
|
25
|
+
|
26
|
+
desc "Start solr"
|
27
|
+
task(:start) do
|
28
|
+
# -Dsolr.clustering.enabled=true
|
29
|
+
cmd = kill_matching_process_cmd(jetty_port_opt)
|
30
|
+
stop_exit_status = run_system_command(cmd)
|
31
|
+
|
32
|
+
sleep(1)
|
33
|
+
|
34
|
+
cmd = "#{solr_server_dir} #{start_solr_cmd } #{solr_params} &"
|
35
|
+
run_system_command(cmd)
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Stop solr"
|
39
|
+
task(:stop) do
|
40
|
+
cmd = kill_matching_process_cmd(jetty_port_opt)
|
41
|
+
run_system_command(cmd)
|
42
|
+
end
|
43
|
+
|
44
|
+
def run_system_command(cmd)
|
45
|
+
puts cmd
|
46
|
+
status = system(cmd)
|
47
|
+
$?.exitstatus
|
48
|
+
end
|
49
|
+
|
50
|
+
def kill_matching_process_cmd(process_name)
|
51
|
+
cmd = "echo `ps -ef | grep -v grep | grep \"#{process_name.gsub("-", "\\-")}\" | awk '{print $2}'` | xargs kill"
|
52
|
+
end
|
53
|
+
|
54
|
+
# #example of a task to index all items
|
55
|
+
# desc "index food"
|
56
|
+
# task(:import_foods, :needs => :environment) do
|
57
|
+
# FoodDescription.find_in_batches do |batch|
|
58
|
+
# FoodIndexer.index(batch)
|
59
|
+
# puts "Done with batch of size: #{batch.size}"
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
end
|
63
|
+
|
data/solrsan.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "solrsan/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "solrsan"
|
7
|
+
s.version = Solrsan::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Tommy Chheng"]
|
10
|
+
s.email = ["tommy.chheng@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/tc/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.add_dependency('rsolr', '~>1.0.0')
|
16
|
+
s.add_dependency('activemodel', '~>3.0.5')
|
17
|
+
s.add_dependency('activesupport', '~>3.0.5')
|
18
|
+
|
19
|
+
s.rubyforge_project = "solrsan"
|
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,24 @@
|
|
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 'solrsan'
|
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
|
+
Solrsan::Config.instance.solr_server_url = solr_server_url
|
@@ -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,171 @@
|
|
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_array_args
|
89
|
+
params = {:fq => [{:tags => ["ruby", "scala"]}]}
|
90
|
+
filters = Document.parse_fq(params[:fq])
|
91
|
+
|
92
|
+
expected = ["tags:\"ruby\"", "tags:\"scala\""]
|
93
|
+
assert_equal expected, filters
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_parse_fq_with_hash_string_args
|
97
|
+
params = {:fq => [{:tags => "ruby"}]}
|
98
|
+
filters = Document.parse_fq(params[:fq])
|
99
|
+
|
100
|
+
expected = ["tags:\"ruby\""]
|
101
|
+
assert_equal expected, filters
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_parse_fq_with_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_empty
|
113
|
+
filters = Document.parse_fq([])
|
114
|
+
expected = []
|
115
|
+
assert_equal expected, filters
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_filter_query
|
119
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10, :tags => ['ruby']))
|
120
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5, :tags => ['ruby', 'scala']))
|
121
|
+
|
122
|
+
response = Document.search(:q => "solr", :fq => [{:tags => ["scala"]}])
|
123
|
+
docs = response[:docs]
|
124
|
+
metadata = response[:metadata]
|
125
|
+
|
126
|
+
assert_equal 1, metadata[:total_count]
|
127
|
+
|
128
|
+
doc = docs.first
|
129
|
+
assert_not_nil doc['tags']
|
130
|
+
assert doc['tags'].include?("scala")
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_text_faceting
|
134
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10))
|
135
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5))
|
136
|
+
|
137
|
+
response = Document.search(:q => "solr", :'facet.field' => ['author'])
|
138
|
+
docs = response[:docs]
|
139
|
+
facet_counts = response[:facet_counts]
|
140
|
+
assert_not_nil facet_counts["facet_fields"]["author"]
|
141
|
+
|
142
|
+
author_facet_entries = facet_counts["facet_fields"]["author"]
|
143
|
+
assert author_facet_entries.keys.include?("Bert") && author_facet_entries.keys.include?("Ernie")
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_range_faceting
|
147
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10))
|
148
|
+
Document.index(Document.new(:id => 4, :author => "Ernie", :title => "lucene solr", :review_count => 5))
|
149
|
+
|
150
|
+
response = Document.search(:q => "solr", :'facet.field' => ['author'], :'facet.query' => ["review_count:[1 TO 5]", "review_count:[6 TO 10]"])
|
151
|
+
docs = response[:docs]
|
152
|
+
facet_counts = response[:facet_counts]
|
153
|
+
|
154
|
+
assert_not_nil facet_counts["facet_fields"]["author"]
|
155
|
+
assert_not_nil facet_counts["facet_queries"]["review_count"]
|
156
|
+
assert_equal({"[1 TO 5]"=>1, "[6 TO 10]"=>1}, facet_counts["facet_queries"]["review_count"])
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_highlighting_support
|
160
|
+
Document.index(Document.new(:id => 3, :author => "Bert", :title => "solr lucene",:review_count => 10, :tags => ["solr"]))
|
161
|
+
|
162
|
+
response = Document.search(:q => "solr",
|
163
|
+
:'hl.fl' => "*")
|
164
|
+
docs = response[:docs]
|
165
|
+
highlighting = response[:highlighting]
|
166
|
+
|
167
|
+
first_result = highlighting.first
|
168
|
+
assert first_result[1]['tags'].include?("<em>solr</em>")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: solrsan
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.20
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tommy Chheng
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-03-18 00:00:00.000000000 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rsolr
|
17
|
+
requirement: &2153183880 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.0.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2153183880
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: activemodel
|
28
|
+
requirement: &2153183260 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.5
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2153183260
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: activesupport
|
39
|
+
requirement: &2153182780 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 3.0.5
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2153182780
|
48
|
+
description: solrsan is a lightweight wrapper for using Apache Solr within a Ruby
|
49
|
+
application including Rails and Sinatra.
|
50
|
+
email:
|
51
|
+
- tommy.chheng@gmail.com
|
52
|
+
executables: []
|
53
|
+
extensions: []
|
54
|
+
extra_rdoc_files: []
|
55
|
+
files:
|
56
|
+
- .gitignore
|
57
|
+
- Gemfile
|
58
|
+
- Gemfile.lock
|
59
|
+
- LICENSE
|
60
|
+
- README.markdown
|
61
|
+
- Rakefile
|
62
|
+
- config/solr.yml
|
63
|
+
- config/solr.yml.example
|
64
|
+
- config/solr/conf/elevate.xml
|
65
|
+
- config/solr/conf/mapping-ISOLatin1Accent.txt
|
66
|
+
- config/solr/conf/protwords.txt
|
67
|
+
- config/solr/conf/schema.xml
|
68
|
+
- config/solr/conf/solrconfig.xml
|
69
|
+
- config/solr/conf/spellings.txt
|
70
|
+
- config/solr/conf/stopwords.txt
|
71
|
+
- config/solr/conf/synonyms.txt
|
72
|
+
- config/solr/conf/xslt/example.xsl
|
73
|
+
- config/solr/conf/xslt/example_atom.xsl
|
74
|
+
- config/solr/conf/xslt/example_rss.xsl
|
75
|
+
- config/solr/conf/xslt/luke.xsl
|
76
|
+
- lib/rails/generators/solrsan/config/config_generator.rb
|
77
|
+
- lib/rails/generators/solrsan/config/templates/solr.yml
|
78
|
+
- lib/rails/generators/solrsan/config/templates/solrsan.rb
|
79
|
+
- lib/rails/generators/solrsan_generator.rb
|
80
|
+
- lib/solrsan.rb
|
81
|
+
- lib/solrsan/config.rb
|
82
|
+
- lib/solrsan/indexer.rb
|
83
|
+
- lib/solrsan/search.rb
|
84
|
+
- lib/solrsan/version.rb
|
85
|
+
- lib/tasks/solr.rake
|
86
|
+
- solrsan.gemspec
|
87
|
+
- test/models/document.rb
|
88
|
+
- test/search_test_helper.rb
|
89
|
+
- test/test_helper.rb
|
90
|
+
- test/unit/indexer_test.rb
|
91
|
+
- test/unit/search_test.rb
|
92
|
+
has_rdoc: true
|
93
|
+
homepage: http://github.com/tc/solrsan
|
94
|
+
licenses: []
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project: solrsan
|
113
|
+
rubygems_version: 1.6.2
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Lightweight wrapper for using Apache Solr within a Ruby application including
|
117
|
+
Rails and Sinatra.
|
118
|
+
test_files:
|
119
|
+
- test/models/document.rb
|
120
|
+
- test/search_test_helper.rb
|
121
|
+
- test/test_helper.rb
|
122
|
+
- test/unit/indexer_test.rb
|
123
|
+
- test/unit/search_test.rb
|