delsolr 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +7 -4
- data/lib/delsolr/query_builder.rb +60 -42
- data/lib/delsolr/response.rb +3 -3
- data/lib/delsolr.rb +2 -2
- data/test/test_query_builder.rb +37 -20
- data/test/test_response.rb +4 -4
- metadata +2 -2
data/README.txt
CHANGED
@@ -30,10 +30,10 @@ Example:
|
|
30
30
|
|
31
31
|
c = DelSolr::Client.new(:server => 'solr1', :port => 8983)
|
32
32
|
rsp = c.query('dismax', :query => 'mp3 player',
|
33
|
-
:filters => {:cost => (50..100)},
|
33
|
+
:filters => {:cost => (50..100), :localparams => {:tag => 'cost_filter'}},
|
34
34
|
:facets => [{:field => 'brand', :limit => 10},
|
35
35
|
{:query => {:onsale => true, :brand => 'Apple'},
|
36
|
-
:
|
36
|
+
:localparams => {:key => 'cheap_apple', :ex => 'cost_filter'}}])
|
37
37
|
|
38
38
|
# output total matches
|
39
39
|
puts rsp.total
|
@@ -47,7 +47,7 @@ Example:
|
|
47
47
|
end
|
48
48
|
|
49
49
|
# output a query facet
|
50
|
-
puts "Cheap Apple stuff: #{rsp.
|
50
|
+
puts "Cheap Apple stuff: #{rsp.facet_query_count_by_key('cheap_apple')}"
|
51
51
|
|
52
52
|
# adding things
|
53
53
|
doc = DelSolr::Document.new
|
@@ -60,10 +60,13 @@ Example:
|
|
60
60
|
rsp = c.query('dismax', :query => 'shuffle mp3 player')
|
61
61
|
puts rsp.ids[0]
|
62
62
|
|
63
|
+
# using local params for filters / facets
|
64
|
+
Use :localparams => {} syntax to add local params to filters and facets
|
65
|
+
|
63
66
|
|
64
67
|
== REQUIREMENTS:
|
65
68
|
|
66
|
-
You need Solr installed somewhere so you can query it ;)
|
69
|
+
You need Solr(1.4 or higher) installed somewhere so you can query it ;)
|
67
70
|
|
68
71
|
== INSTALL:
|
69
72
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'cgi'
|
2
2
|
|
3
3
|
module DelSolr
|
4
|
-
|
4
|
+
|
5
5
|
class Client
|
6
|
-
|
6
|
+
|
7
7
|
class QueryBuilder
|
8
|
-
|
8
|
+
|
9
9
|
FL_DEFAULTS = 'id,unique_id,score' # redefine if you really want to change this.
|
10
|
-
|
10
|
+
|
11
11
|
attr_accessor :query_name, :options
|
12
12
|
|
13
13
|
# ops can basically be straight solr URL params, but it also supports some other formats
|
@@ -21,22 +21,17 @@ module DelSolr
|
|
21
21
|
def request_string
|
22
22
|
@request_string ||= build_request_string
|
23
23
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
name_to_facet_query[query_name]
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
24
|
+
|
25
|
+
private
|
26
|
+
|
32
27
|
def build_request_string()
|
33
28
|
raise "query_name must be set" if query_name.blank?
|
34
|
-
|
29
|
+
|
35
30
|
opts = self.options.dup
|
36
|
-
|
31
|
+
|
37
32
|
# cleanup the nils
|
38
33
|
opts.delete_if {|k,v| v.nil?}
|
39
|
-
|
34
|
+
|
40
35
|
# resolve "rubyish" names to solr names
|
41
36
|
opts[:q] ||= opts[:query]
|
42
37
|
opts[:rows] ||= opts[:limit] || 10
|
@@ -46,9 +41,9 @@ module DelSolr
|
|
46
41
|
opts[:bq] ||= opts[:boost]
|
47
42
|
opts[:suggestionCount] ||= opts[:suggestion_count]
|
48
43
|
opts[:onlyMorePopular] ||= opts[:only_more_popular]
|
49
|
-
|
44
|
+
|
50
45
|
raise ":query or :q must be set" if opts[:q].nil? || opts[:q].empty?
|
51
|
-
|
46
|
+
|
52
47
|
# clear out the "rubyish" versions, what's left will go straight to solr
|
53
48
|
opts.delete(:query)
|
54
49
|
opts.delete(:limit)
|
@@ -57,7 +52,7 @@ module DelSolr
|
|
57
52
|
opts.delete(:boost)
|
58
53
|
opts.delete(:suggestion_count)
|
59
54
|
opts.delete(:only_more_popular)
|
60
|
-
|
55
|
+
|
61
56
|
# needs to be an array of hashs because it's acceptable to have the same key present > once.
|
62
57
|
params = []
|
63
58
|
|
@@ -88,7 +83,7 @@ module DelSolr
|
|
88
83
|
raise 'facets must either be a Hash or an Array'
|
89
84
|
end
|
90
85
|
end
|
91
|
-
|
86
|
+
|
92
87
|
# handle friendly highlight name
|
93
88
|
if opts.delete(:highlight)
|
94
89
|
params << {:hl => 'true'}
|
@@ -109,12 +104,12 @@ module DelSolr
|
|
109
104
|
raise "All params should be a Hash or String"
|
110
105
|
end
|
111
106
|
end
|
112
|
-
|
107
|
+
|
113
108
|
"/select?#{param_strings.join('&')}"
|
114
109
|
end
|
115
|
-
|
110
|
+
|
116
111
|
# returns the query param
|
117
|
-
def build_query(key, queries)
|
112
|
+
def build_query(key, queries, localparams = "")
|
118
113
|
query_string = ''
|
119
114
|
case queries
|
120
115
|
when String
|
@@ -128,7 +123,9 @@ module DelSolr
|
|
128
123
|
end
|
129
124
|
query_string = query_string_array.join(' ')
|
130
125
|
end
|
131
|
-
|
126
|
+
|
127
|
+
query_string = localparams + query_string
|
128
|
+
|
132
129
|
{key => query_string}
|
133
130
|
end
|
134
131
|
|
@@ -144,7 +141,7 @@ module DelSolr
|
|
144
141
|
str = "#{k}:[#{v.begin} TO #{v.end}]"
|
145
142
|
elsif v.is_a?(String)
|
146
143
|
if v =~ /\s/ && # if it contains a space, we may need to quote it
|
147
|
-
|
144
|
+
!(v =~ /^\[.+ TO .+\]$/) # HACK: if the string is a range query, do not wrap it in quotes
|
148
145
|
str = "#{k}:\"#{v}\""
|
149
146
|
else
|
150
147
|
str = "#{k}:#{v}"
|
@@ -154,10 +151,10 @@ module DelSolr
|
|
154
151
|
end
|
155
152
|
str
|
156
153
|
end
|
157
|
-
|
154
|
+
|
158
155
|
def build_filters(key, filters)
|
159
156
|
params = []
|
160
|
-
|
157
|
+
|
161
158
|
# handle "ruby-ish" filters
|
162
159
|
case filters
|
163
160
|
when String
|
@@ -167,13 +164,15 @@ module DelSolr
|
|
167
164
|
params += build_filters(key, f) # recusively add all the filters in the array
|
168
165
|
end
|
169
166
|
when Hash
|
167
|
+
filters_local_params = build_local_params(filters['localparams'] || filters[:localparams])
|
170
168
|
filters.each do |k,v|
|
171
|
-
|
169
|
+
next if ['localparams', :localparams].include?(k.to_s)
|
170
|
+
params << {key => filters_local_params + key_value_pair_string(k, v)} unless v.nil?
|
172
171
|
end
|
173
172
|
end
|
174
173
|
params
|
175
174
|
end
|
176
|
-
|
175
|
+
|
177
176
|
def build_facets(facet_array)
|
178
177
|
params = []
|
179
178
|
facet_array.each do |facet_hash|
|
@@ -181,34 +180,53 @@ module DelSolr
|
|
181
180
|
end
|
182
181
|
params
|
183
182
|
end
|
184
|
-
|
183
|
+
|
185
184
|
def build_facet(facet_hash)
|
186
185
|
params = []
|
187
186
|
facet_name = facet_hash['name'] || facet_hash[:name]
|
187
|
+
unless facet_name.blank?
|
188
|
+
facet_hash[:localparams] ||= {}
|
189
|
+
facet_hash[:localparams][:key] ||= facet_name
|
190
|
+
end
|
191
|
+
facet_local_params = build_local_params(facet_hash['localparams'] || facet_hash[:localparams])
|
188
192
|
facet_hash.each do |k,v|
|
189
193
|
# handle some cases specially
|
190
194
|
if 'field' == k.to_s
|
191
|
-
params << {"facet.field" => v}
|
195
|
+
params << {"facet.field" => "#{facet_local_params}#{v}"}
|
192
196
|
elsif 'query' == k.to_s
|
193
|
-
|
194
|
-
|
195
|
-
if facet_name
|
196
|
-
# keep track of names => facet_queries
|
197
|
-
name_to_facet_query[facet_name] = q['facet.query']
|
198
|
-
end
|
199
|
-
elsif ['name', :name].include?(k.to_s)
|
197
|
+
params << build_query("facet.query", v, facet_local_params)
|
198
|
+
elsif ['localparams', :localparams, 'name', :name].include?(k.to_s)
|
200
199
|
# do nothing
|
201
200
|
else
|
202
|
-
params << {"f.#{facet_hash[:field]}.facet.#{k}" => v}
|
201
|
+
params << {"f.#{facet_hash[:field]}.facet.#{k}" => "#{facet_local_params}#{v}"}
|
203
202
|
end
|
204
203
|
end
|
205
204
|
params
|
206
205
|
end
|
207
|
-
|
208
|
-
def
|
209
|
-
|
206
|
+
|
207
|
+
def build_local_params_array(local_params)
|
208
|
+
local_params_array = []
|
209
|
+
case local_params
|
210
|
+
when String
|
211
|
+
local_params_array << local_params
|
212
|
+
when Array
|
213
|
+
local_params.each do |p|
|
214
|
+
local_params_array << build_local_params_array(p)
|
215
|
+
end
|
216
|
+
when Hash
|
217
|
+
local_params.each do |k,v|
|
218
|
+
local_params_array << "#{k}=#{v}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
local_params_array
|
210
222
|
end
|
211
|
-
|
223
|
+
|
224
|
+
def build_local_params(local_params)
|
225
|
+
local_params_array = build_local_params_array(local_params)
|
226
|
+
|
227
|
+
local_params_array.empty? ? "" : "{!#{local_params_array.join(" ")}}"
|
228
|
+
end
|
229
|
+
|
212
230
|
end
|
213
231
|
end
|
214
232
|
end
|
data/lib/delsolr/response.rb
CHANGED
@@ -174,10 +174,10 @@ module DelSolr
|
|
174
174
|
end
|
175
175
|
|
176
176
|
# Returns the counts for a given facet_query_name
|
177
|
-
def
|
178
|
-
|
179
|
-
facet_queries[query_string] if query_string
|
177
|
+
def facet_query_count_by_key(facet_query_key)
|
178
|
+
facet_queries[facet_query_key.to_s]
|
180
179
|
end
|
180
|
+
alias :facet_query_count_by_name :facet_query_count_by_key
|
181
181
|
|
182
182
|
# Returns the url sent to solr
|
183
183
|
def request_url
|
data/lib/delsolr.rb
CHANGED
@@ -100,7 +100,7 @@ module DelSolr
|
|
100
100
|
#
|
101
101
|
# c.query('standard', :query => 'abc',
|
102
102
|
# :facets => [:query => {:city => 'seattle', :instock => true},
|
103
|
-
# :
|
103
|
+
# :prefix => {:key => 'seattle_instock'}}])
|
104
104
|
#
|
105
105
|
# ...will request counts for the number of documents where "seattle" matches on the "city" field and "instock" is set to true.
|
106
106
|
# Faceting by query requires you to assign a name to the facet so the counts can easily be fetched from the response. Solr
|
@@ -109,7 +109,7 @@ module DelSolr
|
|
109
109
|
#
|
110
110
|
# The count for this facet query can be pulled like so:
|
111
111
|
#
|
112
|
-
# rsp.
|
112
|
+
# rsp.facet_query_count_by_key('seattle_instock').
|
113
113
|
#
|
114
114
|
# [<b><tt>:sorts</tt></b>]
|
115
115
|
# (optional) array or string of sorts in Lucene syntax (<fieldname> <asc/desc>)
|
data/test/test_query_builder.rb
CHANGED
@@ -18,10 +18,10 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
18
18
|
assert(qb)
|
19
19
|
|
20
20
|
p = get_params(qb.request_string)
|
21
|
-
assert_equal(p['start']
|
22
|
-
assert_equal(p['rows']
|
23
|
-
assert_equal(p['fl']
|
24
|
-
assert_equal(p['q']
|
21
|
+
assert_equal('3', p['start'])
|
22
|
+
assert_equal('13', p['rows'])
|
23
|
+
assert_equal('id', p['fl'])
|
24
|
+
assert_equal('good book', p['q'])
|
25
25
|
end
|
26
26
|
|
27
27
|
def test_002
|
@@ -36,8 +36,8 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
36
36
|
assert(qb)
|
37
37
|
|
38
38
|
p = get_params(qb.request_string)
|
39
|
-
assert_equal(
|
40
|
-
assert_equal(p['q']
|
39
|
+
assert_equal('id,unique_id,score', p['fl'])
|
40
|
+
assert_equal('blahblah', p['q'])
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_003
|
@@ -52,8 +52,8 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
52
52
|
assert(qb)
|
53
53
|
|
54
54
|
p = get_params(qb.request_string)
|
55
|
-
assert_equal(
|
56
|
-
assert_equal(p['q']
|
55
|
+
assert_equal('id,unique_id,score', p['fl'])
|
56
|
+
assert_equal('index_type:books', p['q'])
|
57
57
|
end
|
58
58
|
|
59
59
|
def test_004
|
@@ -68,8 +68,8 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
68
68
|
assert(qb)
|
69
69
|
|
70
70
|
p = get_params(qb.request_string)
|
71
|
-
assert_equal(p['fq']
|
72
|
-
assert_equal(p['q']
|
71
|
+
assert_equal('location:seattle', p['fq'])
|
72
|
+
assert_equal('index_type:books', p['q'])
|
73
73
|
end
|
74
74
|
|
75
75
|
def test_005
|
@@ -85,8 +85,8 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
85
85
|
|
86
86
|
p = get_params(qb.request_string)
|
87
87
|
|
88
|
-
assert_equal(p['fq']
|
89
|
-
assert_equal(p['q']
|
88
|
+
assert_equal('location:seattle', p['fq'])
|
89
|
+
assert_equal('index_type:books', p['q'])
|
90
90
|
end
|
91
91
|
|
92
92
|
def test_facets_001
|
@@ -101,9 +101,9 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
101
101
|
|
102
102
|
p = get_params(qb.request_string)
|
103
103
|
|
104
|
-
assert_equal(p['facet']
|
105
|
-
assert_equal(
|
106
|
-
assert_equal(p['f.on_sale_b.facet.limit']
|
104
|
+
assert_equal('true', p['facet'])
|
105
|
+
assert_equal(['instock_b', 'on_sale_b'].sort, p['facet.field'].sort)
|
106
|
+
assert_equal('1', p['f.on_sale_b.facet.limit'])
|
107
107
|
end
|
108
108
|
|
109
109
|
def test_facets_002
|
@@ -118,11 +118,28 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
118
118
|
|
119
119
|
p = get_params(qb.request_string)
|
120
120
|
|
121
|
-
assert_equal(p['facet']
|
122
|
-
assert_equal(p['facet.field']
|
123
|
-
assert_equal(p['facet.query']
|
121
|
+
assert_equal('true', p['facet'])
|
122
|
+
assert_equal('language_idm', p['facet.field'])
|
123
|
+
assert_equal('{!key=seattle}city_idm:19596', p['facet.query'])
|
124
124
|
end
|
125
|
-
|
125
|
+
|
126
|
+
def test_facets_003
|
127
|
+
qb = nil
|
128
|
+
opts = {}
|
129
|
+
opts[:query] = "games"
|
130
|
+
opts[:facets] = [{:query => {:city_idm => 19596}, :localparams => {:key => 'seattle', :ex => 'exclusion'}}, {:field => 'language_idm'}]
|
131
|
+
|
132
|
+
assert_nothing_raised { qb = DelSolr::Client::QueryBuilder.new('onebox-books', opts) }
|
133
|
+
|
134
|
+
assert(qb)
|
135
|
+
|
136
|
+
p = get_params(qb.request_string)
|
137
|
+
|
138
|
+
assert_equal('true', p['facet'])
|
139
|
+
assert_equal('language_idm', p['facet.field'])
|
140
|
+
assert_equal('{!key=seattle ex=exclusion}city_idm:19596', p['facet.query'])
|
141
|
+
end
|
142
|
+
|
126
143
|
def test_range
|
127
144
|
qb = nil
|
128
145
|
opts = {}
|
@@ -135,7 +152,7 @@ class QueryBuilderTest < Test::Unit::TestCase
|
|
135
152
|
|
136
153
|
p = get_params(qb.request_string)
|
137
154
|
|
138
|
-
assert_equal('id:[1 TO 3]'
|
155
|
+
assert_equal(p['fq'], 'id:[1 TO 3]')
|
139
156
|
end
|
140
157
|
|
141
158
|
|
data/test/test_response.rb
CHANGED
@@ -75,7 +75,7 @@ class ResponseTest < Test::Unit::TestCase
|
|
75
75
|
},
|
76
76
|
'facet_counts'=>{
|
77
77
|
'facet_queries'=>{
|
78
|
-
'
|
78
|
+
'19596' => 392},
|
79
79
|
'facet_fields'=>{
|
80
80
|
'available_b'=>[
|
81
81
|
'false',1328],
|
@@ -97,7 +97,7 @@ class ResponseTest < Test::Unit::TestCase
|
|
97
97
|
|
98
98
|
def test_001
|
99
99
|
r = nil
|
100
|
-
qb = DelSolr::Client::QueryBuilder.new('standard', :query => {:index_type => 'widget'}, :facets => {:query => 'city_idm:19596', :
|
100
|
+
qb = DelSolr::Client::QueryBuilder.new('standard', :query => {:index_type => 'widget'}, :facets => {:query => 'city_idm:19596', :prefix => {:key => 19596}} )
|
101
101
|
qb.request_string # need to generate this...
|
102
102
|
assert_nothing_raised { r = DelSolr::Client::Response.new(@@test_001, qb) }
|
103
103
|
|
@@ -114,12 +114,12 @@ class ResponseTest < Test::Unit::TestCase
|
|
114
114
|
assert_equal(1182, r.facet_field_count('onsale_b', false))
|
115
115
|
assert_equal(174, r.facet_field_count('onsale_b', true))
|
116
116
|
assert_equal(1328, r.facet_field_count('available_b', false))
|
117
|
-
assert_equal(392, r.
|
117
|
+
assert_equal(392, r.facet_query_count_by_key(19596))
|
118
118
|
end
|
119
119
|
|
120
120
|
def test_shortcuts
|
121
121
|
r = nil
|
122
|
-
qb = DelSolr::Client::QueryBuilder.new('standard', :query => {:index_type => 'widget'}, :facets => {:query => 'city_idm:19596', :
|
122
|
+
qb = DelSolr::Client::QueryBuilder.new('standard', :query => {:index_type => 'widget'}, :facets => {:query => 'city_idm:19596', :prefix => {:key => 19596}} )
|
123
123
|
qb.request_string # need to generate this...
|
124
124
|
assert_nothing_raised { r = DelSolr::Client::Response.new(@@test_001, qb, :shortcuts => [:index_type, :id]) }
|
125
125
|
|