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.
|
In a separate shell, launch irb -Ilib.
|
||||||
|
|
||||||
# Bring in the Solr library
|
# connect to the solr instance
|
||||||
require 'solr'
|
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'
|
# iterate through all the hits for 'action'
|
||||||
request = Solr::Request::AddDocument.new(doc)
|
conn.query('action') do |hit|
|
||||||
connection.send(request)
|
puts hit
|
||||||
|
end
|
||||||
# Commit changes:
|
|
||||||
|
|
||||||
connection.commit
|
|
||||||
|
|
||||||
# Search:
|
|
||||||
|
|
||||||
request = Solr::Request::Standard.new :query => 'solr flare'
|
|
||||||
connection.send(request)
|
|
||||||
|
|
||||||
|
# delete document by id
|
||||||
|
conn.delete(123)
|
||||||
|
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
|
|
||||||
|
|
|
@ -14,37 +14,109 @@ require 'net/http'
|
||||||
|
|
||||||
module Solr
|
module Solr
|
||||||
class Connection
|
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)
|
@url = URI.parse(url)
|
||||||
unless @url.kind_of? URI::HTTP
|
unless @url.kind_of? URI::HTTP
|
||||||
raise "invalid http url: #{url}"
|
raise "invalid http url: #{url}"
|
||||||
end
|
end
|
||||||
|
@autocommit = opts[:autocommit] == :on ? true : false
|
||||||
end
|
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
|
def commit
|
||||||
self.send(Solr::Request::Commit.new)
|
response = send(Solr::Request::Commit.new)
|
||||||
|
return response.ok?
|
||||||
end
|
end
|
||||||
|
|
||||||
# sends a ping message
|
# pings the connection and returns true/false if it is alive or not
|
||||||
def ping
|
def ping
|
||||||
|
begin
|
||||||
response = send(Solr::Request::Ping.new)
|
response = send(Solr::Request::Ping.new)
|
||||||
|
return response.ok?
|
||||||
|
rescue
|
||||||
|
return false
|
||||||
|
end
|
||||||
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)
|
def send(request)
|
||||||
data = post(request)
|
data = post(request)
|
||||||
case request.response_format
|
return Solr::Response::Base.make_response(request, data)
|
||||||
when :ruby
|
|
||||||
return RubyResponse.new(data)
|
|
||||||
when :xml
|
|
||||||
return XmlResponse.new(data)
|
|
||||||
else
|
|
||||||
raise "Unknown response format: #{request.response_format}"
|
|
||||||
end
|
|
||||||
end
|
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)
|
def post(request)
|
||||||
post = Net::HTTP::Post.new(@url.path + "/" + request.handler)
|
post = Net::HTTP::Post.new(@url.path + "/" + request.handler)
|
||||||
post.body = request.to_s
|
post.body = request.to_s
|
||||||
|
|
|
@ -12,11 +12,10 @@
|
||||||
|
|
||||||
module Solr
|
module Solr
|
||||||
|
|
||||||
class RequestException < Exception
|
class Exception < Exception
|
||||||
attr_reader :code, :message
|
attr_reader :message
|
||||||
|
|
||||||
def initialize(code, message)
|
def initialize(message)
|
||||||
@code = code
|
|
||||||
@message = message
|
@message = message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
require 'solr/request/add_document'
|
require 'solr/request/add_document'
|
||||||
require 'solr/request/base'
|
require 'solr/request/base'
|
||||||
require 'solr/request/commit'
|
require 'solr/request/commit'
|
||||||
|
require 'solr/request/delete'
|
||||||
require 'solr/request/ping'
|
require 'solr/request/ping'
|
||||||
require 'solr/request/select'
|
require 'solr/request/select'
|
||||||
require 'solr/request/standard'
|
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 Solr
|
||||||
module Request
|
module Request
|
||||||
|
|
||||||
|
# a parent class for all requests that go through the solr update handler
|
||||||
class Update < Solr::Request::Base
|
class Update < Solr::Request::Base
|
||||||
def response_format
|
def response_format
|
||||||
:xml
|
:xml
|
||||||
|
|
|
@ -10,32 +10,11 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
module Solr
|
require 'solr/response/base'
|
||||||
class Response
|
require 'solr/response/xml'
|
||||||
attr_reader :header, :raw_response, :data, :parsed_response
|
require 'solr/response/ruby'
|
||||||
def initialize(body)
|
require 'solr/response/ping'
|
||||||
@raw_response = body
|
require 'solr/response/add_document'
|
||||||
if match = /^<result status="(\d+)"/.match(body)
|
require 'solr/response/standard'
|
||||||
unless 0 == match.captures.first.to_i
|
require 'solr/response/commit'
|
||||||
error = REXML::Document.new(body).root
|
require 'solr/response/delete'
|
||||||
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
|
|
||||||
|
|
|
@ -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