require 'json'
require 'restclient'
module RailsConnector
# This class provides a basic implementation for accessing a elasticsearch server.
# It can be activated by making it the superclass of SearchRequest.
# It should be customized by subclassing.
class ElasticsearchRequest
# Takes +query_string+ and +options+ for accessing Elasticsearch.
#
# +options+ is a hash and may include:
#
# :limit:: The maximum number of hits
# :offset:: The search offset
# :url:: A non-default Elasticsearch index URL
def initialize(query_string, options = {})
@query_string = query_string
@options = Configuration.search_options.merge(options)
end
# Accesses Elasticsearch using #query and fetches search hits.
def fetch_hits
the_request = request_body
(the_request[:fields] ||= []) << :obj_id
the_request[:fields].uniq!
the_request[:from] = @options[:offset] if @options[:offset]
the_request[:size] = @options[:limit] if @options[:limit]
hits = JSON.parse(
RestClient::Request.execute(:method => :get, :url => url, :payload => the_request.to_json)
)['hits']
result = SES::SearchResult.new(hits['total'])
hits['hits'].each do |hit|
result << SES::Hit.new(hit['fields']['obj_id'], hit['_score'] / hits['max_score'], hit)
end
result
end
def request_body
{
:query => query,
:filter => filter
}
end
def query
{
:query_string => {
:query => @query_string.
gsub(/[^\w\*]/, ' ').
gsub(/\b(and|or|not)\b/i, '').
gsub(/\s+/, ' ').strip
}
}
end
def filter
now = Time.now
{
:and => [
{:not => {:term => {:obj_type => :image}}},
{:not => {:term => {:suppress_export => true}}},
{:not => {:range => {:valid_from => {:from => (now + 1.second).to_iso, :to => '*'}}}},
{:not => {:range => {:valid_until => {:from => '*', :to => now.to_iso}}}}
]
}
end
private
def url
"#{@options[:url]}/_search"
end
end
end