mirror of https://github.com/apache/lucene.git
SOLR-111: add new response classes and enhance connection. one change i made was to make autocommit off by default and use a symbol for :on/:off
git-svn-id: https://svn.apache.org/repos/asf/incubator/solr/trunk@496871 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
b8ac946026
commit
8b963995a0
|
@ -11,28 +11,26 @@ First launch Solr.
|
|||
|
||||
In a separate shell, launch irb -Ilib.
|
||||
|
||||
# Bring in the Solr library
|
||||
require 'solr'
|
||||
# connect to the solr instance
|
||||
conn = Connection.new('http://localhost:8983/solr')
|
||||
|
||||
# Set up a connection to Solr:
|
||||
# add a document to the index
|
||||
conn.add(:id => 123, :title => 'Lucene in Action')
|
||||
|
||||
connection = Solr::Connection.new 'http://localhost:8983/solr'
|
||||
# update the document
|
||||
conn.update(:id => 123, :title => 'Solr in Action')
|
||||
|
||||
# To add a document:
|
||||
# print out the first hit in a query for 'action'
|
||||
response = conn.query('action')
|
||||
print response.hits[0]
|
||||
|
||||
doc = Solr::Document.new :id => '529', :text => 'Solr Flare in Action'
|
||||
request = Solr::Request::AddDocument.new(doc)
|
||||
connection.send(request)
|
||||
|
||||
# Commit changes:
|
||||
|
||||
connection.commit
|
||||
|
||||
# Search:
|
||||
|
||||
request = Solr::Request::Standard.new :query => 'solr flare'
|
||||
connection.send(request)
|
||||
# iterate through all the hits for 'action'
|
||||
conn.query('action') do |hit|
|
||||
puts hit
|
||||
end
|
||||
|
||||
# delete document by id
|
||||
conn.delete(123)
|
||||
|
||||
INSTALLATION
|
||||
|
||||
|
|
|
@ -14,37 +14,109 @@ require 'net/http'
|
|||
|
||||
module Solr
|
||||
class Connection
|
||||
attr_reader :url
|
||||
attr_reader :url, :autocommit
|
||||
|
||||
def initialize(url)
|
||||
# create a connection to a solr instance using the url for the solr
|
||||
# application context:
|
||||
#
|
||||
# conn = Solr::Connection.new("http://example.com:8080/solr")
|
||||
#
|
||||
# if you would prefer to issue your own commits to cut down on
|
||||
# network traffic use :autocommit => 'off'
|
||||
#
|
||||
# conn = Solr::Connection.new('http://example.com:8080/solr',
|
||||
# :autocommit => 'off')
|
||||
|
||||
def initialize(url, opts={})
|
||||
@url = URI.parse(url)
|
||||
unless @url.kind_of? URI::HTTP
|
||||
raise "invalid http url: #{url}"
|
||||
end
|
||||
@autocommit = opts[:autocommit] == :on ? true : false
|
||||
end
|
||||
|
||||
# sends a commit message
|
||||
# add a document to the index. you can pass in either a hash
|
||||
#
|
||||
# conn.add(:id => 123, :title => 'Tlon, Uqbar, Orbis Tertius')
|
||||
#
|
||||
# or a Solr::Document
|
||||
#
|
||||
# conn.add(Solr::Document.new(:id => 123, :title = 'On Writing')
|
||||
#
|
||||
# true/false will be returned to designate success/failure
|
||||
|
||||
def add(doc)
|
||||
doc = Solr::Document.new(doc)
|
||||
request = Solr::Request::AddDocument.new(doc)
|
||||
response = send(request)
|
||||
commit if @autocommit
|
||||
return response.ok?
|
||||
end
|
||||
|
||||
# update a document in the index (really just an alias to add)
|
||||
|
||||
def update(doc)
|
||||
return add(doc)
|
||||
end
|
||||
|
||||
# performs a standard query and returns a Solr::Response::Standard
|
||||
#
|
||||
# response = conn.query('borges')
|
||||
#
|
||||
# alternative you can pass in a block and iterate over hits
|
||||
#
|
||||
# conn.query('borges') do |hit|
|
||||
# puts hit
|
||||
# end
|
||||
|
||||
def query(query, options={}, &action)
|
||||
options[:query] = query
|
||||
request = Solr::Request::Standard.new(options)
|
||||
response = send(request)
|
||||
return response unless action
|
||||
response.each {|hit| action.call(hit)}
|
||||
end
|
||||
|
||||
# sends a commit message to the server
|
||||
def commit
|
||||
self.send(Solr::Request::Commit.new)
|
||||
response = send(Solr::Request::Commit.new)
|
||||
return response.ok?
|
||||
end
|
||||
|
||||
# sends a ping message
|
||||
# pings the connection and returns true/false if it is alive or not
|
||||
def ping
|
||||
begin
|
||||
response = send(Solr::Request::Ping.new)
|
||||
return response.ok?
|
||||
rescue
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# delete a document from the index using the document id
|
||||
def delete(document_id)
|
||||
response = send(Solr::Request::Delete.new(:id => document_id))
|
||||
commit if @autocommit
|
||||
return response.ok?
|
||||
end
|
||||
|
||||
# delete using a query
|
||||
def delete_by_query(query)
|
||||
response = send(Solr::Request::Delete.new(:query => query))
|
||||
commit if @autocommit
|
||||
return response.ok?
|
||||
end
|
||||
|
||||
# send a given Solr::Request and return a RubyResponse or XmlResponse
|
||||
# depending on the type of request
|
||||
def send(request)
|
||||
data = post(request)
|
||||
case request.response_format
|
||||
when :ruby
|
||||
return RubyResponse.new(data)
|
||||
when :xml
|
||||
return XmlResponse.new(data)
|
||||
else
|
||||
raise "Unknown response format: #{request.response_format}"
|
||||
end
|
||||
return Solr::Response::Base.make_response(request, data)
|
||||
end
|
||||
|
||||
# send the http post request to solr: you will want to use
|
||||
# one of the add(), query(), commit(), delete() or send()
|
||||
# instead of this...
|
||||
def post(request)
|
||||
post = Net::HTTP::Post.new(@url.path + "/" + request.handler)
|
||||
post.body = request.to_s
|
||||
|
|
|
@ -12,11 +12,10 @@
|
|||
|
||||
module Solr
|
||||
|
||||
class RequestException < Exception
|
||||
attr_reader :code, :message
|
||||
class Exception < Exception
|
||||
attr_reader :message
|
||||
|
||||
def initialize(code, message)
|
||||
@code = code
|
||||
def initialize(message)
|
||||
@message = message
|
||||
end
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
require 'solr/request/add_document'
|
||||
require 'solr/request/base'
|
||||
require 'solr/request/commit'
|
||||
require 'solr/request/delete'
|
||||
require 'solr/request/ping'
|
||||
require 'solr/request/select'
|
||||
require 'solr/request/standard'
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
require 'rexml/document'
|
||||
|
||||
module Solr
|
||||
module Request
|
||||
|
||||
class Delete < Solr::Request::Update
|
||||
|
||||
# A delete request can be for a specific document id
|
||||
#
|
||||
# request = Solr::Request::Delete.new(:id => 1234)
|
||||
#
|
||||
# or by query:
|
||||
#
|
||||
# request = Solr::Request::Delete.new(:query =>
|
||||
#
|
||||
def initialize(options)
|
||||
unless options.kind_of?(Hash) and (options[:id] or options[:query])
|
||||
raise Solr::Exception.new("must pass in :id or :query")
|
||||
end
|
||||
if options[:id] and options[:query]
|
||||
raise Solr::Exception.new("can't pass in both :id and :query")
|
||||
end
|
||||
@document_id = options[:id]
|
||||
@query = options[:query]
|
||||
end
|
||||
|
||||
def to_s
|
||||
delete_element = REXML::Element.new('delete')
|
||||
if @document_id
|
||||
id_element = REXML::Element.new('id')
|
||||
id_element.text = @document_id
|
||||
delete_element.add_element(id_element)
|
||||
elsif @query
|
||||
query = REXML::Element.new('query')
|
||||
query.text = @query
|
||||
delete_element.add_element(query)
|
||||
end
|
||||
return delete_element.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
module Solr
|
||||
module Request
|
||||
|
||||
# a parent class for all requests that go through the solr update handler
|
||||
class Update < Solr::Request::Base
|
||||
def response_format
|
||||
:xml
|
||||
|
|
|
@ -10,32 +10,11 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module Solr
|
||||
class Response
|
||||
attr_reader :header, :raw_response, :data, :parsed_response
|
||||
def initialize(body)
|
||||
@raw_response = body
|
||||
if match = /^<result status="(\d+)"/.match(body)
|
||||
unless 0 == match.captures.first.to_i
|
||||
error = REXML::Document.new(body).root
|
||||
raise RequestException.new(error.attributes["status"], error.text)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class RubyResponse < Response
|
||||
def initialize(body)
|
||||
super(body)
|
||||
@parsed_response = eval(body)
|
||||
@header = parsed_response['responseHeader']
|
||||
@data = parsed_response['response']
|
||||
end
|
||||
end
|
||||
|
||||
class XmlResponse < Response
|
||||
def initialize(body)
|
||||
super(body)
|
||||
end
|
||||
end
|
||||
end
|
||||
require 'solr/response/base'
|
||||
require 'solr/response/xml'
|
||||
require 'solr/response/ruby'
|
||||
require 'solr/response/ping'
|
||||
require 'solr/response/add_document'
|
||||
require 'solr/response/standard'
|
||||
require 'solr/response/commit'
|
||||
require 'solr/response/delete'
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
module Solr
|
||||
module Response
|
||||
|
||||
class AddDocument < Solr::Response::Xml
|
||||
def initialize(xml)
|
||||
super(xml)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
module Solr
|
||||
module Response
|
||||
class Base
|
||||
attr_reader :raw_response
|
||||
|
||||
def initialize(raw_response)
|
||||
@raw_response = raw_response
|
||||
end
|
||||
|
||||
# factory method for creating a Solr::Response::* from
|
||||
# a request and the raw response content
|
||||
def self.make_response(request, raw)
|
||||
|
||||
# make sure response format seems sane
|
||||
unless [:xml, :ruby].include?(request.response_format)
|
||||
raise Solr::Exception.new("unknown response format: #{request.response_format}" )
|
||||
end
|
||||
|
||||
case request
|
||||
when Solr::Request::Ping
|
||||
return Solr::Response::Ping.new(raw)
|
||||
when Solr::Request::AddDocument
|
||||
return Solr::Response::AddDocument.new(raw)
|
||||
when Solr::Request::Commit
|
||||
return Solr::Response::Commit.new(raw)
|
||||
when Solr::Request::Standard
|
||||
return Solr::Response::Standard.new(raw)
|
||||
when Solr::Request::Delete
|
||||
return Solr::Response::Delete.new(raw)
|
||||
else
|
||||
raise Solr::Exception.new("unknown request type: #{request.class}")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
require 'rexml/xpath'
|
||||
|
||||
module Solr
|
||||
module Response
|
||||
class Commit < Solr::Response::Xml
|
||||
attr_reader :ok
|
||||
|
||||
def initialize(xml)
|
||||
super(xml)
|
||||
e = REXML::XPath.first(@doc, './result')
|
||||
if e and e.attributes['status'] == '0'
|
||||
@ok = true
|
||||
else
|
||||
@ok = false
|
||||
end
|
||||
end
|
||||
|
||||
def ok?
|
||||
@ok
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
module Solr
|
||||
module Response
|
||||
class Delete < Solr::Response::Xml
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,20 @@
|
|||
require 'rexml/xpath'
|
||||
|
||||
module Solr
|
||||
module Response
|
||||
class Ping < Solr::Response::Xml
|
||||
|
||||
def initialize(xml)
|
||||
super(xml)
|
||||
@ok = REXML::XPath.first(@doc, './solr/ping') ? true : false
|
||||
end
|
||||
|
||||
# returns true or false depending on whether the ping
|
||||
# was successful or not
|
||||
def ok?
|
||||
@ok
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,32 @@
|
|||
module Solr
|
||||
module Response
|
||||
|
||||
class Ruby < Solr::Response::Base
|
||||
attr_reader :data
|
||||
|
||||
def initialize(ruby_code)
|
||||
super(ruby_code)
|
||||
begin
|
||||
@data = eval(ruby_code)
|
||||
@header = @data['responseHeader']
|
||||
@response = @data['response']
|
||||
raise "response should be a hash" unless @data.kind_of? Hash
|
||||
raise "response header missing" unless @header.kind_of? Hash
|
||||
raise "response section missing" unless @response.kind_of? Hash
|
||||
rescue Exception => e
|
||||
raise Solr::Exception.new("invalid ruby code: #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
def ok?
|
||||
return @header['status'] == 0
|
||||
end
|
||||
|
||||
def query_time
|
||||
return @header['QTime']
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
module Solr
|
||||
module Response
|
||||
class Standard < Solr::Response::Ruby
|
||||
include Enumerable
|
||||
|
||||
def initialize(ruby_code)
|
||||
super(ruby_code)
|
||||
end
|
||||
|
||||
def total_hits
|
||||
return @response['numFound']
|
||||
end
|
||||
|
||||
def start
|
||||
return @response['start']
|
||||
end
|
||||
|
||||
def hits
|
||||
return @response['docs']
|
||||
end
|
||||
|
||||
def max_score
|
||||
return @response['maxScore']
|
||||
end
|
||||
|
||||
# supports enumeration of hits
|
||||
def each
|
||||
@response['docs'].each {|hit| yield hit}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,33 @@
|
|||
require 'rexml/document'
|
||||
require 'solr/exception'
|
||||
|
||||
module Solr
|
||||
module Response
|
||||
|
||||
class Xml < Solr::Response::Base
|
||||
attr_reader :doc, :status_code, :status_message
|
||||
|
||||
def initialize(xml)
|
||||
super(xml)
|
||||
begin
|
||||
# parse the xml
|
||||
@doc = REXML::Document.new(xml)
|
||||
# look for the result code and string
|
||||
result = REXML::XPath.first(@doc, './result')
|
||||
if result
|
||||
@status_code = result.attributes['status']
|
||||
@status_message = result.text
|
||||
end
|
||||
rescue REXML::ParseException => e
|
||||
raise Solr::Exception.new("invalid response xml: #{e}")
|
||||
end
|
||||
end
|
||||
|
||||
def ok?
|
||||
return @status_code == '0'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue