Created
February 6, 2011 14:17
-
-
Save karmi/813387 to your computer and use it in GitHub Desktop.
Sketch of a Ruby API for ElasticSearch [http://elasticsearch.com]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Sketch of a Ruby API for ElasticSearch [http://elasticsearch.com] | |
require 'rubygems' | |
require 'curb' | |
require 'rest_client' | |
require 'yajl/json_gem' | |
module Slingshot | |
def http | |
@http ||= Client.new | |
end; module_function :http | |
def search(indices, &block) | |
@search = Search.new(indices, &block) | |
@results = Results.new(@search) | |
end | |
def index(name, &block) | |
@index = Index.new(name, &block) | |
end | |
def mapping | |
raise NoMethodError, "TODO" | |
end | |
class Client | |
def post(url, data) | |
# Curl::Easy.http_post( url, data).body_str | |
RestClient.post url, data | |
end | |
def delete(url) | |
# Curl::Easy.http_delete(url).body_str rescue nil | |
RestClient.delete url rescue nil | |
end | |
end | |
class Results | |
include Enumerable | |
attr_reader :query, :curl, :time, :total, :results, :facets | |
def initialize(search) | |
response = JSON.parse( Slingshot.http.post("http://localhost:9200/#{search.indices}/_search", search.to_json) ) | |
@query = search.to_json | |
@curl = %Q|curl -X POST "http://localhost:9200/#{search.indices}/_search?pretty=true" -d '#{@query}'| | |
@time = response['took'] | |
@total = response['hits']['total'] | |
@results = response['hits']['hits'] | |
@facets = response['facets'] | |
end | |
def each(&block) | |
@results.each(&block) | |
end | |
end | |
class Search | |
attr_reader :indices | |
def initialize(indices, &block) | |
@indices = indices | |
instance_eval(&block) | |
end | |
def query(&block) | |
@query = Query.new.instance_eval(&block) | |
end | |
def from(value) | |
@from = value | |
end | |
def size(value) | |
@size = value | |
end | |
def sort(&block) | |
@sort = Sort.new(&block) | |
end | |
def fields(fields=[]) | |
@fields = fields | |
end | |
def facets(name, options={}, &block) | |
@facets = Facets.new(name, options, &block) | |
end | |
def to_json | |
request = { :query => @query } | |
request.update( { :sort => @sort } ) if @sort | |
request.update( { :fields => @fields } ) if @fields | |
request.update( { :size => @size } ) if @size | |
request.update( { :from => @from } ) if @from | |
request.update( { :facets => @facets } ) if @facets | |
request.to_json | |
end | |
end | |
class Query | |
def term(field, value) | |
@value = { :term => { field => value } } | |
end | |
def terms(field, value, options={}) | |
@value = { :terms => { field => value } } | |
@value[:terms].update( { :minimum_match => options[:minimum_match] } ) if options[:minimum_match] | |
@value | |
end | |
def query(value, options={}) | |
@value = { :query_string => { :query => value } } | |
@value[:query_string].update( { :default_field => options[:default_field] } ) if options[:default_field] | |
# TODO: https://github.com/elasticsearch/elasticsearch/wiki/Query-String-Query | |
@value | |
end | |
def to_json | |
@value.to_json | |
end | |
end | |
class Sort | |
def initialize(&block) | |
@value = [] | |
self.instance_eval(&block) if block_given? | |
end | |
def method_missing(id, *args, &block) | |
case arg = args.shift | |
when String, Symbol, Hash then @value << { id => arg } | |
else @value << id | |
end | |
end | |
def to_json | |
@value.to_json | |
end | |
end | |
class Facets | |
def initialize(name, options={}, &block) | |
@name = name | |
@options = options | |
self.instance_eval(&block) if block_given? | |
end | |
def terms(field, options={}) | |
@value = { :terms => { :field => field } } | |
end | |
def to_json | |
@value.update( @options ) if @options | |
request = { @name => @value } | |
request.to_json | |
end | |
end | |
class Index | |
def initialize(name, &block) | |
@name = name | |
instance_eval(&block) | |
end | |
def delete | |
Slingshot.http.delete "http://localhost:9200/#{@name}" | |
end | |
def create | |
Slingshot.http.post "http://localhost:9200/#{@name}", '' | |
end | |
def store(*args) | |
if args.size > 1 | |
(type, document = args) | |
else | |
(document = args.pop; type = :document) | |
end | |
document = case true | |
when document.is_a?(String) then document | |
when document.respond_to?(:to_json) then document.to_json | |
else raise ArgumentError, "Please pass a JSON string or object with a 'to_json' method" | |
end | |
result = Slingshot.http.post "http://localhost:9200/#{@name}/#{type}/", document | |
JSON.parse(result) | |
end | |
def refresh | |
Slingshot.http.post "http://localhost:9200/#{@name}/_refresh", '' | |
end | |
end | |
end | |
# --- Usage ------------------------------------------------------------------- | |
extend Slingshot | |
index 'articles' do | |
delete | |
create | |
store 'ruby-article', :title => 'One', :tags => ['ruby'] | |
store 'ruby-and-python-article', :title => 'Two', :tags => ['ruby', 'python'] | |
store :title => 'Three', :tags => ['java'] | |
store :title => 'Four', :tags => ['ruby', 'php'] | |
a = store '{"title" : "Five", "tags" : ["erlang"]}' | |
# puts "Stored last article with ID: " + a['_id'], "" | |
refresh | |
end | |
r = search 'articles' do | |
query do | |
# term :title, 'one' | |
# terms :tags, ['ruby', 'python'], :minimum_match => 2 | |
# query 'On*', :default_field => 'title' | |
# terms :tags, ['ruby', 'python'] | |
# query '*' | |
term :tags, 'ruby' | |
end | |
sort do | |
title 'desc' | |
_score | |
end | |
facets 'tags', :global => true do | |
terms :tags | |
end | |
fields :title | |
size 1 | |
from 1 | |
end | |
puts "Query:" , "-"*80, r.query, "" | |
puts "Curl:" , "-"*80, r.curl, "" | |
puts "Results (total: #{r.total}, query returned: #{r.count}):", "-"*80, r.inspect, "" | |
puts "Output:" , "-"*80 | |
r.each_with_index do |document, i| | |
puts "#{i+1}. #{ document['fields']['title'] } (#{document['_type']}, #{document['_id']})" | |
end | |
puts "", "Facets:" , "-"*80 | |
r.facets['tags']['terms'].each do |f| | |
puts "#{f['term'].ljust(10)} #{f['count']}" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment