Class: RSolr::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/rsolr/client.rb

Constant Summary collapse

DEFAULT_URL =
'http://127.0.0.1:8983/solr/'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, options = {}) ⇒ Client

Returns a new instance of Client.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rsolr/client.rb', line 22

def initialize connection, options = {}
  @proxy = @uri = nil
  @connection = connection
  unless false === options[:url]
    @uri = extract_url_from_options(options)
    if options[:proxy]
      proxy_url = options[:proxy].dup
      proxy_url << "/" unless proxy_url.nil? or proxy_url[-1] == ?/
      @proxy = ::URI.parse proxy_url if proxy_url
    elsif options[:proxy] == false
      @proxy = false  # used to avoid setting the proxy from the environment.
    end
  end
  @update_format = options.delete(:update_format) || RSolr::JSON::Generator
  @update_path = options.fetch(:update_path, 'update')
  @options = options

  if options[:read_timeout]
    warn "DEPRECATION: Rsolr.new/connect option `read_timeout` is deprecated and will be removed in Rsolr 3. `timeout` is currently a synonym, use that instead."
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object (protected)

converts the method name for the solr request handler path.



340
341
342
343
344
345
346
# File 'lib/rsolr/client.rb', line 340

def method_missing name, *args
  if name.to_s =~ /^paginated?_(.+)$/
    paginate args[0], args[1], $1, *args[2..-1]
  else
    send_and_receive name, *args
  end
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



20
21
22
# File 'lib/rsolr/client.rb', line 20

def options
  @options
end

#proxyObject (readonly)

Returns the value of attribute proxy.



20
21
22
# File 'lib/rsolr/client.rb', line 20

def proxy
  @proxy
end

#update_formatObject (readonly)

Returns the value of attribute update_format.



20
21
22
# File 'lib/rsolr/client.rb', line 20

def update_format
  @update_format
end

#update_pathObject (readonly)

Returns the value of attribute update_path.



20
21
22
# File 'lib/rsolr/client.rb', line 20

def update_path
  @update_path
end

#uriObject (readonly)

Returns the value of attribute uri.



20
21
22
# File 'lib/rsolr/client.rb', line 20

def uri
  @uri
end

Class Method Details

.default_wtObject



11
12
13
# File 'lib/rsolr/client.rb', line 11

def default_wt
  @default_wt ||= :json
end

.default_wt=(value) ⇒ Object



15
16
17
# File 'lib/rsolr/client.rb', line 15

def default_wt= value
  @default_wt = value
end

Instance Method Details

#adapt_response(request, response) ⇒ Object

This method will evaluate the :body value if the params.params == :ruby … otherwise, the body is returned as is. The return object has methods attached, :request and :response. These methods give you access to the original request and response from the connection.

adapt_response will raise an InvalidRubyResponse if :wt == :ruby and the body couldn’t be evaluated.



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/rsolr/client.rb', line 284

def adapt_response request, response
  raise "The response does not have the correct keys => :body, :headers, :status" unless
    %W(body headers status) == response.keys.map{|k|k.to_s}.sort

  result = if respond_to? "evaluate_#{request[:params][:wt]}_response", true
    send "evaluate_#{request[:params][:wt]}_response", request, response
  else
    response[:body]
  end

  if result.is_a?(Hash) || request[:method] == :head
    result = RSolr::HashWithResponse.new(request, response, result)
  end

  result
end

#add(doc, opts = {}) ⇒ Object

add creates xml “add” documents and sends the xml data to the update method

wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update

single record: solr.add(:id=>1, :name=>‘one’)

add using an array

solr.add(

[{:id=>1, :name=>'one'}, {:id=>2, :name=>'two'}],
:add_attributes => {:boost=>5.0, :commitWithin=>10}

)



115
116
117
118
# File 'lib/rsolr/client.rb', line 115

def add doc, opts = {}
  add_attributes = opts.delete :add_attributes
  update opts.merge(:data => builder.add(doc, add_attributes))
end

#base_request_uriObject

returns the request uri object.



54
55
56
# File 'lib/rsolr/client.rb', line 54

def base_request_uri
  base_uri.request_uri if base_uri
end

#base_uriObject

returns the URI uri object.



59
60
61
# File 'lib/rsolr/client.rb', line 59

def base_uri
  @uri
end

#build_paginated_request(page, per_page, path, opts) ⇒ Object



265
266
267
268
269
270
271
272
# File 'lib/rsolr/client.rb', line 265

