mwmitchell-rsolr 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +9 -0
- data/README.rdoc +28 -43
- data/Rakefile +1 -2
- data/examples/direct.rb +8 -9
- data/examples/http.rb +9 -8
- data/lib/rsolr.rb +10 -14
- data/lib/rsolr/adapter.rb +6 -0
- data/lib/rsolr/{connection/adapter → adapter}/direct.rb +3 -4
- data/lib/rsolr/{connection/adapter → adapter}/http.rb +4 -11
- data/lib/rsolr/connection.rb +104 -3
- data/lib/rsolr/http_client.rb +28 -14
- data/lib/rsolr/http_client/adapter/net_http.rb +1 -1
- data/lib/rsolr/message.rb +5 -6
- data/test/connection/direct_test.rb +19 -20
- data/test/connection/http_test.rb +3 -4
- data/test/connection/test_methods.rb +40 -50
- data/test/http_client/curb_test.rb +3 -4
- data/test/http_client/net_http_test.rb +3 -4
- data/test/http_client/test_methods.rb +1 -1
- data/test/http_client/util_test.rb +1 -1
- data/test/message_test.rb +8 -7
- metadata +6 -20
- data/lib/rsolr/connection/adapter.rb +0 -7
- data/lib/rsolr/connection/adapter/common_methods.rb +0 -50
- data/lib/rsolr/connection/base.rb +0 -101
- data/lib/rsolr/query.rb +0 -58
- data/lib/rsolr/response.rb +0 -8
- data/lib/rsolr/response/base.rb +0 -25
- data/lib/rsolr/response/index_info.rb +0 -33
- data/lib/rsolr/response/query.rb +0 -163
- data/lib/rsolr/response/update.rb +0 -4
- data/test/query_helper_test.rb +0 -30
- data/test/response/base_test.rb +0 -38
- data/test/response/pagination_test.rb +0 -47
- data/test/response/query_test.rb +0 -44
- data/test/test_helpers.rb +0 -61
@@ -1,101 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Connection adapter decorator
|
3
|
-
#
|
4
|
-
class RSolr::Connection::Base
|
5
|
-
|
6
|
-
attr_reader :adapter, :opts
|
7
|
-
|
8
|
-
# "adapter" is instance of:
|
9
|
-
# RSolr::Adapter::HTTP
|
10
|
-
# RSolr::Adapter::Direct (jRuby only)
|
11
|
-
def initialize(adapter, opts={})
|
12
|
-
@adapter = adapter
|
13
|
-
@opts = opts
|
14
|
-
end
|
15
|
-
|
16
|
-
# send request (no param mapping) to the select handler
|
17
|
-
# params is hash with valid solr request params (:q, :fl, :qf etc..)
|
18
|
-
# if params[:wt] is not set, the default is :ruby (see opts[:global_params])
|
19
|
-
# if :wt is something other than :ruby, the raw response body is returned
|
20
|
-
# otherwise, an instance of RSolr::Response::Query is returned
|
21
|
-
# NOTE: to get raw ruby, use :wt=>'ruby'
|
22
|
-
# There is NO param mapping here, what you put it is what gets sent to Solr
|
23
|
-
def query(*args)
|
24
|
-
params = map_params(args.extract_options!)
|
25
|
-
args << params
|
26
|
-
response = @adapter.query(*args)
|
27
|
-
params[:wt] == :ruby ? RSolr::Response::Query::Base.new(response) : response
|
28
|
-
end
|
29
|
-
|
30
|
-
# Finds a document by its id
|
31
|
-
def find_by_id(*args)
|
32
|
-
params = map_params(args.extract_options!)
|
33
|
-
params[:q] = 'id:"#{id}"'
|
34
|
-
args << params
|
35
|
-
self.query(*args)
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
def update(*args)
|
40
|
-
params = map_params(args.extract_options!)
|
41
|
-
args << params
|
42
|
-
response = @adapter.update(*args)
|
43
|
-
params[:wt] == :ruby ? RSolr::Response::Update.new(response) : response
|
44
|
-
end
|
45
|
-
|
46
|
-
def index_info(*args)
|
47
|
-
params = map_params(args.extract_options!)
|
48
|
-
args << params
|
49
|
-
response = @adapter.index_info(*args)
|
50
|
-
params[:wt] == :ruby ? RSolr::Response::IndexInfo.new(response) : response
|
51
|
-
end
|
52
|
-
|
53
|
-
def add(*args, &block)
|
54
|
-
update message.add(*args, &block)
|
55
|
-
end
|
56
|
-
|
57
|
-
# send </commit>
|
58
|
-
def commit(*args)
|
59
|
-
update message.commit, *args
|
60
|
-
end
|
61
|
-
|
62
|
-
# send </optimize>
|
63
|
-
def optimize(*args)
|
64
|
-
update message.optimize, *args
|
65
|
-
end
|
66
|
-
|
67
|
-
# send </rollback>
|
68
|
-
# NOTE: solr 1.4 only
|
69
|
-
def rollback(*args)
|
70
|
-
update message.rollback, *args
|
71
|
-
end
|
72
|
-
|
73
|
-
# Delete one or many documents by id
|
74
|
-
# solr.delete_by_id 10
|
75
|
-
# solr.delete_by_id([12, 41, 199])
|
76
|
-
def delete_by_id(*args)
|
77
|
-
update message.delete_by_id(args.shift), *args
|
78
|
-
end
|
79
|
-
|
80
|
-
# delete one or many documents by query
|
81
|
-
# solr.delete_by_query 'available:0'
|
82
|
-
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
83
|
-
def delete_by_query(*args)
|
84
|
-
update message.delete_by_query(args.shift), *args
|
85
|
-
end
|
86
|
-
|
87
|
-
protected
|
88
|
-
|
89
|
-
# shortcut to solr::message
|
90
|
-
def message
|
91
|
-
RSolr::Message
|
92
|
-
end
|
93
|
-
|
94
|
-
# sets default params etc.. - could be used as a mapping hook
|
95
|
-
# type of request should be passed in here? -> map_params(:query, {})
|
96
|
-
def map_params(params)
|
97
|
-
params||={}
|
98
|
-
{:wt=>:ruby}.merge(params)
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
data/lib/rsolr/query.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module RSolr::Query
|
2
|
-
|
3
|
-
module HelperMethods
|
4
|
-
|
5
|
-
# returns a quoted or non-quoted string
|
6
|
-
# "value" should be a string
|
7
|
-
# "quote" should be true/false
|
8
|
-
def prep_value(value, quote)
|
9
|
-
quote ? %("#{value}") : value
|
10
|
-
end
|
11
|
-
|
12
|
-
# value can be a string, array, hash or symbol
|
13
|
-
# symbols are treated as strings
|
14
|
-
# arrays are recursed through #build_query
|
15
|
-
# keys for hashes are fields for fielded queries, the values are recused through #build_query
|
16
|
-
# strings/symbols are sent to #prep_value for possible quoting
|
17
|
-
#
|
18
|
-
# opts can have:
|
19
|
-
# :quote=>bool - default false
|
20
|
-
# :join=>string - default ' '
|
21
|
-
def build_query(value, opts={})
|
22
|
-
opts[:join]||=' '
|
23
|
-
opts[:quote]||=false
|
24
|
-
result = (
|
25
|
-
case value
|
26
|
-
when Array
|
27
|
-
value.collect do |item|
|
28
|
-
build_query item, opts
|
29
|
-
end.flatten
|
30
|
-
when String,Symbol
|
31
|
-
[prep_value(value.to_s, opts[:quote])]
|
32
|
-
when Hash
|
33
|
-
value.collect do |(k,v)|
|
34
|
-
"#{k}:#{build_query(v, opts)}"
|
35
|
-
end.flatten
|
36
|
-
else
|
37
|
-
[prep_value(value.to_s, opts[:quote])]
|
38
|
-
end
|
39
|
-
)
|
40
|
-
opts[:join] ? result.join(opts[:join]) : result
|
41
|
-
end
|
42
|
-
|
43
|
-
# start_for(2, 10)
|
44
|
-
# calculates the :start value for pagination etc..
|
45
|
-
def start_for(current_page, per_page)
|
46
|
-
page = current_page.to_s.to_i
|
47
|
-
page = page > 0 ? page : 1
|
48
|
-
((page - 1) * (per_page || 0))
|
49
|
-
end
|
50
|
-
|
51
|
-
end # end HelperMethods
|
52
|
-
|
53
|
-
# Easy access: RSolr::Query::Helper.start_for(page=1, per_page=10)
|
54
|
-
class Helper
|
55
|
-
extend HelperMethods
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
data/lib/rsolr/response.rb
DELETED
data/lib/rsolr/response/base.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# default/base response object
|
2
|
-
# This is where the ruby "eval" happens
|
3
|
-
# So far, all response classes extend this
|
4
|
-
class RSolr::Response::Base
|
5
|
-
|
6
|
-
# the object that contains the original :body, :params, full solr :query, post :data etc.
|
7
|
-
attr_reader :input
|
8
|
-
|
9
|
-
attr_reader :data, :header, :params, :status, :query_time
|
10
|
-
|
11
|
-
def initialize(input)
|
12
|
-
input = {:body=>input} if input.is_a?(String)
|
13
|
-
@input = input
|
14
|
-
@data = Kernel.eval(input[:body]).to_mash
|
15
|
-
@header = @data[:responseHeader]
|
16
|
-
@params = @header[:params]
|
17
|
-
@status = @header[:status]
|
18
|
-
@query_time = @header[:QTime]
|
19
|
-
end
|
20
|
-
|
21
|
-
def ok?
|
22
|
-
self.status == 0
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# response for /admin/luke
|
2
|
-
class RSolr::Response::IndexInfo < RSolr::Response::Base
|
3
|
-
|
4
|
-
attr_reader :index, :directory, :has_deletions, :optimized, :current, :max_doc, :num_docs, :version
|
5
|
-
|
6
|
-
alias :has_deletions? :has_deletions
|
7
|
-
alias :optimized? :optimized
|
8
|
-
alias :current? :current
|
9
|
-
|
10
|
-
def initialize(data)
|
11
|
-
super(data)
|
12
|
-
@index = @data[:index]
|
13
|
-
@directory = @data[:directory]
|
14
|
-
# index fields
|
15
|
-
@has_deletions = @index[:hasDeletions]
|
16
|
-
@optimized = @index[:optimized]
|
17
|
-
@current = @index[:current]
|
18
|
-
@max_doc = @index[:maxDoc]
|
19
|
-
@num_docs = @index[:numDocs]
|
20
|
-
@version = @index[:version]
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns an array of fields from the index
|
24
|
-
# An optional rule can be used for "grepping" field names:
|
25
|
-
# field_list(/_facet$/)
|
26
|
-
def field_list(rule=nil)
|
27
|
-
@data[:fields].select do |k,v|
|
28
|
-
rule ? k =~ rule : true
|
29
|
-
end.collect{|k,v|k}
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
end
|
data/lib/rsolr/response/query.rb
DELETED
@@ -1,163 +0,0 @@
|
|
1
|
-
# response module for queries
|
2
|
-
module RSolr::Response::Query
|
3
|
-
|
4
|
-
# module for adding helper methods to each Hash document
|
5
|
-
module DocExt
|
6
|
-
|
7
|
-
# Helper method to check if value/multi-values exist for a given key.
|
8
|
-
# The value can be a string, or a RegExp
|
9
|
-
# Example:
|
10
|
-
# doc.has?(:location_facet)
|
11
|
-
# doc.has?(:location_facet, 'Clemons')
|
12
|
-
# doc.has?(:id, 'h009', /^u/i)
|
13
|
-
def has?(k, *values)
|
14
|
-
return if self[k].nil?
|
15
|
-
return true if self.key?(k) and values.empty?
|
16
|
-
target = self[k]
|
17
|
-
if target.is_a?(Array)
|
18
|
-
values.each do |val|
|
19
|
-
return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
|
20
|
-
end
|
21
|
-
else
|
22
|
-
return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# helper
|
27
|
-
# key is the name of the field
|
28
|
-
# opts is a hash with the following valid keys:
|
29
|
-
# - :sep - a string used for joining multivalued field values
|
30
|
-
# - :default - a value to return when the key doesn't exist
|
31
|
-
# if :sep is nil and the field is a multivalued field, the array is returned
|
32
|
-
def get(key, opts={:sep=>', ', :default=>nil})
|
33
|
-
if self.key? key
|
34
|
-
val = self[key]
|
35
|
-
(val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
|
36
|
-
else
|
37
|
-
opts[:default]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
# from the delsolr project -> http://github.com/avvo/delsolr/tree/master/lib/delsolr/response.rb
|
44
|
-
module Facets
|
45
|
-
|
46
|
-
class FacetValue
|
47
|
-
attr_reader :value,:hits
|
48
|
-
def initialize(value,hits)
|
49
|
-
@value,@hits=value,hits
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class Facet
|
54
|
-
attr_reader :field
|
55
|
-
attr_accessor :values
|
56
|
-
def initialize(field)
|
57
|
-
@field=field
|
58
|
-
@values=[]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# @response.facet_fields.each do |facet|
|
63
|
-
# facet.field
|
64
|
-
# end
|
65
|
-
# "caches" the result in the @facets instance var
|
66
|
-
def facets
|
67
|
-
@facets ||= (
|
68
|
-
facet_fields.inject([]) do |acc,(facet_field_name,values_and_hits_list)|
|
69
|
-
acc << facet = Facet.new(facet_field_name)
|
70
|
-
# the values_and_hits_list is an array where a value is immediately followed by it's hit count
|
71
|
-
# so we shift off an item (the value)
|
72
|
-
while value = values_and_hits_list.shift
|
73
|
-
# and then shift off the next to get the hit value
|
74
|
-
facet.values << FacetValue.new(value, values_and_hits_list.shift)
|
75
|
-
# repeat until there are no more pairs in the values_and_hits_list array
|
76
|
-
end
|
77
|
-
acc
|
78
|
-
end
|
79
|
-
)
|
80
|
-
end
|
81
|
-
|
82
|
-
# pass in a facet field name and get back a Facet instance
|
83
|
-
def facet_by_field_name(name)
|
84
|
-
facets.detect{|facet|facet.field.to_s == name.to_s}
|
85
|
-
end
|
86
|
-
|
87
|
-
def facet_counts
|
88
|
-
@facets ||= data['facet_counts'] || {}
|
89
|
-
end
|
90
|
-
|
91
|
-
# Returns the hash of all the facet_fields (ie: {'instock_b' => ['true', 123, 'false', 20]}
|
92
|
-
def facet_fields
|
93
|
-
@facet_fields ||= facet_counts['facet_fields'] || {}
|
94
|
-
end
|
95
|
-
|
96
|
-
# Returns all of the facet queries
|
97
|
-
def facet_queries
|
98
|
-
@facet_queries ||= facet_counts['facet_queries'] || {}
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
module Pagination
|
107
|
-
|
108
|
-
# alias to the Solr param, 'rows'
|
109
|
-
def per_page
|
110
|
-
@per_page ||= params['rows'].to_s.to_i
|
111
|
-
end
|
112
|
-
|
113
|
-
# Returns the current page calculated from 'rows' and 'start'
|
114
|
-
# WillPaginate hook
|
115
|
-
def current_page
|
116
|
-
@current_page ||= (self.start / self.per_page).ceil + 1
|
117
|
-
end
|
118
|
-
|
119
|
-
# Calcuates the total pages from 'numFound' and 'rows'
|
120
|
-
# WillPaginate hook
|
121
|
-
def total_pages
|
122
|
-
@total_pages ||= self.per_page > 0 ? (self.total / self.per_page.to_f).ceil : 1
|
123
|
-
end
|
124
|
-
|
125
|
-
# returns the previous page number or 1
|
126
|
-
# WillPaginate hook
|
127
|
-
def previous_page
|
128
|
-
@previous_page ||= (current_page > 1) ? current_page - 1 : 1
|
129
|
-
end
|
130
|
-
|
131
|
-
# returns the next page number or the last
|
132
|
-
# WillPaginate hook
|
133
|
-
def next_page
|
134
|
-
@next_page ||= (current_page < total_pages) ? current_page + 1 : total_pages
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
# The base query response class
|
140
|
-
# adds to the Solr::Response::Base class by defining a few more attributes,
|
141
|
-
# includes the Pagination module, and extends each of the doc hashes
|
142
|
-
# with Solr::Response::Query::DocExt
|
143
|
-
class Base < RSolr::Response::Base
|
144
|
-
|
145
|
-
include RSolr::Response::Query::Pagination
|
146
|
-
include RSolr::Response::Query::Facets
|
147
|
-
|
148
|
-
attr_reader :response, :docs, :num_found, :start
|
149
|
-
|
150
|
-
alias :total :num_found
|
151
|
-
alias :offset :start
|
152
|
-
|
153
|
-
def initialize(data)
|
154
|
-
super(data)
|
155
|
-
@response = @data[:response]
|
156
|
-
@docs = @response[:docs].collect{ |d| d=d.to_mash; d.extend(DocExt); d }
|
157
|
-
@num_found = @response[:numFound]
|
158
|
-
@start = @response[:start]
|
159
|
-
end
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
|
-
end
|
data/test/query_helper_test.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'test_helpers.rb')
|
2
|
-
|
3
|
-
class RSolrQueryHelperTest < RSolrBaseTest
|
4
|
-
|
5
|
-
H = RSolr::Query::Helper
|
6
|
-
|
7
|
-
test 'pre_value' do
|
8
|
-
value = 'the man'
|
9
|
-
assert_equal 'the man', H.prep_value(value, false)
|
10
|
-
assert_equal "\"the man\"", H.prep_value(value, :quote=>true)
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'build_query' do
|
14
|
-
assert_equal 'testing', H.build_query('testing')
|
15
|
-
assert_equal '"testing"', H.build_query('testing', :quote=>true)
|
16
|
-
assert_equal 'testing again', H.build_query(['testing', 'again'])
|
17
|
-
assert_equal '"testing" "again"', H.build_query(['testing', 'again'], :quote=>true)
|
18
|
-
assert_equal 'name:whatever', H.build_query({:name=>'whatever'})
|
19
|
-
assert_equal 'name:"whatever"', H.build_query({:name=>'whatever'}, :quote=>true)
|
20
|
-
assert_equal 'sam name:whatever i am', H.build_query(['sam', {:name=>'whatever'}, 'i', 'am'])
|
21
|
-
assert_equal 'testing AND blah', H.build_query(['testing', 'blah'], :join=>' AND ')
|
22
|
-
end
|
23
|
-
|
24
|
-
test 'start_for' do
|
25
|
-
per_page = 8
|
26
|
-
current_page = 2
|
27
|
-
assert_equal 8, H.start_for(current_page, per_page)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
data/test/response/base_test.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '..', 'test_helpers')
|
2
|
-
|
3
|
-
class ResponseBaseTest < RSolrBaseTest
|
4
|
-
|
5
|
-
def test_accessors
|
6
|
-
|
7
|
-
adapter_response = {:body=>mock_query_response}
|
8
|
-
|
9
|
-
r = RSolr::Response::Base.new(adapter_response)
|
10
|
-
|
11
|
-
assert_class Mash, r.data
|
12
|
-
assert_class Mash, r.params
|
13
|
-
assert_class Mash, r.header
|
14
|
-
|
15
|
-
# make sure the incoming adapter response is the same as the response.input
|
16
|
-
assert_equal adapter_response, r.input
|
17
|
-
|
18
|
-
assert_equal r.query_time, r.header[:QTime]
|
19
|
-
assert_equal r.query_time, r.header['QTime']
|
20
|
-
|
21
|
-
assert_equal r.params, r.header[:params]
|
22
|
-
assert_equal r.params, r.header['params']
|
23
|
-
|
24
|
-
assert_equal '*:*', r.params[:q]
|
25
|
-
assert_equal '*:*', r.params['q']
|
26
|
-
|
27
|
-
assert_equal 0, r.status
|
28
|
-
assert_equal r.status, r.header[:status]
|
29
|
-
assert_equal r.status, r.header['status']
|
30
|
-
|
31
|
-
assert_equal r.header, r.data[:responseHeader]
|
32
|
-
assert_equal r.header, r.data['responseHeader']
|
33
|
-
|
34
|
-
assert r.ok?
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|