rsolr 1.0.8 → 1.1.2
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.
- 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
|