def build_paginated_request page, per_page, path, opts
  per_page = per_page.to_s.to_i
  page = page.to_s.to_i-1
  page = page < 1 ? 0 : page
  opts[:params]["start"] = page * per_page
  opts[:params]["rows"] = per_page
  build_request path, opts
end

#build_request(path, opts) ⇒ Object

build_request accepts a path and options hash, then prepares a normalized hash to return for sending to a solr connection driver. build_request sets up the uri/query string and converts the data arg to form-urlencoded, if the data arg is a hash. returns a hash with the following keys:

:method
:params
:headers
:data
:uri
:path
:query


239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/rsolr/client.rb', line 239

def build_request path, opts
  raise "path must be a string or symbol, not #{path.inspect}" unless [String,Symbol].include?(path.class)
  path = path.to_s
  opts[:proxy] = proxy unless proxy.nil?
  opts[:method] ||= :get
  raise "The :data option can only be used if :method => :post" if opts[:method] != :post and opts[:data]
  opts[:params] = params_with_wt(opts[:params])
  query = RSolr::Uri.params_to_solr(opts[:params]) unless opts[:params].empty?
  opts[:query] = query
  if opts[:data].is_a? Hash
    opts[:data] = RSolr::Uri.params_to_solr opts[:data]
    opts[:headers] ||= {}
    opts[:headers]['Content-Type'] ||= 'application/x-www-form-urlencoded; charset=UTF-8'
  end
  opts[:path] = path
  opts[:uri] = base_uri.merge(path.to_s + (query ? "?#{query}" : "")) if base_uri

  opts
end

#builderObject



172
173
174
175
176
177
178
179
180
181
182
# File 'lib/rsolr/client.rb', line 172

def builder
  @builder ||= if update_format.is_a? Class
                 update_format.new
               elsif update_format == :json
                 RSolr::JSON::Generator.new
               elsif update_format == :xml
                 RSolr::Xml::Generator.new
               else
                 update_format
               end
end

#commit(opts = {}) ⇒ Object



124
125
126
127
# File 'lib/rsolr/client.rb', line 124

def commit opts = {}
  commit_attrs = opts.delete :commit_attributes
  update opts.merge(:data => builder.commit( commit_attrs ))
end

#connectionObject



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/rsolr/client.rb', line 301

def connection
  @connection ||= begin
    conn_opts = { request: {} }
    conn_opts[:url] = uri.to_s
    conn_opts[:proxy] = proxy if proxy
    conn_opts[:request][:open_timeout] = options[:open_timeout] if options[:open_timeout]

    if options[:read_timeout] || options[:timeout]
      # read_timeout was being passed to faraday as timeout since Rsolr 2.0,
      # it's now deprecated, just use `timeout` directly.
      conn_opts[:request][:timeout] = options[:timeout] || options[:read_timeout]
    end

    conn_opts[:request][:params_encoder] = Faraday::FlatParamsEncoder

    Faraday.new(conn_opts) do |conn|
      if uri.user && uri.password
        case Faraday::VERSION
        when /^0/
          conn.basic_auth uri.user, uri.password
        when /^1/
          conn.request :basic_auth, uri.user, uri.password
        else
          conn.request :authorization, :basic_auth, uri.user, uri.password
        end
      end

      conn.response :raise_error
      conn.request :retry, max: options[:retry_after_limit], interval: 0.05,
                           interval_randomness: 0.5, backoff_factor: 2,
                           exceptions: ['Faraday::Error', 'Timeout::Error'] if options[:retry_503]
      conn.adapter options[:adapter] || Faraday.default_adapter || :net_http
    end
  end
end

#delete_by_id(id, opts = {}) ⇒ Object

Delete one or many documents by id

solr.delete_by_id 10
solr.delete_by_id([12, 41, 199])


158
159
160
# File 'lib/rsolr/client.rb', line 158

def delete_by_id id, opts = {}
  update opts.merge(:data => builder.delete_by_id(id))
end

#delete_by_query(query, opts = {}) ⇒ Object

delete one or many documents by query.

wiki.apache.org/solr/UpdateXmlMessages#A.22delete.22_by_ID_and_by_Query

solr.delete_by_query 'available:0'
solr.delete_by_query ['quantity:0', 'manu:"FQ"']


168
169
170
# File 'lib/rsolr/client.rb', line 168

def delete_by_query query, opts = {}
  update opts.merge(:data => builder.delete_by_query(query))
end

#execute(request_context) ⇒ Object



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/rsolr/client.rb', line 207

