class Asari
Constants
- VERSION
Attributes
Public Class Methods
# File lib/asari.rb, line 14 def self.mode @@mode end
# File lib/asari.rb, line 18 def self.mode=(mode) @@mode = mode end
# File lib/asari.rb, line 26 def initialize(search_domain=nil, aws_region=nil) @search_domain = search_domain @aws_region = aws_region end
Public Instance Methods
Public: Add an item to the index with the given ID.
id - the ID to associate with this document fields - a hash of the data to associate with this document. This needs to match the search fields defined in your CloudSearch domain.
Examples:
@asari.update_item("4", { :name => "Party Pooper", :email => ..., ... }) #=> nil
Returns: nil if the request is successful.
Raises: DocumentUpdateException
if there's an issue communicating the
request to the server.
# File lib/asari.rb, line 126 def add_item(id, fields) return nil if self.class.mode == :sandbox query = { "type" => "add", "id" => id.to_s, "version" => Time.now.to_i, "lang" => "en" } fields.each do |k,v| fields[k] = convert_date_or_time(fields[k]) fields[k] = "" if v.nil? end query["fields"] = fields doc_request(query) end
Public: returns the current api_version
, or the sensible default of “2011-02-01” (at the time of writing, the current version of the CloudSearch API).
# File lib/asari.rb, line 42 def api_version @api_version || "2011-02-01" end
Public: returns the current aws_region
, or the sensible default of “us-east-1.”
# File lib/asari.rb, line 48 def aws_region @aws_region || "us-east-1" end
Internal: helper method: common logic for queries against the doc endpoint.
# File lib/asari.rb, line 179 def doc_request(query) endpoint = "http://doc-#{search_domain}.#{aws_region}.cloudsearch.amazonaws.com/#{api_version}/documents/batch" options = { :body => [query].to_json, :headers => { "Content-Type" => "application/json"} } begin response = HTTParty.post(endpoint, options) rescue Exception => e ae = Asari::DocumentUpdateException.new("#{e.class}: #{e.message}") ae.set_backtrace e.backtrace raise ae end unless response.response.code == "200" raise Asari::DocumentUpdateException.new("#{response.response.code}: #{response.response.msg}") end nil end
Public: Remove an item from the index based on its document ID.
Examples:
@asari.search("fritters") #=> ["13","28"] @asari.remove_item("13") #=> nil @asari.search("fritters") #=> ["28"] @asari.remove_item("13") #=> nil
Returns: nil if the request is successful (note that asking the index to
delete an item that's not present in the index is still a successful request).
Raises: DocumentUpdateException
if there's an issue communicating the
request to the server.
# File lib/asari.rb, line 170 def remove_item(id) return nil if self.class.mode == :sandbox query = { "type" => "delete", "id" => id.to_s, "version" => Time.now.to_i } doc_request query end
Public: Search for the specified term.
Examples:
@asari.search("fritters") #=> ["13","28"] @asari.search(filter: { and: { type: 'donuts' }}) #=> ["13,"28","35","50"] @asari.search(filter: "(or type:'donut' type:'bagel')") #=> ["13,"28","35","50", "80"] @asari.search("fritters", filter: { and: { type: 'donuts' }}) #=> ["13"]
Returns: An Asari::Collection
containing all document IDs in the system that match the
specified search term. If no results are found, an empty Asari::Collection is returned.
Raises: SearchException
if there's an issue communicating the request to
the server.
# File lib/asari.rb, line 67 def search(term, options = {}) return Asari::Collection.sandbox_fake if self.class.mode == :sandbox term,options = "",term if term.is_a?(Hash) and options.empty? bq = if options[:filter] if options[:filter].is_a?(String) options[:filter] else boolean_query(options[:filter]) end end page_size = options[:page_size].nil? ? 10 : options[:page_size].to_i url = "http://search-#{search_domain}.#{aws_region}.cloudsearch.amazonaws.com/#{api_version}/search" url += "?q=#{CGI.escape(term.to_s)}" url += "&bq=#{CGI.escape(bq)}" if options[:filter] url += "&size=#{page_size}" url += "&return-fields=#{options[:return_fields].join ','}" if options[:return_fields] if options[:page] start = (options[:page].to_i - 1) * page_size url << "&start=#{start}" end if options[:rank] rank = normalize_rank(options[:rank]) url << "&rank=#{rank}" end begin response = HTTParty.get(url) rescue Exception => e ae = Asari::SearchException.new("#{e.class}: #{e.message} (#{url})") ae.set_backtrace e.backtrace raise ae end unless response.response.code == "200" raise Asari::SearchException.new("#{response.response.code}: #{response.response.msg} (#{url})") end Asari::Collection.new(response, page_size) end
Public: returns the current search_domain
, or raises a MissingSearchDomainException
.
# File lib/asari.rb, line 34 def search_domain @search_domain || raise(MissingSearchDomainException.new) end
Public: Update an item in the index based on its document ID.
Note: As of right now, this is the same method call in CloudSearch that's utilized for adding items. This method is here to provide a consistent interface in case that changes.
Examples:
@asari.update_item("4", { :name => "Party Pooper", :email => ..., ... }) #=> nil
Returns: nil if the request is successful.
Raises: DocumentUpdateException
if there's an issue communicating the
request to the server.
# File lib/asari.rb, line 152 def update_item(id, fields) add_item(id, fields) end
Protected Instance Methods
Private: Builds the query from a passed hash
terms - a hash of the search query. %w(and or not) are reserved hash keys that build the logic of the query
# File lib/asari.rb, line 205 def boolean_query(terms = {}, options = {}) reduce = lambda { |hash| hash.reduce("") do |memo, (key, value)| if %w(and or not).include?(key.to_s) && value.is_a?(Hash) sub_query = reduce.call(value) memo += " (#{key}#{sub_query})" unless sub_query.empty? else if value.is_a?(Range) || value.is_a?(Integer) memo += " #{key}:#{value}" elsif value.is_a?(String) && value =~ /\A\d*\.\.\d*\Z/ memo += " #{key}:#{value}" elsif !value.to_s.empty? memo += " #{key}:'#{value.to_s}'" end end memo end } reduce.call(terms) end
# File lib/asari.rb, line 232 def convert_date_or_time(obj) return obj unless [Time, Date, DateTime].include?(obj.class) obj.to_time.to_i end
# File lib/asari.rb, line 226 def normalize_rank(rank) rank = Array(rank) rank << :asc if rank.size < 2 rank[1] == :desc ? "-#{rank[0]}" : rank[0] end