diff --git a/client/ruby/solrb/README b/client/ruby/solrb/README index 3ecdb736cef..f3dc627b7ab 100644 --- a/client/ruby/solrb/README +++ b/client/ruby/solrb/README @@ -6,33 +6,31 @@ USAGE First launch Solr. - cd solr - java -jar start.jar + cd solr + java -jar start.jar 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 diff --git a/client/ruby/solrb/lib/solr/connection.rb b/client/ruby/solrb/lib/solr/connection.rb index 9a271bf4824..aaafb6db7b4 100755 --- a/client/ruby/solrb/lib/solr/connection.rb +++ b/client/ruby/solrb/lib/solr/connection.rb @@ -14,37 +14,109 @@ require 'net/http' module Solr class Connection - attr_reader :url + attr_reader :url, :autocommit + + # 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) + 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 - response = send(Solr::Request::Ping.new) - end - - 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}" + 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) + 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 diff --git a/client/ruby/solrb/lib/solr/exception.rb b/client/ruby/solrb/lib/solr/exception.rb index 235e20e6b9c..cd501cb2292 100644 --- a/client/ruby/solrb/lib/solr/exception.rb +++ b/client/ruby/solrb/lib/solr/exception.rb @@ -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 @@ -26,4 +25,4 @@ module Solr end -end \ No newline at end of file +end diff --git a/client/ruby/solrb/lib/solr/request.rb b/client/ruby/solrb/lib/solr/request.rb index 01795ea1605..a01d849763f 100755 --- a/client/ruby/solrb/lib/solr/request.rb +++ b/client/ruby/solrb/lib/solr/request.rb @@ -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' diff --git a/client/ruby/solrb/lib/solr/request/delete.rb b/client/ruby/solrb/lib/solr/request/delete.rb new file mode 100644 index 00000000000..4386b4352b6 --- /dev/null +++ b/client/ruby/solrb/lib/solr/request/delete.rb @@ -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 + diff --git a/client/ruby/solrb/lib/solr/request/update.rb b/client/ruby/solrb/lib/solr/request/update.rb index 11b4dd11972..9334d46a663 100644 --- a/client/ruby/solrb/lib/solr/request/update.rb +++ b/client/ruby/solrb/lib/solr/request/update.rb @@ -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 diff --git a/client/ruby/solrb/lib/solr/response.rb b/client/ruby/solrb/lib/solr/response.rb index 00d5362d917..6394c592e10 100755 --- a/client/ruby/solrb/lib/solr/response.rb +++ b/client/ruby/solrb/lib/solr/response.rb @@ -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 = /^ 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 diff --git a/client/ruby/solrb/lib/solr/response/standard.rb b/client/ruby/solrb/lib/solr/response/standard.rb new file mode 100644 index 00000000000..dd5efa0fb7c --- /dev/null +++ b/client/ruby/solrb/lib/solr/response/standard.rb @@ -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 diff --git a/client/ruby/solrb/lib/solr/response/xml.rb b/client/ruby/solrb/lib/solr/response/xml.rb new file mode 100644 index 00000000000..a14f1b955f6 --- /dev/null +++ b/client/ruby/solrb/lib/solr/response/xml.rb @@ -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