mwmitchell-rsolr 0.8.0 → 0.8.1
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/CHANGES.txt +5 -0
- data/README.rdoc +17 -9
- data/examples/direct.rb +3 -1
- data/lib/rsolr/http_client.rb +11 -2
- data/lib/rsolr/message.rb +98 -17
- data/lib/rsolr.rb +20 -1
- data/test/connection/test_methods.rb +7 -7
- data/test/message_test.rb +25 -8
- metadata +2 -2
data/CHANGES.txt
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
0.8.1 - March 12, 2009
|
2
|
+
Added RSolr.escape and RSolr::Connection.new.escape
|
3
|
+
- tests in rsolr_test
|
4
|
+
Added ability to set doc and field attributes when adding documents via Message.add
|
5
|
+
|
1
6
|
0.8.0 - March 6, 2009
|
2
7
|
Removed all response wrapper classes (now returning a simple hash for ruby responses)
|
3
8
|
Removed RSolr::Query - this library needs an external partner lib, RSolrExt etc..
|
data/README.rdoc
CHANGED
@@ -2,10 +2,6 @@
|
|
2
2
|
|
3
3
|
A Ruby client for Apache Solr. Has transparent JRuby support by using "org.apache.solr.servlet.DirectSolrConnection" as a connection adapter.
|
4
4
|
|
5
|
-
=NOTE
|
6
|
-
Please look at the latest code/branch here: http://github.com/mwmitchell/rsolr/tree/no-response-wrap
|
7
|
-
The mapping/response helper stuff in master, will be extracted out into a separate Gem.
|
8
|
-
|
9
5
|
==Installation:
|
10
6
|
gem sources -a http://gems.github.com
|
11
7
|
sudo gem install mwmitchell-rsolr
|
@@ -53,13 +49,18 @@ Single document
|
|
53
49
|
response = solr.add(:id=>1, :price=>1.00)
|
54
50
|
|
55
51
|
Multiple documents
|
56
|
-
|
57
|
-
|
58
|
-
When adding, you can also supply "add" attributes and/or a block for digging into the Solr "add" params:
|
52
|
+
documents = [{:id=>1, :price=>1.00}, {:id=>2, :price=>10.50}]
|
53
|
+
response = solr.add(documents)
|
59
54
|
|
55
|
+
When adding, you can also supply "add" xml element attributes and/or a block for manipulating other "add" related elements:
|
56
|
+
|
60
57
|
doc = {:id=>1, :price=>1.00}
|
61
|
-
|
62
|
-
|
58
|
+
add_attributes = {:allowDups=>false, :commitWithin=>10.0}
|
59
|
+
solr.add(doc, add_attributes) do |doc|
|
60
|
+
# boost each document
|
61
|
+
doc.attrs[:boost] = 1.5
|
62
|
+
# boost the price field:
|
63
|
+
doc.field_by_name(:price).attrs[:boost] = 2.0
|
63
64
|
end
|
64
65
|
|
65
66
|
Delete by id
|
@@ -81,6 +82,13 @@ Commit & Optimize
|
|
81
82
|
== Response Formats
|
82
83
|
The default response format is Ruby. When the :wt param is set to :ruby, the response is eval'd and wrapped up in a nice Mash (Hash) class. You can get a raw response by setting the :wt to "ruby" - notice, the string -- not a symbol. All other response formats are available as expected, :wt=>'xml' etc..
|
83
84
|
|
85
|
+
===XML:
|
86
|
+
solr.select(:wt=>:xml)
|
87
|
+
===JSON:
|
88
|
+
solr.select(:wt=>:json)
|
89
|
+
===Raw Ruby
|
90
|
+
solr.select(:wt=>'ruby')
|
91
|
+
|
84
92
|
You can access the original request context (path, params, url etc.) by using a block:
|
85
93
|
solr.select(:q=>'*:*') do |solr_response, adapter_response|
|
86
94
|
adapter_response[:status_code]
|
data/examples/direct.rb
CHANGED
data/lib/rsolr/http_client.rb
CHANGED
@@ -105,9 +105,9 @@ module RSolr::HTTPClient
|
|
105
105
|
#
|
106
106
|
# converts hash into URL query string, keys get an alpha sort
|
107
107
|
# if a value is an array, the array values get mapped to the same key:
|
108
|
-
# hash_to_params(:q=>'blah', 'facet
|
108
|
+
# hash_to_params(:q=>'blah', :fq=>['blah', 'blah'], :facet=>{:field=>['location_facet', 'format_facet']})
|
109
109
|
# returns:
|
110
|
-
# ?q=blah&facet.field=location_facet&facet.field=format.facet
|
110
|
+
# ?q=blah&fq=blah&fq=blah&facet.field=location_facet&facet.field=format.facet
|
111
111
|
#
|
112
112
|
# if a value is empty/nil etc., the key is not added
|
113
113
|
def hash_to_params(params)
|
@@ -119,6 +119,15 @@ module RSolr::HTTPClient
|
|
119
119
|
v = params[k]
|
120
120
|
if v.is_a?(Array)
|
121
121
|
acc << v.reject{|i|i.to_s.empty?}.collect{|vv|build_param(k, vv)}
|
122
|
+
elsif v.is_a?(Hash)
|
123
|
+
# NOT USED
|
124
|
+
# creates dot based params like:
|
125
|
+
# hash_to_params(:facet=>{:field=>['one', 'two']}) == facet.field=one&facet.field=two
|
126
|
+
# TODO: should this go into a non-solr based param builder?
|
127
|
+
# - dotted syntax is special to solr only
|
128
|
+
#v.each_pair do |field,field_value|
|
129
|
+
# acc.push(hash_to_params({"#{k}.#{field}"=>field_value}))
|
130
|
+
#end
|
122
131
|
elsif ! v.to_s.empty?
|
123
132
|
acc.push(build_param(k, v))
|
124
133
|
end
|
data/lib/rsolr/message.rb
CHANGED
@@ -6,49 +6,128 @@ require 'builder'
|
|
6
6
|
|
7
7
|
class RSolr::Message
|
8
8
|
|
9
|
+
# A class that represents a "doc" xml element for a solr update
|
10
|
+
class Document
|
11
|
+
|
12
|
+
# "attrs" is a hash for setting the "doc" xml attributes
|
13
|
+
# "fields" is an array of Field objects
|
14
|
+
attr_accessor :attrs, :fields
|
15
|
+
|
16
|
+
# "doc_hash" must be a Hash/Mash object
|
17
|
+
# If a value in the "doc_hash" is an array,
|
18
|
+
# a field object is created for each value...
|
19
|
+
def initialize(doc_hash)
|
20
|
+
@fields = []
|
21
|
+
doc_hash.each_pair do |field,values|
|
22
|
+
# create a new field for each value (multi-valued)
|
23
|
+
# put non-array values into an array
|
24
|
+
values = [values] unless values.is_a?(Array)
|
25
|
+
values.each do |v|
|
26
|
+
next if v.to_s.empty?
|
27
|
+
@fields << Field.new({:name=>field}, v)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@attrs={}
|
31
|
+
end
|
32
|
+
|
33
|
+
# returns an array of fields that match the "name" arg
|
34
|
+
def fields_by_name(name)
|
35
|
+
@fields.select{|f|f.name==name}
|
36
|
+
end
|
37
|
+
|
38
|
+
# returns the first field that matches the "name" arg
|
39
|
+
def field_by_name(name)
|
40
|
+
@fields.detect{|f|f.name==name}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
# A class that represents a "doc"/"field" xml element for a solr update
|
46
|
+
class Field
|
47
|
+
|
48
|
+
# "attrs" is a hash for setting the "doc" xml attributes
|
49
|
+
# "value" is the text value for the node
|
50
|
+
attr_accessor :attrs, :value
|
51
|
+
|
52
|
+
# "attrs" must be a hash
|
53
|
+
# "value" should be something that responds to #_to_s
|
54
|
+
def initialize(attrs, value)
|
55
|
+
@attrs = attrs
|
56
|
+
@value = value
|
57
|
+
end
|
58
|
+
|
59
|
+
# the value of the "name" attribute
|
60
|
+
def name
|
61
|
+
@attrs[:name]
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
9
66
|
class << self
|
10
67
|
|
68
|
+
# shortcut method -> xml = RSolr::Message.xml
|
11
69
|
def xml
|
12
70
|
::Builder::XmlMarkup.new
|
13
71
|
end
|
14
72
|
|
15
|
-
# add
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
73
|
+
# generates "add" xml for updating solr
|
74
|
+
# "data" can be a hash or an array of hashes.
|
75
|
+
# - each hash should be a simple key=>value pair representing a solr doc.
|
76
|
+
# If a value is an array, multiple fields will be created.
|
77
|
+
#
|
78
|
+
# "add_attrs" can be a hash for setting the add xml element attributes.
|
79
|
+
#
|
80
|
+
# This method can also accept a block.
|
81
|
+
# The value yielded to the block is a Message::Document; for each solr doc in "data".
|
82
|
+
# You can set xml element attributes for each "doc" element or individual "field" elements.
|
83
|
+
#
|
84
|
+
# For example:
|
85
|
+
#
|
86
|
+
# solr.add({:id=>1, :nickname=>'Tim'}, {:boost=>5.0, :commitWithin=>1.0}) do |doc_msg|
|
87
|
+
# doc_msg.attrs[:boost] = 10.00 # boost the document
|
88
|
+
# nickname = doc_msg.field_by_name(:nickname)
|
89
|
+
# nickname.attrs[:boost] = 20 if nickname.value=='Tim' # boost a field
|
19
90
|
# end
|
20
|
-
|
21
|
-
|
22
|
-
|
91
|
+
#
|
92
|
+
# would result in an add element having the attributes boost="10.0"
|
93
|
+
# and a commitWithin="1.0".
|
94
|
+
# Each doc element would have a boost="10.0".
|
95
|
+
# The "nickname" field would have a boost="20.0"
|
96
|
+
# if the doc had a "nickname" field with the value of "Tim".
|
97
|
+
#
|
98
|
+
def add(data, add_attrs={}, &blk)
|
99
|
+
data = [data] if data.respond_to?(:each_pair)
|
100
|
+
xml.add(add_attrs) do |add_node|
|
23
101
|
data.each do |item|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
yield item, doc_attrs if block_given?
|
31
|
-
[item[k]].flatten.each do |v| # multiValued attributes
|
32
|
-
doc_xml.field(v, doc_attrs)
|
33
|
-
end
|
102
|
+
# create doc, passing in fields
|
103
|
+
doc = Document.new(item)
|
104
|
+
yield doc if block_given?
|
105
|
+
add_node.doc(doc.attrs) do |doc_node|
|
106
|
+
doc.fields.each do |field_obj|
|
107
|
+
doc_node.field(field_obj.value, field_obj.attrs)
|
34
108
|
end
|
35
109
|
end
|
36
110
|
end
|
37
111
|
end
|
38
112
|
end
|
39
113
|
|
114
|
+
# generates a <commit/> message
|
40
115
|
def commit(opts={})
|
41
116
|
xml.commit(opts)
|
42
117
|
end
|
43
118
|
|
119
|
+
# generates a <optimize/> message
|
44
120
|
def optimize(opts={})
|
45
121
|
xml.optimize(opts)
|
46
122
|
end
|
47
123
|
|
124
|
+
# generates a <rollback/> message
|
48
125
|
def rollback
|
49
126
|
xml.rollback
|
50
127
|
end
|
51
128
|
|
129
|
+
# generates a <delete><id>ID</id></delete> message
|
130
|
+
# "ids" can be a single value or array of values
|
52
131
|
def delete_by_id(ids)
|
53
132
|
ids = [ids] unless ids.is_a?(Array)
|
54
133
|
xml.delete do |xml|
|
@@ -58,6 +137,8 @@ class RSolr::Message
|
|
58
137
|
end
|
59
138
|
end
|
60
139
|
|
140
|
+
# generates a <delete><query>ID</query></delete> message
|
141
|
+
# "queries" can be a single value or an array of values
|
61
142
|
def delete_by_query(queries)
|
62
143
|
queries = [queries] unless queries.is_a?(Array)
|
63
144
|
xml.delete do |xml|
|
data/lib/rsolr.rb
CHANGED
@@ -7,7 +7,7 @@ proc {|base, files|
|
|
7
7
|
|
8
8
|
module RSolr
|
9
9
|
|
10
|
-
VERSION = '0.8.
|
10
|
+
VERSION = '0.8.1'
|
11
11
|
|
12
12
|
autoload :Message, 'rsolr/message'
|
13
13
|
autoload :Connection, 'rsolr/connection'
|
@@ -29,6 +29,25 @@ module RSolr
|
|
29
29
|
RSolr::Connection.new(adapter, connection_opts)
|
30
30
|
end
|
31
31
|
|
32
|
+
module Char
|
33
|
+
|
34
|
+
# escape - from the solr-ruby library
|
35
|
+
# RSolr.escape('asdf')
|
36
|
+
# backslash everything that isn't a word character
|
37
|
+
def escape(value)
|
38
|
+
value.gsub(/(\W)/, '\\\\\1')
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# send the escape method into the Connection class ->
|
44
|
+
# solr = RSolr.connect
|
45
|
+
# solr.escape('asdf')
|
46
|
+
RSolr::Connection.send(:include, Char)
|
47
|
+
|
48
|
+
# bring escape into this module (RSolr) -> RSolr.escape('asdf')
|
49
|
+
extend Char
|
50
|
+
|
32
51
|
class RequestError < RuntimeError; end
|
33
52
|
|
34
53
|
end
|
@@ -6,11 +6,11 @@
|
|
6
6
|
module ConnectionTestMethods
|
7
7
|
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
def teardown
|
10
|
+
@solr.delete_by_query('id:[* TO *]')
|
11
|
+
@solr.commit
|
12
|
+
assert_equal 0, @solr.select(:q=>'*:*')[:response][:docs].size
|
13
|
+
end
|
14
14
|
|
15
15
|
# If :wt is NOT :ruby, the format doesn't get converted into a Mash (special Hash; see lib/mash.rb)
|
16
16
|
# Raw ruby can be returned by using :wt=>'ruby', not :ruby
|
@@ -56,7 +56,7 @@ module ConnectionTestMethods
|
|
56
56
|
|
57
57
|
def test_add
|
58
58
|
assert_equal 0, @solr.select(:q=>'*:*')[:response][:numFound]
|
59
|
-
update_response = @solr.add(:id=>100)
|
59
|
+
update_response = @solr.add({:id=>100})
|
60
60
|
assert update_response.is_a?(Mash)
|
61
61
|
#
|
62
62
|
@solr.commit
|
@@ -79,7 +79,7 @@ module ConnectionTestMethods
|
|
79
79
|
@solr.add(:id=>1, :name=>'BLAH BLAH BLAH')
|
80
80
|
@solr.commit
|
81
81
|
assert_equal 1, @solr.select(:q=>'*:*')[:response][:numFound]
|
82
|
-
response = @solr.delete_by_query('name:BLAH BLAH BLAH')
|
82
|
+
response = @solr.delete_by_query('name:"BLAH BLAH BLAH"')
|
83
83
|
@solr.commit
|
84
84
|
assert response.is_a?(Mash)
|
85
85
|
assert_equal 0, @solr.select(:q=>'*:*')[:response][:numFound]
|
data/test/message_test.rb
CHANGED
@@ -14,13 +14,27 @@ class MessageTest < RSolrBaseTest
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
17
|
+
def test_add_yields_doc_objects_if_block_given
|
18
|
+
documents = [{:id=>1, :name=>'sam', :cat=>['cat 1', 'cat 2']}]
|
19
|
+
add_attrs = {:boost=>200.00}
|
20
|
+
result = RSolr::Message.add(documents, add_attrs) do |doc|
|
21
|
+
doc.field_by_name(:name).attrs[:boost] = 10
|
22
|
+
assert_equal 4, doc.fields.size
|
23
|
+
assert_equal 2, doc.fields_by_name(:cat).size
|
20
24
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
#<add boost="200.0">
|
26
|
+
#<doc>
|
27
|
+
#<field name="cat">cat 1</field>
|
28
|
+
#<field name="cat">cat 2</field>
|
29
|
+
#<field name="name" boost="10">sam</field>
|
30
|
+
#<field name="id">1</field>
|
31
|
+
#</doc>
|
32
|
+
#</add>
|
33
|
+
assert result =~ %r(name="cat">cat 1</field>)
|
34
|
+
assert result =~ %r(name="cat">cat 2</field>)
|
35
|
+
assert result =~ %r(<add boost="200.0">)
|
36
|
+
assert result =~ %r(boost="10")
|
37
|
+
assert result =~ %r(<field name="id">1</field>)
|
24
38
|
end
|
25
39
|
|
26
40
|
def test_delete_by_id
|
@@ -83,8 +97,11 @@ class MessageTest < RSolrBaseTest
|
|
83
97
|
:id => 1,
|
84
98
|
:name => ['matt1', 'matt2']
|
85
99
|
}
|
86
|
-
|
87
|
-
|
100
|
+
|
101
|
+
result = RSolr::Message.add(data)
|
102
|
+
|
103
|
+
assert result.to_s =~ /<field name="name">matt1<\/field>/
|
104
|
+
assert result.to_s =~ /<field name="name">matt2<\/field>/
|
88
105
|
end
|
89
106
|
|
90
107
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mwmitchell-rsolr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Mitchell
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-12 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|