rsolr 1.0.8 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +21 -0
- data/CHANGES.txt +20 -1
- data/Gemfile +3 -9
- data/README.rdoc +34 -31
- data/Rakefile +1 -10
- data/lib/rsolr.rb +14 -10
- data/lib/rsolr/char.rb +4 -1
- data/lib/rsolr/client.rb +133 -54
- data/lib/rsolr/connection.rb +21 -17
- data/lib/rsolr/error.rb +39 -20
- data/lib/rsolr/response.rb +57 -13
- data/lib/rsolr/uri.rb +44 -27
- data/lib/rsolr/version.rb +7 -0
- data/lib/rsolr/xml.rb +69 -15
- data/rsolr.gemspec +14 -7
- data/spec/api/char_spec.rb +8 -3
- data/spec/api/client_spec.rb +221 -87
- data/spec/api/connection_spec.rb +93 -29
- data/spec/api/error_spec.rb +22 -32
- data/spec/api/pagination_spec.rb +12 -5
- data/spec/api/rsolr_spec.rb +28 -8
- data/spec/api/uri_spec.rb +108 -50
- data/spec/api/xml_spec.rb +196 -96
- data/spec/fixtures/basic_configs/_rest_managed.json +1 -0
- data/spec/fixtures/basic_configs/currency.xml +67 -0
- data/spec/fixtures/basic_configs/lang/stopwords_en.txt +54 -0
- data/spec/fixtures/basic_configs/protwords.txt +21 -0
- data/spec/fixtures/basic_configs/schema.xml +530 -0
- data/spec/fixtures/basic_configs/solrconfig.xml +572 -0
- data/spec/fixtures/basic_configs/stopwords.txt +14 -0
- data/spec/fixtures/basic_configs/synonyms.txt +29 -0
- data/spec/integration/solr5_spec.rb +26 -0
- data/spec/spec_helper.rb +8 -1
- data/tasks/spec.rake +1 -38
- metadata +98 -34
- data/tasks/rcov.rake +0 -25
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e401f0dcdd04d8215eec9b67a1e7c775c41ac7f4
|
4
|
+
data.tar.gz: 6e466531f33da1560869ce39586101dfc4bbb08e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 29a5ac0f898a33e2d8efc2a0b0b7ed618c169e63597dcc283573ae9302183f0ee983ec18e30d3c9dc100bb13e06ff86358d02ad0df91515101efc8a26f82b7f8
|
7
|
+
data.tar.gz: 1a509a26c086ffbad2543154106584989d7c40d42b747a422a622ba77fe1dd87202373ae1cd8d10727a0b61b89ad16a5cfcdc5655375ebc7d4b5733d9fa7dcb0
|
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
addons:
|
2
|
+
apt:
|
3
|
+
packages:
|
4
|
+
- libgmp-dev
|
5
|
+
language: ruby
|
6
|
+
sudo: false
|
7
|
+
rvm:
|
8
|
+
- 2.3.1
|
9
|
+
- 2.2.5
|
10
|
+
- jruby-9.0.5.0
|
11
|
+
|
12
|
+
notifications:
|
13
|
+
irc: "irc.freenode.org#blacklight"
|
14
|
+
email:
|
15
|
+
- blacklight-commits@googlegroups.com
|
16
|
+
|
17
|
+
env:
|
18
|
+
global:
|
19
|
+
- JRUBY_OPTS="-J-Xms512m -J-Xmx1024m"
|
20
|
+
- NOKOGIRI_USE_SYSTEM_LIBRARIES=true
|
21
|
+
jdk: oraclejdk8
|
data/CHANGES.txt
CHANGED
@@ -1,5 +1,24 @@
|
|
1
|
+
1.0.12
|
2
|
+
- Fix bug where specifying the wt property as a string, would add the supplied value to the default ('ruby') rather than overriding it.
|
3
|
+
|
4
|
+
1.0.11
|
5
|
+
- add RSolr.solr_escape method and add deprecation messages to RSolr.escape (ndushay)
|
6
|
+
- use stdlib URI.escape methods instead of homegrown in RSolr::URI (ndushay)
|
7
|
+
- fix bug with Rsolr::Uri.create adding trailing slash if query params (ndushay)
|
8
|
+
- update rake tasks (cbeer)
|
9
|
+
- add Ruby 2.2.0 to travis ci build (ndushay)
|
10
|
+
- Housekeeping (badges to README, license in gemspec, correct url in gemspec ...) (ndushay)
|
11
|
+
- Improve rdoc styling (udaykadaboina)
|
12
|
+
- Support setting default_wt per connection via its options. (jcoleman)
|
13
|
+
- eliminates the usage of per-instance `extend` (jcoleman)
|
14
|
+
- Upgrade to RSpec 3 (blackwinter, adamjonas, cbeer)
|
15
|
+
- Fixed RSolr::Error to_s (PofMagicfingers)
|
16
|
+
1.0.10 xxx
|
17
|
+
|
1
18
|
1.0.8
|
2
19
|
- Fix connection refused errors in specs + add basic auth support (Denis Goeury)
|
20
|
+
- Ability to set :retry_503, the number of retry attempts for a 503 response
|
21
|
+
with a Retry-After header.
|
3
22
|
1.0.7
|
4
23
|
- Response body encoding is set to response charset in Ruby >= 1.9
|
5
24
|
- Ability to set :read_timeout and :open_timeout when creating new instance of RSolr
|
@@ -14,4 +33,4 @@
|
|
14
33
|
- Jeweler is no longer used for building the gemspec
|
15
34
|
1.0.3
|
16
35
|
- Proper encodings in Ruby 1.9
|
17
|
-
- Applied pull request from https://github.com/mwmitchell/rsolr/pull/20
|
36
|
+
- Applied pull request from https://github.com/mwmitchell/rsolr/pull/20
|
data/Gemfile
CHANGED
@@ -1,15 +1,9 @@
|
|
1
|
-
source "
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
gem "builder", ">= 2.1.2"
|
6
6
|
|
7
|
-
|
8
|
-
gem
|
9
|
-
gem "rdoc", "~> 3.9.4"
|
10
|
-
end
|
11
|
-
|
12
|
-
group :test do
|
13
|
-
gem "rake", "~> 0.9.2"
|
14
|
-
gem "rspec", "~> 2.6.0"
|
7
|
+
if defined? RUBY_VERSION and RUBY_VERSION < "1.9"
|
8
|
+
gem 'nokogiri', "< 1.6"
|
15
9
|
end
|
data/README.rdoc
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
=RSolr
|
2
|
+
{<img src="https://travis-ci.org/rsolr/rsolr.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/rsolr/rsolr] {<img src="https://badge.fury.io/rb/rsolr.svg" alt="Gem Version" />}[http://badge.fury.io/rb/rsolr]
|
3
|
+
|
2
4
|
|
3
5
|
A simple, extensible Ruby client for Apache Solr.
|
4
6
|
|
5
7
|
==Documentation
|
6
|
-
The code docs
|
8
|
+
The code docs http://www.rubydoc.info/gems/rsolr
|
7
9
|
|
8
10
|
== Installation:
|
9
|
-
|
11
|
+
gem install rsolr
|
10
12
|
|
11
13
|
== Example:
|
12
14
|
require 'rubygems'
|
@@ -24,18 +26,25 @@ The code docs for the last *release* can be viewed here: http://rubydoc.info/gem
|
|
24
26
|
# send a request to /catalog
|
25
27
|
response = solr.get 'catalog', :params => {:q => '*:*'}
|
26
28
|
|
27
|
-
When the Solr
|
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.
|
28
30
|
|
29
|
-
The response also exposes 2 attribute readers (for any
|
31
|
+
The response also exposes 2 attribute readers (for any +:wt+ value), +:request+ and +:response+. Both are Hash objects with symbolized keys.
|
30
32
|
|
31
|
-
The
|
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..
|
32
34
|
|
33
|
-
The
|
35
|
+
The +:response+ attribute contains the original response. This object contains the +:status+, +:body+ and +:headers+ keys.
|
34
36
|
|
35
37
|
== Timeouts
|
36
38
|
The read and connect timeout settings can be set when creating a new instance of RSolr:
|
37
39
|
solr = RSolr.connect(:read_timeout => 120, :open_timeout => 120)
|
38
40
|
|
41
|
+
== Retry 503s
|
42
|
+
A 503 is usually a temporary error which RSolr may retry if requested. You may specify the number of retry attempts with the +:retry_503+ option.
|
43
|
+
|
44
|
+
Only requests which specify a Retry-After header will be retried, after waiting the indicated retry interval, otherwise RSolr will treat the request as a 500. You may specify a maximum Retry-After interval to wait with the +:retry_after_limit+ option (default: one second).
|
45
|
+
solr = RSolr.connect(:retry_503 => 1, :retry_after_limit => 1)
|
46
|
+
|
47
|
+
|
39
48
|
== Querying
|
40
49
|
Use the #get / #post method to send search requests to the /select handler:
|
41
50
|
response = solr.get 'select', :params => {
|
@@ -45,7 +54,7 @@ Use the #get / #post method to send search requests to the /select handler:
|
|
45
54
|
}
|
46
55
|
response["response"]["docs"].each{|doc| puts doc["id"] }
|
47
56
|
|
48
|
-
The
|
57
|
+
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.
|
49
58
|
When an array is used, multiple parameters *with the same name* are generated for the Solr query. Example:
|
50
59
|
|
51
60
|
solr.get 'select', :params => {:q=>'roses', :fq=>['red', 'violet']}
|
@@ -64,7 +73,7 @@ The paginate method returns WillPaginate ready "docs" objects, so for example in
|
|
64
73
|
<%= will_paginate @solr_response["response"]["docs"] %>
|
65
74
|
|
66
75
|
===Method Missing
|
67
|
-
The RSolr::Client class also uses method_missing for setting the request handler/path:
|
76
|
+
The +RSolr::Client+ class also uses +method_missing+ for setting the request handler/path:
|
68
77
|
|
69
78
|
solr.paintings :params => {:q=>'roses', :fq=>['red', 'violet']}
|
70
79
|
|
@@ -79,7 +88,7 @@ This works with pagination as well:
|
|
79
88
|
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:
|
80
89
|
response = solr.music :data => {:q => "*:*"}
|
81
90
|
|
82
|
-
The
|
91
|
+
The +:data+ hash is serialized as a form-encoded query string, and the correct content-type headers are sent along to Solr.
|
83
92
|
|
84
93
|
===Sending HEAD Requests
|
85
94
|
There may be cases where you'd like to send a HEAD request to Solr:
|
@@ -87,11 +96,11 @@ There may be cases where you'd like to send a HEAD request to Solr:
|
|
87
96
|
|
88
97
|
==Sending HTTP Headers
|
89
98
|
Solr responds to the request headers listed here: http://wiki.apache.org/solr/SolrAndHTTPCaches
|
90
|
-
To send header information to Solr using RSolr, just use the
|
99
|
+
To send header information to Solr using RSolr, just use the +:headers+ option:
|
91
100
|
response = solr.head "admin/ping", :headers => {"Cache-Control" => "If-None-Match"}
|
92
101
|
|
93
102
|
===Building a Request
|
94
|
-
RSolr::Client provides a method for building a request context, which can be useful for debugging or logging etc.:
|
103
|
+
+RSolr::Client+ provides a method for building a request context, which can be useful for debugging or logging etc.:
|
95
104
|
request_context = solr.build_request "select", :data => {:q => "*:*"}, :method => :post, :headers => {}
|
96
105
|
|
97
106
|
To build a paginated request use build_paginated_request:
|
@@ -107,7 +116,7 @@ Multiple documents via #add
|
|
107
116
|
documents = [{:id=>1, :price=>1.00}, {:id=>2, :price=>10.50}]
|
108
117
|
solr.add documents
|
109
118
|
|
110
|
-
The optional
|
119
|
+
The optional +:add_attributes+ hash can also be used to set Solr "add" document attributes:
|
111
120
|
solr.add documents, :add_attributes => {:commitWithin => 10}
|
112
121
|
|
113
122
|
Raw XML via #update
|
@@ -144,7 +153,7 @@ Delete by array of queries
|
|
144
153
|
solr.optimize, :optimize_attributes => {}
|
145
154
|
|
146
155
|
== Response Formats
|
147
|
-
The default response format is Ruby. When the
|
156
|
+
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..
|
148
157
|
|
149
158
|
===Evaluated Ruby (default)
|
150
159
|
solr.get 'select', :params => {:wt => :ruby} # notice :ruby is a Symbol
|
@@ -176,27 +185,21 @@ The default response format is Ruby. When the :wt param is set to :ruby, the res
|
|
176
185
|
* Send me a pull request. Bonus points for topic branches.
|
177
186
|
|
178
187
|
==Contributors
|
179
|
-
*
|
180
|
-
* Dmitry Lihachev
|
181
|
-
* Lucas Souza
|
182
|
-
* Peter Kieltyka
|
183
|
-
* Rob Di Marco
|
188
|
+
* Nathan Witmer
|
184
189
|
* Magnus Bergmark
|
185
|
-
*
|
186
|
-
* Chris Beer
|
187
|
-
* Craig Smith
|
190
|
+
* shima
|
188
191
|
* Randy Souza
|
189
|
-
* Colin Steele
|
190
|
-
* Peter Kieltyka
|
191
|
-
* Lorenzo Riccucci
|
192
|
-
* Mike Perham
|
193
192
|
* Mat Brown
|
194
|
-
* Shairon Toledo
|
195
|
-
* Matthew Rudy
|
196
|
-
* Fouad Mardini
|
197
193
|
* Jeremy Hinegardner
|
198
|
-
*
|
199
|
-
*
|
194
|
+
* Denis Goeury
|
195
|
+
* shairon toledo
|
196
|
+
* Rob Di Marco
|
197
|
+
* Peter Kieltyka
|
198
|
+
* Mike Perham
|
199
|
+
* Lucas Souza
|
200
|
+
* Dmitry Lihachev
|
201
|
+
* Antoine Latter
|
202
|
+
* Naomi Dushay
|
200
203
|
|
201
204
|
==Author
|
202
205
|
|
@@ -204,4 +207,4 @@ Matt Mitchell <mailto:goodieboy@gmail.com>
|
|
204
207
|
|
205
208
|
==Copyright
|
206
209
|
|
207
|
-
Copyright (c) 2008-2010 Matt Mitchell. See LICENSE for details.
|
210
|
+
Copyright (c) 2008-2010 Matt Mitchell. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,15 +1,6 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require 'rake/testtask'
|
3
2
|
require 'bundler/gem_tasks'
|
4
3
|
|
5
|
-
require 'rubygems/package_task'
|
6
|
-
|
7
|
-
ENV['RUBYOPT'] = '-W1'
|
8
|
-
|
9
|
-
task :environment do
|
10
|
-
require File.dirname(__FILE__) + '/lib/rsolr'
|
11
|
-
end
|
12
|
-
|
13
4
|
Dir['tasks/**/*.rake'].each { |t| load t }
|
14
5
|
|
15
|
-
task :default => ['spec
|
6
|
+
task :default => ['spec']
|
data/lib/rsolr.rb
CHANGED
@@ -1,14 +1,6 @@
|
|
1
|
-
$: << "#{File.dirname(__FILE__)}" unless $:.include? File.dirname(__FILE__)
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
|
5
1
|
module RSolr
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
def self.version; "1.0.8" end
|
10
|
-
|
11
|
-
VERSION = self.version
|
3
|
+
Dir.glob(File.expand_path("../rsolr/*.rb", __FILE__)).each{|rb_file| require(rb_file)}
|
12
4
|
|
13
5
|
def self.connect *args
|
14
6
|
driver = Class === args[0] ? args[0] : RSolr::Connection
|
@@ -16,7 +8,19 @@ module RSolr
|
|
16
8
|
Client.new driver.new, opts
|
17
9
|
end
|
18
10
|
|
19
|
-
# RSolr.escape
|
11
|
+
# RSolr.escape, which is deprecated as of 2015-02
|
20
12
|
extend Char
|
21
13
|
|
14
|
+
# backslash escape characters that have special meaning to Solr query parser
|
15
|
+
# per http://lucene.apache.org/core/4_0_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#Escaping_Special_Characters
|
16
|
+
# + - & | ! ( ) { } [ ] ^ " ~ * ? : \ /
|
17
|
+
# see also http://svn.apache.org/repos/asf/lucene/dev/tags/lucene_solr_4_9_1/solr/solrj/src/java/org/apache/solr/client/solrj/util/ClientUtils.java
|
18
|
+
# escapeQueryChars method
|
19
|
+
# @return [String] str with special chars preceded by a backslash
|
20
|
+
def self.solr_escape(str)
|
21
|
+
# note that the gsub will parse the escaped backslashes, as will the ruby code sending the query to Solr
|
22
|
+
# so the result sent to Solr is ultimately a single backslash in front of the particular character
|
23
|
+
str.gsub(/([+\-&|!\(\)\{\}\[\]\^"~\*\?:\\\/])/, '\\\\\1')
|
24
|
+
end
|
25
|
+
|
22
26
|
end
|
data/lib/rsolr/char.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# A module that contains (1) string related methods
|
2
|
+
# @deprecated remove this module when we remove the method (duh)
|
2
3
|
module RSolr::Char
|
3
4
|
|
4
5
|
# backslash everything
|
5
6
|
# that isn't a word character
|
7
|
+
# @deprecated - this is incorrect Solr escaping
|
6
8
|
def escape value
|
9
|
+
warn "[DEPRECATION] `RSolr.escape` is deprecated (and incorrect). Use `RSolr.solr_escape` instead."
|
7
10
|
value.gsub(/(\W)/, '\\\\\1')
|
8
11
|
end
|
9
12
|
|
@@ -18,4 +21,4 @@ module RSolr::Char
|
|
18
21
|
# }.join(delim)
|
19
22
|
# end
|
20
23
|
|
21
|
-
end
|
24
|
+
end
|
data/lib/rsolr/client.rb
CHANGED
@@ -1,7 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'json'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
1
6
|
class RSolr::Client
|
2
|
-
|
3
|
-
|
4
|
-
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def default_wt
|
10
|
+
@default_wt || :ruby
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_wt= value
|
14
|
+
@default_wt = value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :connection, :uri, :proxy, :options, :update_path
|
19
|
+
|
5
20
|
def initialize connection, options = {}
|
6
21
|
@proxy = @uri = nil
|
7
22
|
@connection = connection
|
@@ -13,22 +28,24 @@ class RSolr::Client
|
|
13
28
|
proxy_url = options[:proxy].dup
|
14
29
|
proxy_url << "/" unless proxy_url.nil? or proxy_url[-1] == ?/
|
15
30
|
@proxy = RSolr::Uri.create proxy_url if proxy_url
|
31
|
+
elsif options[:proxy] == false
|
32
|
+
@proxy = false # used to avoid setting the proxy from the environment.
|
16
33
|
end
|
17
34
|
end
|
35
|
+
@update_path = options.fetch(:update_path, 'update')
|
18
36
|
@options = options
|
19
37
|
end
|
20
|
-
|
38
|
+
|
21
39
|
# returns the request uri object.
|
22
40
|
def base_request_uri
|
23
41
|
base_uri.request_uri if base_uri
|
24
42
|
end
|
25
|
-
|
26
|
-
# returns the uri
|
27
|
-
# otherwise just the uri object.
|
43
|
+
|
44
|
+
# returns the RSolr::URI uri object.
|
28
45
|
def base_uri
|
29
|
-
@
|
46
|
+
@uri
|
30
47
|
end
|
31
|
-
|
48
|
+
|
32
49
|
# Create the get, post, and head methods
|
33
50
|
%W(get post head).each do |meth|
|
34
51
|
class_eval <<-RUBY
|
@@ -37,7 +54,7 @@ class RSolr::Client
|
|
37
54
|
end
|
38
55
|
RUBY
|
39
56
|
end
|
40
|
-
|
57
|
+
|
41
58
|
# A paginated request method.
|
42
59
|
# Converts the page and per_page
|
43
60
|
# arguments into "rows" and "start".
|
@@ -47,9 +64,9 @@ class RSolr::Client
|
|
47
64
|
raise "'rows' or 'start' params should not be set when using +paginate+" if ["start", "rows"].include?(opts[:params].keys)
|
48
65
|
execute build_paginated_request(page, per_page, path, opts)
|
49
66
|
end
|
50
|
-
|
67
|
+
|
51
68
|
# POST XML messages to /update with optional params.
|
52
|
-
#
|
69
|
+
#
|
53
70
|
# http://wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update
|
54
71
|
#
|
55
72
|
# If not set, opts[:headers] will be set to a hash with the key
|
@@ -64,24 +81,24 @@ class RSolr::Client
|
|
64
81
|
def update opts = {}
|
65
82
|
opts[:headers] ||= {}
|
66
83
|
opts[:headers]['Content-Type'] ||= 'text/xml'
|
67
|
-
post
|
84
|
+
post opts.fetch(:path, update_path), opts
|
68
85
|
end
|
69
|
-
|
70
|
-
#
|
86
|
+
|
87
|
+
#
|
71
88
|
# +add+ creates xml "add" documents and sends the xml data to the +update+ method
|
72
|
-
#
|
89
|
+
#
|
73
90
|
# http://wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update
|
74
|
-
#
|
91
|
+
#
|
75
92
|
# single record:
|
76
|
-
# solr.
|
93
|
+
# solr.add(:id=>1, :name=>'one')
|
94
|
+
#
|
95
|
+
# add using an array
|
77
96
|
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
# solr.update(
|
97
|
+
# solr.add(
|
81
98
|
# [{:id=>1, :name=>'one'}, {:id=>2, :name=>'two'}],
|
82
99
|
# :add_attributes => {:boost=>5.0, :commitWithin=>10}
|
83
100
|
# )
|
84
|
-
#
|
101
|
+
#
|
85
102
|
def add doc, opts = {}
|
86
103
|
add_attributes = opts.delete :add_attributes
|
87
104
|
update opts.merge(:data => xml.add(doc, add_attributes))
|
@@ -104,16 +121,16 @@ class RSolr::Client
|
|
104
121
|
optimize_attributes = opts.delete :optimize_attributes
|
105
122
|
update opts.merge(:data => xml.optimize(optimize_attributes))
|
106
123
|
end
|
107
|
-
|
124
|
+
|
108
125
|
# send </rollback>
|
109
|
-
#
|
126
|
+
#
|
110
127
|
# http://wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22
|
111
|
-
#
|
128
|
+
#
|
112
129
|
# NOTE: solr 1.4 only
|
113
130
|
def rollback opts = {}
|
114
131
|
update opts.merge(:data => xml.rollback)
|
115
132
|
end
|
116
|
-
|
133
|
+
|
117
134
|
# Delete one or many documents by id
|
118
135
|
# solr.delete_by_id 10
|
119
136
|
# solr.delete_by_id([12, 41, 199])
|
@@ -122,22 +139,22 @@ class RSolr::Client
|
|
122
139
|
end
|
123
140
|
|
124
141
|
# delete one or many documents by query.
|
125
|
-
#
|
142
|
+
#
|
126
143
|
# http://wiki.apache.org/solr/UpdateXmlMessages#A.22delete.22_by_ID_and_by_Query
|
127
|
-
#
|
144
|
+
#
|
128
145
|
# solr.delete_by_query 'available:0'
|
129
146
|
# solr.delete_by_query ['quantity:0', 'manu:"FQ"']
|
130
147
|
def delete_by_query query, opts = {}
|
131
148
|
update opts.merge(:data => xml.delete_by_query(query))
|
132
149
|
end
|
133
|
-
|
150
|
+
|
134
151
|
# shortcut to RSolr::Xml::Generator
|
135
152
|
def xml
|
136
153
|
@xml ||= RSolr::Xml::Generator.new
|
137
154
|
end
|
138
|
-
|
155
|
+
|
139
156
|
# +send_and_receive+ is the main request method responsible for sending requests to the +connection+ object.
|
140
|
-
#
|
157
|
+
#
|
141
158
|
# "path" : A string value that usually represents a solr request handler
|
142
159
|
# "opts" : A hash, which can contain the following keys:
|
143
160
|
# :method : required - the http method (:get, :post or :head)
|
@@ -145,7 +162,7 @@ class RSolr::Client
|
|
145
162
|
# :data : optional - post data -- if a hash is given, it's sent as "application/x-www-form-urlencoded; charset=UTF-8"
|
146
163
|
# :headers : optional - hash of request headers
|
147
164
|
# All other options are passed right along to the connection's +send_and_receive+ method (:get, :post, or :head)
|
148
|
-
#
|
165
|
+
#
|
149
166
|
# +send_and_receive+ returns either a string or hash on a successful ruby request.
|
150
167
|
# When the :params[:wt] => :ruby, the response will be a hash, else a string.
|
151
168
|
#
|
@@ -155,18 +172,53 @@ class RSolr::Client
|
|
155
172
|
# then passes the request/response into +adapt_response+.
|
156
173
|
def send_and_receive path, opts
|
157
174
|
request_context = build_request path, opts
|
158
|
-
[:open_timeout, :read_timeout].each do |k|
|
159
|
-
request_context[k] = @options[k]
|
160
|
-
end
|
161
175
|
execute request_context
|
162
176
|
end
|
163
|
-
|
164
|
-
#
|
177
|
+
|
178
|
+
#
|
165
179
|
def execute request_context
|
180
|
+
|
166
181
|
raw_response = connection.execute self, request_context
|
182
|
+
|
183
|
+
while retry_503?(request_context, raw_response)
|
184
|
+
request_context[:retry_503] -= 1
|
185
|
+
sleep retry_after(raw_response)
|
186
|
+
raw_response = connection.execute self, request_context
|
187
|
+
end
|
188
|
+
|
167
189
|
adapt_response(request_context, raw_response) unless raw_response.nil?
|
168
190
|
end
|
169
|
-
|
191
|
+
|
192
|
+
def retry_503?(request_context, response)
|
193
|
+
return false if response.nil?
|
194
|
+
status = response[:status] && response[:status].to_i
|
195
|
+
return false unless status == 503
|
196
|
+
retry_503 = request_context[:retry_503]
|
197
|
+
return false unless retry_503 && retry_503 > 0
|
198
|
+
retry_after_limit = request_context[:retry_after_limit] || 1
|
199
|
+
retry_after = retry_after(response)
|
200
|
+
return false unless retry_after && retry_after <= retry_after_limit
|
201
|
+
true
|
202
|
+
end
|
203
|
+
|
204
|
+
# Retry-After can be a relative number of seconds from now, or an RFC 1123 Date.
|
205
|
+
# If the latter, attempt to convert it to a relative time in seconds.
|
206
|
+
def retry_after(response)
|
207
|
+
retry_after = Array(response[:headers]['Retry-After'] || response[:headers]['retry-after']).flatten.first.to_s
|
208
|
+
if retry_after =~ /\A[0-9]+\Z/
|
209
|
+
retry_after = retry_after.to_i
|
210
|
+
else
|
211
|
+
begin
|
212
|
+
retry_after_date = DateTime.parse(retry_after)
|
213
|
+
retry_after = retry_after_date.to_time - Time.now
|
214
|
+
retry_after = nil if retry_after < 0
|
215
|
+
rescue ArgumentError
|
216
|
+
retry_after = retry_after.to_i
|
217
|
+
end
|
218
|
+
end
|
219
|
+
retry_after
|
220
|
+
end
|
221
|
+
|
170
222
|
# +build_request+ accepts a path and options hash,
|
171
223
|
# then prepares a normalized hash to return for sending
|
172
224
|
# to a solr connection driver.
|
@@ -187,7 +239,7 @@ class RSolr::Client
|
|
187
239
|
opts[:proxy] = proxy unless proxy.nil?
|
188
240
|
opts[:method] ||= :get
|
189
241
|
raise "The :data option can only be used if :method => :post" if opts[:method] != :post and opts[:data]
|
190
|
-
opts[:params] =
|
242
|
+
opts[:params] = params_with_wt(opts[:params])
|
191
243
|
query = RSolr::Uri.params_to_solr(opts[:params]) unless opts[:params].empty?
|
192
244
|
opts[:query] = query
|
193
245
|
if opts[:data].is_a? Hash
|
@@ -197,9 +249,20 @@ class RSolr::Client
|
|
197
249
|
end
|
198
250
|
opts[:path] = path
|
199
251
|
opts[:uri] = base_uri.merge(path.to_s + (query ? "?#{query}" : "")) if base_uri
|
252
|
+
|
253
|
+
[:open_timeout, :read_timeout, :retry_503, :retry_after_limit].each do |k|
|
254
|
+
opts[k] = @options[k]
|
255
|
+
end
|
256
|
+
|
200
257
|
opts
|
201
258
|
end
|
202
|
-
|
259
|
+
|
260
|
+
def params_with_wt(params)
|
261
|
+
return { wt: default_wt } if params.nil?
|
262
|
+
return params if params.key?(:wt) || params.key?('wt')
|
263
|
+
{ wt: default_wt }.merge(params)
|
264
|
+
end
|
265
|
+
|
203
266
|
def build_paginated_request page, per_page, path, opts
|
204
267
|
per_page = per_page.to_s.to_i
|
205
268
|
page = page.to_s.to_i-1
|
@@ -208,12 +271,7 @@ class RSolr::Client
|
|
208
271
|
opts[:params]["rows"] = per_page
|
209
272
|
build_request path, opts
|
210
273
|
end
|
211
|
-
|
212
|
-
# A mixin for used by #adapt_response
|
213
|
-
module Context
|
214
|
-
attr_accessor :request, :response
|
215
|
-
end
|
216
|
-
|
274
|
+
|
217
275
|
# This method will evaluate the :body value
|
218
276
|
# if the params[:uri].params[:wt] == :ruby
|
219
277
|
# ... otherwise, the body is returned as is.
|
@@ -228,14 +286,22 @@ class RSolr::Client
|
|
228
286
|
raise "The response does not have the correct keys => :body, :headers, :status" unless
|
229
287
|
%W(body headers status) == response.keys.map{|k|k.to_s}.sort
|
230
288
|
raise RSolr::Error::Http.new request, response unless [200,302].include? response[:status]
|
231
|
-
|
232
|
-
result
|
233
|
-
|
234
|
-
|
289
|
+
|
290
|
+
result = if respond_to? "evaluate_#{request[:params][:wt]}_response", true
|
291
|
+
send "evaluate_#{request[:params][:wt]}_response", request, response
|
292
|
+
else
|
293
|
+
response[:body]
|
294
|
+
end
|
295
|
+
|
296
|
+
if result.is_a?(Hash) || request[:method] == :head
|
297
|
+
result = RSolr::HashWithResponse.new(request, response, result)
|
298
|
+
end
|
299
|
+
|
300
|
+
result
|
235
301
|
end
|
236
|
-
|
302
|
+
|
237
303
|
protected
|
238
|
-
|
304
|
+
|
239
305
|
# converts the method name for the solr request handler path.
|
240
306
|
def method_missing name, *args
|
241
307
|
if name.to_s =~ /^paginated?_(.+)$/
|
@@ -244,7 +310,7 @@ class RSolr::Client
|
|
244
310
|
send_and_receive name, *args
|
245
311
|
end
|
246
312
|
end
|
247
|
-
|
313
|
+
|
248
314
|
# evaluates the response[:body],
|
249
315
|
# attempts to bring the ruby string to life.
|
250
316
|
# If a SyntaxError is raised, then
|
@@ -259,5 +325,18 @@ class RSolr::Client
|
|
259
325
|
raise RSolr::Error::InvalidRubyResponse.new request, response
|
260
326
|
end
|
261
327
|
end
|
262
|
-
|
328
|
+
|
329
|
+
def evaluate_json_response request, response
|
330
|
+
return response[:body] unless defined? JSON
|
331
|
+
|
332
|
+
begin
|
333
|
+
JSON.parse response[:body].to_s
|
334
|
+
rescue JSON::ParserError
|
335
|
+
raise RSolr::Error::InvalidJsonResponse.new request, response
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
def default_wt
|
340
|
+
self.options[:default_wt] || self.class.default_wt
|
341
|
+
end
|
263
342
|
end
|