rsolr 0.12.0 → 1.0.3
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/README.rdoc +147 -51
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/lib/rsolr/char.rb +21 -0
- data/lib/rsolr/client.rb +216 -70
- data/lib/rsolr/connection.rb +78 -9
- data/lib/rsolr/error.rb +117 -0
- data/lib/rsolr/response.rb +51 -0
- data/lib/rsolr/uri.rb +58 -0
- data/lib/rsolr/xml.rb +165 -0
- data/lib/rsolr-direct.rb +111 -0
- data/lib/rsolr.rb +11 -27
- data/spec/api/char_spec.rb +18 -0
- data/spec/api/client_spec.rb +216 -0
- data/spec/api/connection_spec.rb +15 -0
- data/spec/api/error_spec.rb +56 -0
- data/spec/api/pagination_spec.rb +30 -0
- data/spec/api/rsolr_spec.rb +19 -0
- data/spec/api/uri_spec.rb +70 -0
- data/spec/api/xml_spec.rb +121 -0
- data/spec/spec_helper.rb +1 -0
- data/tasks/rdoc.rake +11 -0
- data/tasks/spec.rake +39 -0
- metadata +144 -25
- data/CHANGES.txt +0 -282
- data/lib/rsolr/connection/net_http.rb +0 -48
- data/lib/rsolr/connection/requestable.rb +0 -43
- data/lib/rsolr/connection/utils.rb +0 -73
- data/lib/rsolr/message/document.rb +0 -48
- data/lib/rsolr/message/field.rb +0 -20
- data/lib/rsolr/message/generator.rb +0 -89
- data/lib/rsolr/message.rb +0 -8
- data/rsolr.gemspec +0 -32
data/README.rdoc
CHANGED
@@ -1,63 +1,102 @@
|
|
1
1
|
=RSolr
|
2
2
|
|
3
|
-
A Ruby client for Apache Solr.
|
3
|
+
A simple, extensible Ruby client for Apache Solr.
|
4
|
+
|
5
|
+
Notice: This document is only for the the 1.0 in the master. The last pre 1.0 gem release documentation can be found here: http://github.com/mwmitchell/rsolr/tree/v0.12.1
|
6
|
+
|
7
|
+
==Documentation
|
8
|
+
The code docs for the last *release* can be viewed here : http://rdoc.info/projects/mwmitchell/rsolr
|
4
9
|
|
5
10
|
== Installation:
|
6
|
-
gem sources -a http://gemcutter.org
|
7
11
|
sudo gem install rsolr
|
8
12
|
|
9
|
-
==
|
10
|
-
* {Solr}[http://lucene.apache.org/solr/]
|
11
|
-
* {RSolr Google Group}[http://groups.google.com/group/rsolr]
|
12
|
-
* {RSolr::Ext}[http://github.com/mwmitchell/rsolr-ext] -- an extension kit for RSolr
|
13
|
-
* {Sunspot}[http://github.com/outoftime/sunspot] -- an awesome Solr DSL, built with RSolr
|
14
|
-
* {Blacklight}[http://blacklightopac.org] -- a next generation Library OPAC, built with RSolr
|
15
|
-
* {solr-ruby}[http://wiki.apache.org/solr/solr-ruby] -- the original Solr Ruby Gem
|
16
|
-
* {java_bin}[http://github.com/kennyj/java_bin] -- Provides javabin/binary parsing for Ruby
|
17
|
-
|
18
|
-
== Simple usage:
|
13
|
+
== Example:
|
19
14
|
require 'rubygems'
|
20
15
|
require 'rsolr'
|
21
|
-
solr = RSolr.connect :url=>'http://solrserver.com'
|
22
16
|
|
23
|
-
#
|
24
|
-
|
17
|
+
# Direct connection
|
18
|
+
solr = RSolr.connect :url => 'http://solrserver.com'
|
25
19
|
|
26
|
-
#
|
27
|
-
|
20
|
+
# Connecting over a proxy server
|
21
|
+
solr = RSolr.connect :url => 'http://solrserver.com', :proxy=>'http://user:pass@proxy.example.com:8080'
|
28
22
|
|
29
|
-
#
|
30
|
-
response =
|
23
|
+
# send a request to /select
|
24
|
+
response = solr.get 'select', :params => {:q => '*:*'}
|
25
|
+
|
26
|
+
# send a request to /catalog
|
27
|
+
response = solr.get 'catalog', :params => {:q => '*:*'}
|
28
|
+
|
29
|
+
When the Solr :wt is :ruby, then the response will be a Hash. This Hash is the same object returned by Solr, but evaluated as Ruby. If the :wt is not :ruby, then the response will be a String.
|
30
|
+
|
31
|
+
The response also exposes 2 attribute readers (for any :wt value), :request and :response. Both are Hash objects with symbolized keys.
|
32
|
+
|
33
|
+
The :request attribute contains the original request context. You can use this for debugging or logging. Some of the keys this object contains are :uri, :query, :method etc..
|
34
|
+
|
35
|
+
The :response attribute contains the original response. This object contains the :status, :body and :headers keys.
|
31
36
|
|
32
37
|
== Querying
|
33
|
-
Use the #
|
34
|
-
response = solr.select
|
38
|
+
Use the #get / #post method to send search requests to the /select handler:
|
39
|
+
response = solr.get 'select', :params => {
|
35
40
|
:q=>'washington',
|
36
41
|
:start=>0,
|
37
42
|
:rows=>10
|
38
|
-
}
|
43
|
+
}
|
44
|
+
response["response"]["docs"].each{|doc| puts doc["id"] }
|
39
45
|
|
40
|
-
The params sent into the method are sent to Solr as-is
|
46
|
+
The :params sent into the method are sent to Solr as-is, which is to say they are converted to Solr url style, but no special mapping is used.
|
47
|
+
When an array is used, multiple parameters *with the same name* are generated for the Solr query. Example:
|
41
48
|
|
42
|
-
solr.select :q=>'roses', :fq=>['red', 'violet']
|
49
|
+
solr.get 'select', :params => {:q=>'roses', :fq=>['red', 'violet']}
|
43
50
|
|
44
51
|
The above statement generates this Solr query:
|
45
52
|
|
46
|
-
?q=roses&fq=red&fq=violet
|
53
|
+
select?q=roses&fq=red&fq=violet
|
47
54
|
|
48
|
-
|
49
|
-
|
55
|
+
===Pagination
|
56
|
+
To paginate through a set of Solr documents, use the paginate method:
|
57
|
+
solr.paginate 1, 10, "select", :params => {:q => "test"}
|
50
58
|
|
51
|
-
|
52
|
-
response = solr.documents :q=>'test'
|
59
|
+
The first argument is the current page, the second is how many documents to return for each page. In other words, "page" is the "start" Solr param and "per-page" is the "rows" Solr param.
|
53
60
|
|
61
|
+
The paginate method returns WillPaginate ready "docs" objects, so for example in a Rails application, paginating is as simple as:
|
62
|
+
<%= will_paginate @solr_response["response"]["docs"] %>
|
54
63
|
|
55
|
-
|
56
|
-
|
64
|
+
===Method Missing
|
65
|
+
The RSolr::Client class also uses method_missing for setting the request handler/path:
|
66
|
+
|
67
|
+
solr.paintings :params => {:q=>'roses', :fq=>['red', 'violet']}
|
68
|
+
|
69
|
+
This is sent to Solr as:
|
70
|
+
paintings?q=roses&fq=red&fq=violet
|
57
71
|
|
58
|
-
|
59
|
-
|
60
|
-
solr.
|
72
|
+
This works with pagination as well:
|
73
|
+
|
74
|
+
solr.paginate_paintings 1, 10, {:q=>'roses', :fq=>['red', 'violet']}
|
75
|
+
|
76
|
+
===Using POST for Search Queries
|
77
|
+
There may be cases where the query string is too long for a GET request. RSolr solves this issue by converting hash objects into form-encoded strings:
|
78
|
+
response = solr.music :data => {:q => "*:*"}
|
79
|
+
|
80
|
+
The :data hash is serialized as a form-encoded query string, and the correct content-type headers are sent along to Solr.
|
81
|
+
|
82
|
+
===Sending HEAD Requests
|
83
|
+
There may be cases where you'd like to send a HEAD request to Solr:
|
84
|
+
solr.head("admin/ping").response[:status] == 200
|
85
|
+
|
86
|
+
==Sending HTTP Headers
|
87
|
+
Solr responds to the request headers listed here: http://wiki.apache.org/solr/SolrAndHTTPCaches
|
88
|
+
To send header information to Solr using RSolr, just use the :headers option:
|
89
|
+
response = solr.head "admin/ping", :headers => {"Cache-Control" => "If-None-Match"}
|
90
|
+
|
91
|
+
===Building a Request
|
92
|
+
RSolr::Client provides a method for building a request context, which can be useful for debugging or logging etc.:
|
93
|
+
request_context = solr.build_request "select", :data => {:q => "*:*"}, :method => :post, :headers => {}
|
94
|
+
|
95
|
+
To build a paginated request use build_paginated_request:
|
96
|
+
request_context = solr.build_paginated_request 1, 10, "select", ...
|
97
|
+
|
98
|
+
== Updating Solr
|
99
|
+
Updating is done using native Ruby objects. Hashes are used for single documents and arrays are used for a collection of documents (hashes). These objects get turned into simple XML "messages". Raw XML strings can also be used.
|
61
100
|
|
62
101
|
Single document via #add
|
63
102
|
solr.add :id=>1, :price=>1.00
|
@@ -66,17 +105,28 @@ Multiple documents via #add
|
|
66
105
|
documents = [{:id=>1, :price=>1.00}, {:id=>2, :price=>10.50}]
|
67
106
|
solr.add documents
|
68
107
|
|
69
|
-
|
108
|
+
The optional :add_attributes hash can also be used to set Solr "add" document attributes:
|
109
|
+
solr.add documents, :add_attributes => {:commitWithin => 10}
|
110
|
+
|
111
|
+
Raw XML via #update
|
112
|
+
solr.update :data => '<commit/>'
|
113
|
+
solr.update :data => '<optimize/>'
|
114
|
+
|
115
|
+
When adding, you can also supply "add" xml element attributes and/or a block for manipulating other "add" related elements (docs and fields) by calling the +xml+ method directly:
|
70
116
|
|
71
117
|
doc = {:id=>1, :price=>1.00}
|
72
|
-
add_attributes = {:allowDups=>false, :commitWithin=>10
|
73
|
-
solr.add(doc, add_attributes) do |doc|
|
118
|
+
add_attributes = {:allowDups=>false, :commitWithin=>10}
|
119
|
+
add_xml = solr.xml.add(doc, add_attributes) do |doc|
|
74
120
|
# boost each document
|
75
121
|
doc.attrs[:boost] = 1.5
|
76
122
|
# boost the price field:
|
77
123
|
doc.field_by_name(:price).attrs[:boost] = 2.0
|
78
124
|
end
|
79
125
|
|
126
|
+
Now the "add_xml" object can be sent to Solr like:
|
127
|
+
solr.update :data => add_xml
|
128
|
+
|
129
|
+
===Deleting
|
80
130
|
Delete by id
|
81
131
|
solr.delete_by_id 1
|
82
132
|
or an array of ids
|
@@ -87,27 +137,73 @@ Delete by query:
|
|
87
137
|
Delete by array of queries
|
88
138
|
solr.delete_by_query ['price:1.00', 'price:10.00']
|
89
139
|
|
90
|
-
Commit
|
91
|
-
solr.commit
|
92
|
-
solr.optimize
|
140
|
+
===Commit / Optimize
|
141
|
+
solr.commit, :commit_attributes => {}
|
142
|
+
solr.optimize, :optimize_attributes => {}
|
93
143
|
|
94
144
|
== Response Formats
|
95
145
|
The default response format is Ruby. When the :wt param is set to :ruby, the response is eval'd resulting in a Hash. You can get a raw response by setting the :wt to "ruby" - notice, the string -- not a symbol. RSolr will eval the Ruby string ONLY if the :wt value is :ruby. All other response formats are available as expected, :wt=>'xml' etc..
|
96
146
|
|
97
147
|
===Evaluated Ruby (default)
|
98
|
-
solr.select
|
148
|
+
solr.get 'select', :params => {:wt => :ruby} # notice :ruby is a Symbol
|
99
149
|
===Raw Ruby
|
100
|
-
solr.select
|
150
|
+
solr.get 'select', :params => {:wt => 'ruby'} # notice 'ruby' is a String
|
101
151
|
|
102
152
|
===XML:
|
103
|
-
solr.select
|
153
|
+
solr.get 'select', :params => {:wt => :xml}
|
104
154
|
===JSON:
|
105
|
-
solr.select
|
106
|
-
|
107
|
-
You can access the original request context (path, params, url etc.) by calling the #raw method:
|
108
|
-
response = solr.select :q=>'*:*'
|
109
|
-
response.raw[:status_code]
|
110
|
-
response.raw[:body]
|
111
|
-
response.raw[:url]
|
155
|
+
solr.get 'select', :params => {:wt => :json}
|
112
156
|
|
113
|
-
|
157
|
+
==Related Resources & Projects
|
158
|
+
* {RSolr Google Group}[http://groups.google.com/group/rsolr] -- The RSolr discussion group
|
159
|
+
* {rsolr-ext}[http://github.com/mwmitchell/rsolr-ext] -- An extension kit for RSolr
|
160
|
+
* {rsolr-direct}[http://github.com/mwmitchell/rsolr-direct] -- JRuby direct connection for RSolr
|
161
|
+
* {rsolr-nokogiri}[http://github.com/mwmitchell/rsolr-nokogiri] -- Gives RSolr Nokogiri for XML generation.
|
162
|
+
* {SunSpot}[http://github.com/outoftime/sunspot] -- An awesome Solr DSL, built with RSolr
|
163
|
+
* {Blacklight}[http://blacklightopac.org] -- A "next generation" Library OPAC, built with RSolr
|
164
|
+
* {java_bin}[http://github.com/kennyj/java_bin] -- Provides javabin/binary parsing for RSolr
|
165
|
+
* {Solr}[http://lucene.apache.org/solr/] -- The Apache Solr project
|
166
|
+
* {solr-ruby}[http://wiki.apache.org/solr/solr-ruby] -- The original Solr Ruby Gem!
|
167
|
+
|
168
|
+
== Note on Patches/Pull Requests
|
169
|
+
* Fork the project.
|
170
|
+
* Make your feature addition or bug fix.
|
171
|
+
* Add tests for it. This is important so I don't break it in a future version unintentionally.
|
172
|
+
* Commit, do not mess with rakefile, version, or history
|
173
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
174
|
+
* Send me a pull request. Bonus points for topic branches.
|
175
|
+
|
176
|
+
== Note on Patches/Pull Requests
|
177
|
+
|
178
|
+
* Fork the project.
|
179
|
+
* Make your feature addition or bug fix.
|
180
|
+
* Add tests for it. This is important so I don't break it in a
|
181
|
+
future version unintentionally.
|
182
|
+
* Commit, do not mess with rakefile, version, or history.
|
183
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
184
|
+
* Send me a pull request. Bonus points for topic branches.
|
185
|
+
|
186
|
+
==Contributors
|
187
|
+
* Jonathan Rochkind
|
188
|
+
* Chris Beer
|
189
|
+
* Craig Smith
|
190
|
+
* Randy Souza
|
191
|
+
* Colin Steele
|
192
|
+
* Peter Kieltyka
|
193
|
+
* Lorenzo Riccucci
|
194
|
+
* Mike Perham
|
195
|
+
* Mat Brown
|
196
|
+
* Shairon Toledo
|
197
|
+
* Matthew Rudy
|
198
|
+
* Fouad Mardini
|
199
|
+
* Jeremy Hinegardner
|
200
|
+
* Nathan Witmer
|
201
|
+
* "shima"
|
202
|
+
|
203
|
+
==Author
|
204
|
+
|
205
|
+
Matt Mitchell <mailto:goodieboy@gmail.com>
|
206
|
+
|
207
|
+
==Copyright
|
208
|
+
|
209
|
+
Copyright (c) 2008-2010 Matt Mitchell. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
require 'rubygems/package_task'
|
5
|
+
|
6
|
+
ENV['RUBYOPT'] = '-W1'
|
7
|
+
|
8
|
+
task :environment do
|
9
|
+
require File.dirname(__FILE__) + '/lib/rsolr'
|
10
|
+
end
|
11
|
+
|
12
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
13
|
+
|
14
|
+
task :default => ['spec:api']
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.3
|
data/lib/rsolr/char.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# A module that contains (1) string related methods
|
2
|
+
module RSolr::Char
|
3
|
+
|
4
|
+
# backslash everything
|
5
|
+
# that isn't a word character
|
6
|
+
def escape value
|
7
|
+
value.gsub(/(\W)/, '\\\\\1')
|
8
|
+
end
|
9
|
+
|
10
|
+
# LUCENE_CHAR_RX = /([\+\-\!\(\)\[\]\^\"\~\*\?\:\\]+)/
|
11
|
+
# LUCENE_WORD_RX = /(OR|AND|NOT)/
|
12
|
+
#
|
13
|
+
# # More specific/lucene escape sequence
|
14
|
+
# def lucene_escape string
|
15
|
+
# delim = " "
|
16
|
+
# string.gsub(LUCENE_CHAR_RX, '\\\\\1').split(delim).map { |v|
|
17
|
+
# v.gsub(LUCENE_WORD_RX, '\\\\\1')
|
18
|
+
# }.join(delim)
|
19
|
+
# end
|
20
|
+
|
21
|
+
end
|
data/lib/rsolr/client.rb
CHANGED
@@ -1,114 +1,260 @@
|
|
1
1
|
class RSolr::Client
|
2
2
|
|
3
|
-
attr_reader :connection
|
3
|
+
attr_reader :connection, :uri, :proxy, :options
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
# RSolr::Adapter::Direct (jRuby only)
|
8
|
-
# or any other class that uses the connection "interface"
|
9
|
-
def initialize(connection)
|
5
|
+
def initialize connection, options = {}
|
6
|
+
@proxy = @uri = nil
|
10
7
|
@connection = connection
|
8
|
+
unless false === options[:url]
|
9
|
+
url = options[:url] ? options[:url].dup : 'http://127.0.0.1:8983/solr/'
|
10
|
+
url << "/" unless url[-1] == ?/
|
11
|
+
@uri = RSolr::Uri.create url
|
12
|
+
if options[:proxy]
|
13
|
+
proxy_url = options[:proxy].dup
|
14
|
+
proxy_url << "/" unless proxy_url.nil? or proxy_url[-1] == ?/
|
15
|
+
@proxy = RSolr::Uri.create proxy_url if proxy_url
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@options = options
|
19
|
+
end
|
20
|
+
|
21
|
+
# returns the request uri object.
|
22
|
+
def base_request_uri
|
23
|
+
base_uri.request_uri if base_uri
|
11
24
|
end
|
12
25
|
|
13
|
-
#
|
14
|
-
#
|
15
|
-
def
|
16
|
-
|
26
|
+
# returns the uri proxy if present,
|
27
|
+
# otherwise just the uri object.
|
28
|
+
def base_uri
|
29
|
+
@proxy ? @proxy : @uri
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create the get, post, and head methods
|
33
|
+
%W(get post head).each do |meth|
|
34
|
+
class_eval <<-RUBY
|
35
|
+
def #{meth} path, opts = {}, &block
|
36
|
+
send_and_receive path, opts.merge(:method => :#{meth}), &block
|
37
|
+
end
|
38
|
+
RUBY
|
17
39
|
end
|
18
40
|
|
19
|
-
#
|
20
|
-
#
|
21
|
-
|
22
|
-
|
41
|
+
# A paginated request method.
|
42
|
+
# Converts the page and per_page
|
43
|
+
# arguments into "rows" and "start".
|
44
|
+
def paginate page, per_page, path, opts = nil
|
45
|
+
opts ||= {}
|
46
|
+
opts[:params] ||= {}
|
47
|
+
raise "'rows' or 'start' params should not be set when using +paginate+" if ["start", "rows"].include?(opts[:params].keys)
|
48
|
+
execute build_paginated_request(page, per_page, path, opts)
|
23
49
|
end
|
24
50
|
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
51
|
+
# POST XML messages to /update with optional params.
|
52
|
+
#
|
53
|
+
# http://wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update
|
54
|
+
#
|
55
|
+
# If not set, opts[:headers] will be set to a hash with the key
|
56
|
+
# 'Content-Type' set to 'text/xml'
|
57
|
+
#
|
58
|
+
# +opts+ can/should contain:
|
31
59
|
#
|
60
|
+
# :data - posted data
|
61
|
+
# :headers - http headers
|
62
|
+
# :params - solr query parameter hash
|
32
63
|
#
|
33
|
-
def
|
34
|
-
|
35
|
-
|
64
|
+
def update opts = {}
|
65
|
+
opts[:headers] ||= {}
|
66
|
+
opts[:headers]['Content-Type'] ||= 'text/xml'
|
67
|
+
post 'update', opts
|
36
68
|
end
|
37
69
|
|
70
|
+
#
|
71
|
+
# +add+ creates xml "add" documents and sends the xml data to the +update+ method
|
72
|
+
#
|
73
|
+
# http://wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update
|
38
74
|
#
|
39
75
|
# single record:
|
40
76
|
# solr.update(:id=>1, :name=>'one')
|
41
77
|
#
|
42
78
|
# update using an array
|
43
|
-
#
|
44
|
-
#
|
45
|
-
|
46
|
-
|
79
|
+
#
|
80
|
+
# solr.update(
|
81
|
+
# [{:id=>1, :name=>'one'}, {:id=>2, :name=>'two'}],
|
82
|
+
# :add_attributes => {:boost=>5.0, :commitWithin=>10}
|
83
|
+
# )
|
84
|
+
#
|
85
|
+
def add doc, opts = {}
|
86
|
+
add_attributes = opts.delete :add_attributes
|
87
|
+
update opts.merge(:data => xml.add(doc, add_attributes))
|
47
88
|
end
|
48
89
|
|
49
|
-
# send
|
50
|
-
|
51
|
-
|
90
|
+
# send "commit" xml with opts
|
91
|
+
#
|
92
|
+
# http://wiki.apache.org/solr/UpdateXmlMessages#A.22commit.22_and_.22optimize.22
|
93
|
+
#
|
94
|
+
def commit opts = {}
|
95
|
+
commit_attrs = opts.delete :commit_attributes
|
96
|
+
update opts.merge(:data => xml.commit( commit_attrs ))
|
52
97
|
end
|
53
98
|
|
54
|
-
# send
|
55
|
-
|
56
|
-
|
99
|
+
# send "optimize" xml with opts.
|
100
|
+
#
|
101
|
+
# http://wiki.apache.org/solr/UpdateXmlMessages#A.22commit.22_and_.22optimize.22
|
102
|
+
#
|
103
|
+
def optimize opts = {}
|
104
|
+
optimize_attributes = opts.delete :optimize_attributes
|
105
|
+
update opts.merge(:data => xml.optimize(optimize_attributes))
|
57
106
|
end
|
58
|
-
|
107
|
+
|
59
108
|
# send </rollback>
|
109
|
+
#
|
110
|
+
# http://wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22
|
111
|
+
#
|
60
112
|
# NOTE: solr 1.4 only
|
61
|
-
def rollback
|
62
|
-
update
|
113
|
+
def rollback opts = {}
|
114
|
+
update opts.merge(:data => xml.rollback)
|
63
115
|
end
|
64
|
-
|
116
|
+
|
65
117
|
# Delete one or many documents by id
|
66
118
|
# solr.delete_by_id 10
|
67
119
|
# solr.delete_by_id([12, 41, 199])
|
68
|
-
def delete_by_id
|
69
|
-
update
|
120
|
+
def delete_by_id id, opts = {}
|
121
|
+
update opts.merge(:data => xml.delete_by_id(id))
|
70
122
|
end
|
71
123
|
|
72
|
-
# delete one or many documents by query
|
124
|
+
# delete one or many documents by query.
|
125
|
+
#
|
126
|
+
# http://wiki.apache.org/solr/UpdateXmlMessages#A.22delete.22_by_ID_and_by_Query
|
127
|
+
#
|
73
128
|
# solr.delete_by_query 'available:0'
|
74
129
|
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
75
|
-
def delete_by_query
|
76
|
-
update
|
130
|
+
def delete_by_query query, opts = {}
|
131
|
+
update opts.merge(:data => xml.delete_by_query(query))
|
132
|
+
end
|
133
|
+
|
134
|
+
# shortcut to RSolr::Xml::Generator
|
135
|
+
def xml
|
136
|
+
@xml ||= RSolr::Xml::Generator.new
|
137
|
+
end
|
138
|
+
|
139
|
+
# +send_and_receive+ is the main request method responsible for sending requests to the +connection+ object.
|
140
|
+
#
|
141
|
+
# "path" : A string value that usually represents a solr request handler
|
142
|
+
# "opts" : A hash, which can contain the following keys:
|
143
|
+
# :method : required - the http method (:get, :post or :head)
|
144
|
+
# :params : optional - the query string params in hash form
|
145
|
+
# :data : optional - post data -- if a hash is given, it's sent as "application/x-www-form-urlencoded"
|
146
|
+
# :headers : optional - hash of request headers
|
147
|
+
# All other options are passed right along to the connection's +send_and_receive+ method (:get, :post, or :head)
|
148
|
+
#
|
149
|
+
# +send_and_receive+ returns either a string or hash on a successful ruby request.
|
150
|
+
# When the :params[:wt] => :ruby, the response will be a hash, else a string.
|
151
|
+
#
|
152
|
+
# creates a request context hash,
|
153
|
+
# sends it to the connection's +execute+ method
|
154
|
+
# which returns a simple hash,
|
155
|
+
# then passes the request/response into +adapt_response+.
|
156
|
+
def send_and_receive path, opts
|
157
|
+
request_context = build_request path, opts
|
158
|
+
execute request_context
|
77
159
|
end
|
78
160
|
|
79
|
-
#
|
80
|
-
def
|
81
|
-
|
161
|
+
#
|
162
|
+
def execute request_context
|
163
|
+
raw_response = connection.execute self, request_context
|
164
|
+
adapt_response(request_context, raw_response) unless raw_response.nil?
|
165
|
+
end
|
166
|
+
|
167
|
+
# +build_request+ accepts a path and options hash,
|
168
|
+
# then prepares a normalized hash to return for sending
|
169
|
+
# to a solr connection driver.
|
170
|
+
# +build_request+ sets up the uri/query string
|
171
|
+
# and converts the +data+ arg to form-urlencoded,
|
172
|
+
# if the +data+ arg is a hash.
|
173
|
+
# returns a hash with the following keys:
|
174
|
+
# :method
|
175
|
+
# :params
|
176
|
+
# :headers
|
177
|
+
# :data
|
178
|
+
# :uri
|
179
|
+
# :path
|
180
|
+
# :query
|
181
|
+
def build_request path, opts
|
182
|
+
raise "path must be a string or symbol, not #{path.inspect}" unless [String,Symbol].include?(path.class)
|
183
|
+
path = path.to_s
|
184
|
+
opts[:proxy] = proxy unless proxy.nil?
|
185
|
+
opts[:method] ||= :get
|
186
|
+
raise "The :data option can only be used if :method => :post" if opts[:method] != :post and opts[:data]
|
187
|
+
opts[:params] = opts[:params].nil? ? {:wt => :ruby} : {:wt => :ruby}.merge(opts[:params])
|
188
|
+
query = RSolr::Uri.params_to_solr(opts[:params]) unless opts[:params].empty?
|
189
|
+
opts[:query] = query
|
190
|
+
if opts[:data].is_a? Hash
|
191
|
+
opts[:data] = RSolr::Uri.params_to_solr opts[:data]
|
192
|
+
opts[:headers] ||= {}
|
193
|
+
opts[:headers]['Content-Type'] ||= 'application/x-www-form-urlencoded'
|
194
|
+
end
|
195
|
+
opts[:path] = path
|
196
|
+
opts[:uri] = base_uri.merge(path.to_s + (query ? "?#{query}" : "")) if base_uri
|
197
|
+
opts
|
198
|
+
end
|
199
|
+
|
200
|
+
def build_paginated_request page, per_page, path, opts
|
201
|
+
per_page = per_page.to_s.to_i
|
202
|
+
page = page.to_s.to_i-1
|
203
|
+
page = page < 1 ? 0 : page
|
204
|
+
opts[:params]["start"] = page * per_page
|
205
|
+
opts[:params]["rows"] = per_page
|
206
|
+
build_request path, opts
|
207
|
+
end
|
208
|
+
|
209
|
+
# A mixin for used by #adapt_response
|
210
|
+
module Context
|
211
|
+
attr_accessor :request, :response
|
212
|
+
end
|
213
|
+
|
214
|
+
# This method will evaluate the :body value
|
215
|
+
# if the params[:uri].params[:wt] == :ruby
|
216
|
+
# ... otherwise, the body is returned as is.
|
217
|
+
# The return object has methods attached, :request and :response.
|
218
|
+
# These methods give you access to the original
|
219
|
+
# request and response from the connection.
|
220
|
+
#
|
221
|
+
# +adapt_response+ will raise an InvalidRubyResponse
|
222
|
+
# if :wt == :ruby and the body
|
223
|
+
# couldn't be evaluated.
|
224
|
+
def adapt_response request, response
|
225
|
+
raise "The response does not have the correct keys => :body, :headers, :status" unless
|
226
|
+
%W(body headers status) == response.keys.map{|k|k.to_s}.sort
|
227
|
+
raise RSolr::Error::Http.new request, response unless [200,302].include? response[:status]
|
228
|
+
result = request[:params][:wt] == :ruby ? evaluate_ruby_response(request, response) : response[:body]
|
229
|
+
result.extend Context
|
230
|
+
result.request, result.response = request, response
|
231
|
+
result.is_a?(Hash) ? result.extend(RSolr::Response) : result
|
82
232
|
end
|
83
233
|
|
84
234
|
protected
|
85
235
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
236
|
+
# converts the method name for the solr request handler path.
|
237
|
+
def method_missing name, *args
|
238
|
+
if name.to_s =~ /^paginated?_(.+)$/
|
239
|
+
paginate args[0], args[1], $1, *args[2..-1]
|
240
|
+
else
|
241
|
+
send_and_receive name, *args
|
242
|
+
end
|
91
243
|
end
|
92
|
-
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
if connection_response[:params][:wt] == :ruby
|
106
|
-
data = Kernel.eval(data)
|
244
|
+
|
245
|
+
# evaluates the response[:body],
|
246
|
+
# attempts to bring the ruby string to life.
|
247
|
+
# If a SyntaxError is raised, then
|
248
|
+
# this method intercepts and raises a
|
249
|
+
# RSolr::Error::InvalidRubyResponse
|
250
|
+
# instead, giving full access to the
|
251
|
+
# request/response objects.
|
252
|
+
def evaluate_ruby_response request, response
|
253
|
+
begin
|
254
|
+
Kernel.eval response[:body].to_s
|
255
|
+
rescue SyntaxError
|
256
|
+
raise RSolr::Error::InvalidRubyResponse.new request, response
|
107
257
|
end
|
108
|
-
# attach a method called #raw that returns the original connection response value
|
109
|
-
def data.raw; @raw end
|
110
|
-
data.send(:instance_variable_set, '@raw', connection_response)
|
111
|
-
data
|
112
258
|
end
|
113
259
|
|
114
|
-
end
|
260
|
+
end
|