def execute request_context
  raw_response = begin
    response = connection.send(request_context[:method], request_context[:uri].to_s) do |req|
      req.body = request_context[:data] if request_context[:method] == :post and request_context[:data]
      req.headers.merge!(request_context[:headers]) if request_context[:headers]
    end

    { status: response.status.to_i, headers: response.headers, body: response.body.force_encoding('utf-8') }
  rescue Faraday::TimeoutError => e
    raise RSolr::Error::Timeout.new(request_context, e.response)
  rescue Errno::ECONNREFUSED, defined?(Faraday::ConnectionFailed) ? Faraday::ConnectionFailed : Faraday::Error::ConnectionFailed
    raise RSolr::Error::ConnectionRefused.new(request_context)
  rescue Faraday::Error => e
    raise RSolr::Error::Http.new(request_context, e.response)
  end
  adapt_response(request_context, raw_response) unless raw_response.nil?
end

#extract_url_from_options(options) ⇒ Object

Raises:

  • (ArgumentError)


44
45
46
47
48
49
50
51
# File 'lib/rsolr/client.rb', line 44

def extract_url_from_options(options)
  url = options[:url] ? options[:url].dup : DEFAULT_URL
  url << "/" unless url[-1] == ?/
  uri = ::URI.parse(url)
  # URI::HTTPS is a subclass of URI::HTTP, so this check accepts HTTP(S)
  raise ArgumentError, "You must provide an HTTP(S) url." unless uri.kind_of?(URI::HTTP)
  uri
end

#optimize(opts = {}) ⇒ Object



141
142
143
144
# File 'lib/rsolr/client.rb', line 141

def optimize opts = {}
  optimize_attributes = opts.delete :optimize_attributes
  update opts.merge(:data => builder.optimize(optimize_attributes))
end

#paginate(page, per_page, path, opts = nil) ⇒ Object

A paginated request method. Converts the page and per_page arguments into “rows” and “start”.



75
76
77
78
79
80
# File 'lib/rsolr/client.rb', line 75

def paginate page, per_page, path, opts = nil
  opts ||= {}
  opts[:params] ||= {}
  raise "'rows' or 'start' params should not be set when using +paginate+" if ["start", "rows"].include?(opts[:params].keys)
  execute build_paginated_request(page, per_page, path, opts)
end

#params_with_wt(params) ⇒ Object



259
260
261
262
263
# File 'lib/rsolr/client.rb', line 259

def params_with_wt(params)
  return { wt: default_wt } if params.nil?
  return params if params.key?(:wt) || params.key?('wt')
  { wt: default_wt }.merge(params)
end

#rollback(opts = {}) ⇒ Object

send </rollback>

wiki.apache.org/solr/UpdateXmlMessages#A.22rollback.22

NOTE: solr 1.4 only



151
152
153
# File 'lib/rsolr/client.rb', line 151

def rollback opts = {}
  update opts.merge(:data => builder.rollback)
end

#send_and_receive(path, opts) ⇒ Object

send_and_receive is the main request method responsible for sending requests to the connection object.

“path” : A string value that usually represents a solr request handler “opts” : A hash, which can contain the following keys:

:method : required - the http method (:get, :post or :head)
:params : optional - the query string params in hash form
:data : optional - post data -- if a hash is given, it's sent as "application/x-www-form-urlencoded; charset=UTF-8"
:headers : optional - hash of request headers

All other options are passed right along to the connection’s send_and_receive method (:get, :post, or :head)

send_and_receive returns either a string or hash on a successful ruby request. When the :params => :ruby, the response will be a hash, else a string.

creates a request context hash, sends it to the connection’s execute method which returns a simple hash, then passes the request/response into adapt_response.



201
202
203
204
# File 'lib/rsolr/client.rb', line 201

def send_and_receive path, opts
  request_context = build_request path, opts
  execute request_context
end

#soft_commit(opts = {}) ⇒ Object



133
134
135
# File 'lib/rsolr/client.rb', line 133

def soft_commit opts = {}
  commit(opts.merge params: { softCommit: true })
end

#update(opts = {}) ⇒ Object

POST XML messages to /update with optional params.

wiki.apache.org/solr/UpdateXmlMessages#add.2BAC8-update

If not set, opts will be set to a hash with the key ‘Content-Type’ set to ‘text/xml’

opts can/should contain:

:data - posted data
:headers - http headers
:params - solr query parameter hash


95
96
97
98
99
# File 'lib/rsolr/client.rb', line 95

def update opts = {}
  opts[:headers] ||= {}
  opts[:headers]['Content-Type'] ||= builder.content_type
  post opts.fetch(:path, update_path), opts
end