delsolr 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/delsolr.rb +16 -3
- data/lib/delsolr/document.rb +16 -8
- data/lib/delsolr/query_builder.rb +30 -20
- data/lib/delsolr/response.rb +27 -4
- data/test/test_client.rb +1 -1
- data/test/test_helper.rb +1 -1
- data/test/test_query_builder.rb +1 -1
- data/test/test_response.rb +1 -1
- metadata +26 -8
data/lib/delsolr.rb
CHANGED
@@ -22,7 +22,7 @@ module DelSolr
|
|
22
22
|
|
23
23
|
class Client
|
24
24
|
|
25
|
-
attr_reader :configuration
|
25
|
+
attr_reader :configuration, :logger
|
26
26
|
|
27
27
|
#
|
28
28
|
# [<b><tt>:server</tt></b>]
|
@@ -39,9 +39,13 @@ module DelSolr
|
|
39
39
|
#
|
40
40
|
# [<b><tt>:path</tt></b>]
|
41
41
|
# (optional) the path of the solr install (defaults to "/solr")
|
42
|
+
#
|
43
|
+
# [<b><tt>:logger</tt></b>]
|
44
|
+
# (optional) Log4r logger object
|
42
45
|
def initialize(options = {})
|
43
46
|
@configuration = DelSolr::Client::Configuration.new(options[:server], options[:port], options[:timeout], options[:path])
|
44
47
|
@cache = options[:cache]
|
48
|
+
@logger = options[:logger]
|
45
49
|
@shortcuts = options[:shortcuts]
|
46
50
|
end
|
47
51
|
|
@@ -155,12 +159,19 @@ module DelSolr
|
|
155
159
|
|
156
160
|
# if we're caching, first try looking in the cache
|
157
161
|
if enable_caching
|
162
|
+
t1 = Time.now
|
158
163
|
body = @cache.get(cache_key) rescue body = nil
|
159
164
|
from_cache = true unless body.blank?
|
165
|
+
cache_time = (Time.now - t1).to_i * 1000 # retrieval time from the cache in ms
|
160
166
|
end
|
161
167
|
|
162
168
|
if body.blank? # cache miss (or wasn't enabled)
|
163
|
-
|
169
|
+
begin
|
170
|
+
header, body = connection.get(configuration.path + query_builder.request_string)
|
171
|
+
rescue Timeout::Error
|
172
|
+
# If we timed out, just return nil and let the client decide what to do
|
173
|
+
return nil
|
174
|
+
end
|
164
175
|
|
165
176
|
# We get UTF-8 from Solr back, make sure the string knows about it
|
166
177
|
# when running on Ruby >= 1.9
|
@@ -177,7 +188,9 @@ module DelSolr
|
|
177
188
|
end
|
178
189
|
end
|
179
190
|
|
180
|
-
DelSolr::Client::Response.new(body, query_builder, :from_cache => from_cache, :shortcuts => @shortcuts)
|
191
|
+
response = DelSolr::Client::Response.new(body, query_builder, :logger => logger, :from_cache => from_cache, :shortcuts => @shortcuts)
|
192
|
+
logger.info "#{from_cache ? 'C' : 'S'},#{from_cache ? cache_time : response.qtime},#{response.total},http://#{configuration.server}:#{configuration.port}#{response.request_url}" if logger && response && response.success?
|
193
|
+
response
|
181
194
|
end
|
182
195
|
|
183
196
|
# Adds a document to the buffer to be posted to solr (NOTE: does not perform the actual post)
|
data/lib/delsolr/document.rb
CHANGED
@@ -37,6 +37,10 @@ module DelSolr
|
|
37
37
|
#
|
38
38
|
class Document
|
39
39
|
|
40
|
+
def initialize(options={})
|
41
|
+
@options = options
|
42
|
+
end
|
43
|
+
|
40
44
|
# [<b><tt>field_mame</tt></b>]
|
41
45
|
# is the name of the field in your schema.xml
|
42
46
|
# [<b><tt>value</tt></b>]
|
@@ -50,7 +54,7 @@ module DelSolr
|
|
50
54
|
end
|
51
55
|
|
52
56
|
def xml
|
53
|
-
"<doc>\n" + field_buffer + "</doc>"
|
57
|
+
"<doc#{opts2str(@options)}>\n" + field_buffer + "</doc>"
|
54
58
|
end
|
55
59
|
|
56
60
|
private
|
@@ -59,14 +63,8 @@ module DelSolr
|
|
59
63
|
def construct_field_tag(name, value, options={})
|
60
64
|
options[:name] = name.to_s
|
61
65
|
use_cdata = options.delete(:cdata)
|
62
|
-
opts = []
|
63
|
-
options.each do |k,v|
|
64
|
-
opts.push "#{k}=\"#{v}\""
|
65
|
-
end
|
66
|
-
opts = opts.join(" ")
|
67
|
-
opts = " " + opts if opts
|
68
66
|
|
69
|
-
return "<field#{
|
67
|
+
return "<field#{opts2str(options)}>#{use_cdata ? cdata(value) : value}</field>\n"
|
70
68
|
end
|
71
69
|
|
72
70
|
def cdata(str)
|
@@ -77,6 +75,16 @@ module DelSolr
|
|
77
75
|
@buffer ||= ""
|
78
76
|
end
|
79
77
|
|
78
|
+
def opts2str(options)
|
79
|
+
opts = []
|
80
|
+
options.each do |k,v|
|
81
|
+
opts.push "#{k}=\"#{v}\""
|
82
|
+
end
|
83
|
+
opts = opts.join(" ")
|
84
|
+
opts = " " + opts unless opts.blank?
|
85
|
+
opts
|
86
|
+
end
|
87
|
+
|
80
88
|
end
|
81
89
|
|
82
90
|
end
|
@@ -41,12 +41,13 @@ module DelSolr
|
|
41
41
|
opts[:q] ||= opts[:query]
|
42
42
|
opts[:rows] ||= opts[:limit] || 10
|
43
43
|
opts[:start] ||= opts[:offset] || 0
|
44
|
+
opts[:start] = 0 if opts[:start].to_i < 0
|
44
45
|
opts[:fl] ||= opts[:fields] || FL_DEFAULTS
|
45
46
|
opts[:bq] ||= opts[:boost]
|
46
47
|
opts[:suggestionCount] ||= opts[:suggestion_count]
|
47
48
|
opts[:onlyMorePopular] ||= opts[:only_more_popular]
|
48
49
|
|
49
|
-
raise ":query or :q must be set" if opts[:q].
|
50
|
+
raise ":query or :q must be set" if opts[:q].nil? || opts[:q].empty?
|
50
51
|
|
51
52
|
# clear out the "rubyish" versions, what's left will go straight to solr
|
52
53
|
opts.delete(:query)
|
@@ -123,21 +124,36 @@ module DelSolr
|
|
123
124
|
when Hash
|
124
125
|
query_string_array = []
|
125
126
|
queries.each do |k,v|
|
126
|
-
|
127
|
-
v.each do |val|
|
128
|
-
query_string_array << "#{k}:#{val}"
|
129
|
-
end
|
130
|
-
elsif v.is_a?(Range)
|
131
|
-
query_string_array << "#{k}:[#{v.begin} TO #{v.end}]"
|
132
|
-
else
|
133
|
-
query_string_array << "#{k}:#{v}"
|
134
|
-
end
|
127
|
+
query_string_array << key_value_pair_string(k, v)
|
135
128
|
end
|
136
129
|
query_string = query_string_array.join(' ')
|
137
130
|
end
|
138
131
|
|
139
132
|
{key => query_string}
|
140
133
|
end
|
134
|
+
|
135
|
+
def key_value_pair_string(k, v)
|
136
|
+
str = ''
|
137
|
+
if v.is_a?(Array) # add a filter for each value
|
138
|
+
str_ary = []
|
139
|
+
v.each do |val|
|
140
|
+
str_ary << key_value_pair_string(k, val)
|
141
|
+
end
|
142
|
+
str = str_ary.join(' ')
|
143
|
+
elsif v.is_a?(Range)
|
144
|
+
str = "#{k}:[#{v.begin} TO #{v.end}]"
|
145
|
+
elsif v.is_a?(String)
|
146
|
+
if v =~ /\s/ && # if it contains a space, we may need to quote it
|
147
|
+
!(v =~ /^\[.+ TO .+\]$/) # HACK: if the string is a range query, do not wrap it in quotes
|
148
|
+
str = "#{k}:\"#{v}\""
|
149
|
+
else
|
150
|
+
str = "#{k}:#{v}"
|
151
|
+
end
|
152
|
+
else
|
153
|
+
str = "#{k}:#{v}"
|
154
|
+
end
|
155
|
+
str
|
156
|
+
end
|
141
157
|
|
142
158
|
def build_filters(key, filters)
|
143
159
|
params = []
|
@@ -147,18 +163,12 @@ module DelSolr
|
|
147
163
|
when String
|
148
164
|
params << {key => filters}
|
149
165
|
when Array
|
150
|
-
filters.each
|
166
|
+
filters.each do |f|
|
167
|
+
params += build_filters(key, f) # recusively add all the filters in the array
|
168
|
+
end
|
151
169
|
when Hash
|
152
170
|
filters.each do |k,v|
|
153
|
-
|
154
|
-
v.each do |val|
|
155
|
-
params << {key => "#{k}:#{val}"}
|
156
|
-
end
|
157
|
-
elsif v.is_a?(Range)
|
158
|
-
params << {key => "#{k}:[#{v.begin} TO #{v.end}]"}
|
159
|
-
else
|
160
|
-
params << {key => "#{k}:#{v}"}
|
161
|
-
end
|
171
|
+
params << {key => key_value_pair_string(k, v)} unless v.nil?
|
162
172
|
end
|
163
173
|
end
|
164
174
|
params
|
data/lib/delsolr/response.rb
CHANGED
@@ -9,9 +9,12 @@ module DelSolr
|
|
9
9
|
def initialize(solr_response_buffer, query_builder, options = {})
|
10
10
|
@query_builder = query_builder
|
11
11
|
@from_cache = options[:from_cache]
|
12
|
+
@logger = options[:logger]
|
12
13
|
begin
|
13
14
|
@raw_response = eval(solr_response_buffer)
|
14
|
-
rescue
|
15
|
+
rescue SyntaxError, Exception => e
|
16
|
+
@logger.error(solr_response_buffer) if @logger
|
17
|
+
@logger.error(e) if @logger
|
15
18
|
@raw_response = nil
|
16
19
|
end
|
17
20
|
|
@@ -30,6 +33,11 @@ module DelSolr
|
|
30
33
|
def raw_response
|
31
34
|
@raw_response
|
32
35
|
end
|
36
|
+
|
37
|
+
# Did we get some kind of valid response back from solr?
|
38
|
+
def success?
|
39
|
+
!raw_response.nil?
|
40
|
+
end
|
33
41
|
|
34
42
|
# Returns the total number of matches
|
35
43
|
def total
|
@@ -38,7 +46,7 @@ module DelSolr
|
|
38
46
|
|
39
47
|
# Returns true if there no results
|
40
48
|
def blank?
|
41
|
-
|
49
|
+
raw_response.blank? || total < 1
|
42
50
|
end
|
43
51
|
|
44
52
|
alias_method :empty?, :blank?
|
@@ -74,6 +82,21 @@ module DelSolr
|
|
74
82
|
raw_response['highlighting'][unique_id] ||= {}
|
75
83
|
raw_response['highlighting'][unique_id][field]
|
76
84
|
end
|
85
|
+
|
86
|
+
def suggestions
|
87
|
+
@suggestions ||= raw_response['spellcheck']['suggestions'] if raw_response && raw_response['spellcheck']
|
88
|
+
end
|
89
|
+
|
90
|
+
# solr is super-weird about the way it returns suggestions,
|
91
|
+
# hence this strangeness:
|
92
|
+
# 'spellcheck'=>{'suggestions'=>['fishh',{'numFound'=>1,'startOffset'=>0,'endOffset'=>4,'suggestion'=>['fish']},'collation','fish']}
|
93
|
+
def collation
|
94
|
+
@collation ||= begin
|
95
|
+
collation = nil
|
96
|
+
suggestions.in_groups_of(2) {|k,v| collation = v if k == 'collation'} if suggestions
|
97
|
+
collation
|
98
|
+
end
|
99
|
+
end
|
77
100
|
|
78
101
|
# Returns the query time in ms
|
79
102
|
def qtime
|
@@ -125,7 +148,7 @@ module DelSolr
|
|
125
148
|
|
126
149
|
# Returns an array of value/counts for a given field (ie: ['true', 123, 'false', 20]
|
127
150
|
def facet_field(field)
|
128
|
-
facet_fields[field.to_s]
|
151
|
+
facet_fields[field.to_s] || []
|
129
152
|
end
|
130
153
|
|
131
154
|
# Returns the array of field values for the given field in the order they were returned from solr
|
@@ -142,7 +165,7 @@ module DelSolr
|
|
142
165
|
|
143
166
|
# Returns a hash of value/counts for a given field (ie: {'true' => 123, 'false' => 20}
|
144
167
|
def facet_field_by_hash(field)
|
145
|
-
facet_fields_by_hash
|
168
|
+
facet_fields_by_hash[field.to_s]
|
146
169
|
end
|
147
170
|
|
148
171
|
# Returns the count for the given field/value pair
|
data/test/test_client.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
require File.dirname(__FILE__) + '/../lib/delsolr'
|
2
|
+
require File.expand_path(File.dirname(__FILE__)) + '/../lib/delsolr'
|
data/test/test_query_builder.rb
CHANGED
data/test/test_response.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delsolr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 6
|
9
|
+
version: 0.0.6
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Ben VandenBos
|
@@ -14,14 +19,19 @@ default_executable:
|
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: mocha
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
20
25
|
requirements:
|
21
26
|
- - ">="
|
22
27
|
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 9
|
31
|
+
- 0
|
23
32
|
version: 0.9.0
|
24
|
-
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
25
35
|
description: Ruby wrapper for Lucene Solr
|
26
36
|
email:
|
27
37
|
executables: []
|
@@ -39,6 +49,10 @@ files:
|
|
39
49
|
- lib/delsolr/query_builder.rb
|
40
50
|
- lib/delsolr/response.rb
|
41
51
|
- lib/delsolr/document.rb
|
52
|
+
- test/test_client.rb
|
53
|
+
- test/test_helper.rb
|
54
|
+
- test/test_query_builder.rb
|
55
|
+
- test/test_response.rb
|
42
56
|
has_rdoc: true
|
43
57
|
homepage: http://github.com/avvo/delsolr
|
44
58
|
licenses: []
|
@@ -49,21 +63,25 @@ rdoc_options: []
|
|
49
63
|
require_paths:
|
50
64
|
- lib
|
51
65
|
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
52
67
|
requirements:
|
53
68
|
- - ">="
|
54
69
|
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
55
72
|
version: "0"
|
56
|
-
version:
|
57
73
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
58
75
|
requirements:
|
59
76
|
- - ">="
|
60
77
|
- !ruby/object:Gem::Version
|
78
|
+
segments:
|
79
|
+
- 0
|
61
80
|
version: "0"
|
62
|
-
version:
|
63
81
|
requirements: []
|
64
82
|
|
65
83
|
rubyforge_project:
|
66
|
-
rubygems_version: 1.3.
|
84
|
+
rubygems_version: 1.3.7
|
67
85
|
signing_key:
|
68
86
|
specification_version: 3
|
69
87
|
summary: DelSolr is a light weight ruby wrapper for solr. It's intention is to expose the full power of solr queries while keeping the interface as ruby-esque as possible.
|