delsolr 0.0.5 → 0.0.6
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/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.
|