elasticsearch-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in elastic_search.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = 'spec/**/*_spec.rb'
8
+ t.libs << 'lib' << 'spec'
9
+ end
10
+
11
+ task :default => :test
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "elastic_search/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "elasticsearch-ruby"
7
+ s.version = ElasticSearch::VERSION
8
+ s.authors = ["Edmund Salvacion"]
9
+ s.email = ["edmund@edmundatwork.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Ruby Driver for Elastic Search}
12
+ s.description = %q{Ruby Driver for Elastic Search}
13
+
14
+ s.rubyforge_project = "elasticsearch"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # = Library dependencies
22
+ #
23
+ s.add_dependency 'thrift'
24
+ s.add_dependency 'faraday'
25
+ s.add_dependency 'activesupport', ">= 3.0.0"
26
+ s.add_development_dependency "rake"
27
+ s.add_development_dependency "minitest"
28
+ s.add_development_dependency "turn"
29
+ end
@@ -0,0 +1,44 @@
1
+ module ElasticSearch
2
+ class Client
3
+ def initialize(transport)
4
+ @transport = transport
5
+ @indexes = {}
6
+ end
7
+
8
+ def get_index(index_name)
9
+ @indexes[index_name.to_sym] ||= ElasticSearch::Index.new(index_name, self)
10
+ end
11
+ alias :[] :get_index
12
+
13
+ def create_index(index_name, options = {})
14
+ body = { mappings: options[:mappings], settings: options[:settings] }.reject { |_, v| v.nil? }
15
+ request = Request.new({ method: :post, index: index_name, body: body })
16
+ status = self.execute(request).status
17
+ get_index(index_name) if status.eql?(200) || status.eql?(201)
18
+ end
19
+
20
+ def delete_index(index_name)
21
+ request = Request.new({ method: :delete, index: index_name })
22
+ execute(request)
23
+ end
24
+
25
+ def has_index?(index_name)
26
+ request = Request.new({ method: :head, index: index_name })
27
+ begin
28
+ execute(request).status.between?(200, 206)
29
+ rescue ElasticSearch::ResponseError
30
+ return false
31
+ end
32
+ end
33
+
34
+ def bulk(objects)
35
+ body = objects.flatten.join("\n") + "\n"
36
+ request = Request.new({ method: :post, action: :bulk, body: body })
37
+ execute(request)
38
+ end
39
+
40
+ def execute(request)
41
+ @transport.execute(request)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,75 @@
1
+ module ElasticSearch
2
+ class Index
3
+ attr_reader :index_name, :client
4
+
5
+ def initialize(index_name, client)
6
+ @index_name = index_name
7
+ @client = client
8
+ @types = {}
9
+ end
10
+
11
+ def get_type(type_name)
12
+ @types[type_name.to_sym] ||= ElasticSearch::Type.new(type_name, self)
13
+ end
14
+ alias :[] :get_type
15
+
16
+ def search(body, parameters)
17
+ request = build_request(method: :get, action: :search, parameters: parameters, body: body || {})
18
+ response = execute(request)
19
+ ElasticSearch::Search::Results.new(response)
20
+ end
21
+
22
+ def refresh
23
+ request = build_request(method: :post, action: :refresh)
24
+ execute(request)
25
+ end
26
+
27
+ def open
28
+ request = build_request(method: :post, action: :open)
29
+ execute(request)
30
+ end
31
+
32
+ def close
33
+ request = build_request(method: :post, action: :close)
34
+ execute(request)
35
+ end
36
+
37
+ def settings
38
+ request = build_request(method: :get, action: :settings)
39
+ execute(request).body
40
+ end
41
+
42
+ def settings=(settings)
43
+ request = build_request(method: :put, action: :settings, body: settings)
44
+ execute(request)
45
+ end
46
+
47
+ def mapping
48
+ request = build_request(method: :get, action: :mapping)
49
+ execute(request).body
50
+ end
51
+
52
+ def mapping=(mapping)
53
+ request = build_request(method: :put, action: :mapping, body: mapping)
54
+ execute(request).status.eql?(200)
55
+ end
56
+
57
+ def optimize(options = {})
58
+ request = build_request(method: :post, action: :optimize, parameters: options)
59
+ execute(request).status.eql?(200)
60
+ end
61
+
62
+ def exists?
63
+ @client.has_index?(@index_name)
64
+ end
65
+
66
+ def execute(request)
67
+ @client.execute(request)
68
+ end
69
+
70
+ private
71
+ def build_request(options = {})
72
+ Request.new({ index: @index_name }.merge(options))
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,14 @@
1
+ module ElasticSearch
2
+ class Item < HashWithIndifferentAccess
3
+ attr_reader :index, :type, :item, :version, :exists
4
+
5
+ def initialize(request)
6
+ @index = request.body['_index']
7
+ @type = request.body['_type']
8
+ @item = request.body['_id']
9
+ @version = request.body['_version']
10
+ @exists = request.body['exists']
11
+ self.replace(request.body['_source'])
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,33 @@
1
+ module ElasticSearch
2
+ class Request
3
+ attr_reader :method, :index, :type, :id, :action
4
+
5
+ def initialize(options = {})
6
+ @method = options[:method] ? options[:method].to_sym : :get
7
+ @index = options[:index]
8
+ @type = options[:type]
9
+ @id = options[:id]
10
+ @action = options[:action]
11
+ @parameters = options[:parameters]
12
+ @body = options[:body]
13
+ end
14
+
15
+ def parameters
16
+ @stringified_parameters ||= @parameters.inject({}) do |options, (key, value)|
17
+ options[key.to_s] = value
18
+ options
19
+ end if @parameters
20
+ end
21
+
22
+ def body
23
+ @encoded_body ||= @body.to_json
24
+ end
25
+
26
+ def path
27
+ components = [@index, @type]
28
+ components << @id if @id
29
+ components << "_#{@action.to_s}" if @action
30
+ components.compact.join("/")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,38 @@
1
+ module ElasticSearch
2
+ class Response
3
+ attr_reader :status
4
+
5
+ def initialize(options)
6
+ @body = options[:body].eql?("") ? "{}" : options[:body]
7
+ @status = options[:status]
8
+
9
+ case @status
10
+ when 200..206
11
+ when 404
12
+ if self.body['error'] =~ /^IndexMissingException/ || self.body.eql?(nil)
13
+ raise ElasticSearch::IndexMissingException, "#{self.body['status']}: #{self.body['error']}"
14
+ elsif self.body['exists'].eql?(false)
15
+ raise ElasticSearch::ItemMissingException, "_id: #{self.body['id']} NOT FOUND"
16
+ else
17
+ raise ElasticSearch::ResponseError
18
+ end
19
+ else
20
+ raise ElasticSearch::ResponseError, "#{self.body['status']}: #{self.body['error']}"
21
+ end
22
+ end
23
+
24
+ def body
25
+ @decoded_body ||= (@body ? ActiveSupport::JSON.decode(@body) : {})
26
+ end
27
+
28
+ private
29
+ def recursive_symbolize_keys!(hash)
30
+ hash.symbolize_keys!
31
+ hash.values.select{|v| v.is_a? Hash}.each{|h| recursive_symbolize_keys!(h)}
32
+ end
33
+ end
34
+
35
+ class ResponseError < StandardError; end
36
+ class IndexMissingException < StandardError; end
37
+ class ItemMissingException < StandardError; end
38
+ end
@@ -0,0 +1,28 @@
1
+ module ElasticSearch
2
+ module Search
3
+ class Results < Array
4
+ attr_reader :took, :timed_out, :shards, :total, :max_score
5
+
6
+ def initialize(response)
7
+ @took = response.body['took']
8
+ @timed_out = response.body['timed_out']
9
+ @shards = response.body['shards']
10
+ @total = response.body['hits']['total']
11
+ @max_score = response.body['hits']['max_score']
12
+ self.replace(response.body['hits']['hits'].collect { |h| ResultItem.new(h) })
13
+ end
14
+ end
15
+
16
+ class ResultItem < HashWithIndifferentAccess
17
+ attr_reader :index, :type, :id, :score
18
+
19
+ def initialize(hit)
20
+ @index = hit['_index']
21
+ @type = hit['_type']
22
+ @id = hit['_id']
23
+ @score = hit['_score']
24
+ self.replace(hit['_source'])
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,10 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.8.0)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ module ElasticSearch
8
+ module Thrift
9
+ end
10
+ end
@@ -0,0 +1,123 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.8.0)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ module ElasticSearch
8
+ module Thrift
9
+ module Method
10
+ GET = 0
11
+ PUT = 1
12
+ POST = 2
13
+ DELETE = 3
14
+ HEAD = 4
15
+ OPTIONS = 5
16
+ VALUE_MAP = {0 => "GET", 1 => "PUT", 2 => "POST", 3 => "DELETE", 4 => "HEAD", 5 => "OPTIONS"}
17
+ VALID_VALUES = Set.new([GET, PUT, POST, DELETE, HEAD, OPTIONS]).freeze
18
+ end
19
+
20
+ module Status
21
+ CONT = 100
22
+ SWITCHING_PROTOCOLS = 101
23
+ OK = 200
24
+ CREATED = 201
25
+ ACCEPTED = 202
26
+ NON_AUTHORITATIVE_INFORMATION = 203
27
+ NO_CONTENT = 204
28
+ RESET_CONTENT = 205
29
+ PARTIAL_CONTENT = 206
30
+ MULTI_STATUS = 207
31
+ MULTIPLE_CHOICES = 300
32
+ MOVED_PERMANENTLY = 301
33
+ FOUND = 302
34
+ SEE_OTHER = 303
35
+ NOT_MODIFIED = 304
36
+ USE_PROXY = 305
37
+ TEMPORARY_REDIRECT = 307
38
+ BAD_REQUEST = 400
39
+ UNAUTHORIZED = 401
40
+ PAYMENT_REQUIRED = 402
41
+ FORBIDDEN = 403
42
+ NOT_FOUND = 404
43
+ METHOD_NOT_ALLOWED = 405
44
+ NOT_ACCEPTABLE = 406
45
+ PROXY_AUTHENTICATION = 407
46
+ REQUEST_TIMEOUT = 408
47
+ CONFLICT = 409
48
+ GONE = 410
49
+ LENGTH_REQUIRED = 411
50
+ PRECONDITION_FAILED = 412
51
+ REQUEST_ENTITY_TOO_LARGE = 413
52
+ REQUEST_URI_TOO_LONG = 414
53
+ UNSUPPORTED_MEDIA_TYPE = 415
54
+ REQUESTED_RANGE_NOT_SATISFIED = 416
55
+ EXPECTATION_FAILED = 417
56
+ UNPROCESSABLE_ENTITY = 422
57
+ LOCKED = 423
58
+ FAILED_DEPENDENCY = 424
59
+ INTERNAL_SERVER_ERROR = 500
60
+ NOT_IMPLEMENTED = 501
61
+ BAD_GATEWAY = 502
62
+ SERVICE_UNAVAILABLE = 503
63
+ GATEWAY_TIMEOUT = 504
64
+ INSUFFICIENT_STORAGE = 506
65
+ VALUE_MAP = {100 => "CONT", 101 => "SWITCHING_PROTOCOLS", 200 => "OK", 201 => "CREATED", 202 => "ACCEPTED", 203 => "NON_AUTHORITATIVE_INFORMATION", 204 => "NO_CONTENT", 205 => "RESET_CONTENT", 206 => "PARTIAL_CONTENT", 207 => "MULTI_STATUS", 300 => "MULTIPLE_CHOICES", 301 => "MOVED_PERMANENTLY", 302 => "FOUND", 303 => "SEE_OTHER", 304 => "NOT_MODIFIED", 305 => "USE_PROXY", 307 => "TEMPORARY_REDIRECT", 400 => "BAD_REQUEST", 401 => "UNAUTHORIZED", 402 => "PAYMENT_REQUIRED", 403 => "FORBIDDEN", 404 => "NOT_FOUND", 405 => "METHOD_NOT_ALLOWED", 406 => "NOT_ACCEPTABLE", 407 => "PROXY_AUTHENTICATION", 408 => "REQUEST_TIMEOUT", 409 => "CONFLICT", 410 => "GONE", 411 => "LENGTH_REQUIRED", 412 => "PRECONDITION_FAILED", 413 => "REQUEST_ENTITY_TOO_LARGE", 414 => "REQUEST_URI_TOO_LONG", 415 => "UNSUPPORTED_MEDIA_TYPE", 416 => "REQUESTED_RANGE_NOT_SATISFIED", 417 => "EXPECTATION_FAILED", 422 => "UNPROCESSABLE_ENTITY", 423 => "LOCKED", 424 => "FAILED_DEPENDENCY", 500 => "INTERNAL_SERVER_ERROR", 501 => "NOT_IMPLEMENTED", 502 => "BAD_GATEWAY", 503 => "SERVICE_UNAVAILABLE", 504 => "GATEWAY_TIMEOUT", 506 => "INSUFFICIENT_STORAGE"}
66
+ VALID_VALUES = Set.new([CONT, SWITCHING_PROTOCOLS, OK, CREATED, ACCEPTED, NON_AUTHORITATIVE_INFORMATION, NO_CONTENT, RESET_CONTENT, PARTIAL_CONTENT, MULTI_STATUS, MULTIPLE_CHOICES, MOVED_PERMANENTLY, FOUND, SEE_OTHER, NOT_MODIFIED, USE_PROXY, TEMPORARY_REDIRECT, BAD_REQUEST, UNAUTHORIZED, PAYMENT_REQUIRED, FORBIDDEN, NOT_FOUND, METHOD_NOT_ALLOWED, NOT_ACCEPTABLE, PROXY_AUTHENTICATION, REQUEST_TIMEOUT, CONFLICT, GONE, LENGTH_REQUIRED, PRECONDITION_FAILED, REQUEST_ENTITY_TOO_LARGE, REQUEST_URI_TOO_LONG, UNSUPPORTED_MEDIA_TYPE, REQUESTED_RANGE_NOT_SATISFIED, EXPECTATION_FAILED, UNPROCESSABLE_ENTITY, LOCKED, FAILED_DEPENDENCY, INTERNAL_SERVER_ERROR, NOT_IMPLEMENTED, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, INSUFFICIENT_STORAGE]).freeze
67
+ end
68
+
69
+ class RestRequest
70
+ include ::Thrift::Struct, ::Thrift::Struct_Union
71
+ METHOD = 1
72
+ URI = 2
73
+ PARAMETERS = 3
74
+ HEADERS = 4
75
+ BODY = 5
76
+
77
+ FIELDS = {
78
+ METHOD => {:type => ::Thrift::Types::I32, :name => 'method', :enum_class => ElasticSearch::Thrift::Method},
79
+ URI => {:type => ::Thrift::Types::STRING, :name => 'uri'},
80
+ PARAMETERS => {:type => ::Thrift::Types::MAP, :name => 'parameters', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
81
+ HEADERS => {:type => ::Thrift::Types::MAP, :name => 'headers', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
82
+ BODY => {:type => ::Thrift::Types::STRING, :name => 'body', :binary => true, :optional => true}
83
+ }
84
+
85
+ def struct_fields; FIELDS; end
86
+
87
+ def validate
88
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field method is unset!') unless @method
89
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field uri is unset!') unless @uri
90
+ unless @method.nil? || ElasticSearch::Thrift::Method::VALID_VALUES.include?(@method)
91
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field method!')
92
+ end
93
+ end
94
+
95
+ ::Thrift::Struct.generate_accessors self
96
+ end
97
+
98
+ class RestResponse
99
+ include ::Thrift::Struct, ::Thrift::Struct_Union
100
+ STATUS = 1
101
+ HEADERS = 2
102
+ BODY = 3
103
+
104
+ FIELDS = {
105
+ STATUS => {:type => ::Thrift::Types::I32, :name => 'status', :enum_class => ElasticSearch::Thrift::Status},
106
+ HEADERS => {:type => ::Thrift::Types::MAP, :name => 'headers', :key => {:type => ::Thrift::Types::STRING}, :value => {:type => ::Thrift::Types::STRING}, :optional => true},
107
+ BODY => {:type => ::Thrift::Types::STRING, :name => 'body', :binary => true, :optional => true}
108
+ }
109
+
110
+ def struct_fields; FIELDS; end
111
+
112
+ def validate
113
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field status is unset!') unless @status
114
+ unless @status.nil? || ElasticSearch::Thrift::Status::VALID_VALUES.include?(@status)
115
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field status!')
116
+ end
117
+ end
118
+
119
+ ::Thrift::Struct.generate_accessors self
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,80 @@
1
+ namespace java org.elasticsearch.thrift
2
+ namespace csharp ElasticSearch.Thrift
3
+ namespace cpp elasticsearch.thrift
4
+ namespace rb ElasticSearch.Thrift
5
+ namespace py elasticsearch
6
+ namespace perl Elasticsearch
7
+
8
+ enum Method {
9
+ GET = 0,
10
+ PUT = 1,
11
+ POST = 2,
12
+ DELETE = 3,
13
+ HEAD = 4,
14
+ OPTIONS = 5
15
+ }
16
+
17
+ struct RestRequest {
18
+ 1: required Method method,
19
+ 2: required string uri
20
+ 3: optional map<string, string> parameters
21
+ 4: optional map<string, string> headers
22
+ 5: optional binary body
23
+ }
24
+
25
+ enum Status {
26
+ CONT = 100,
27
+ SWITCHING_PROTOCOLS = 101,
28
+ OK = 200,
29
+ CREATED = 201,
30
+ ACCEPTED = 202,
31
+ NON_AUTHORITATIVE_INFORMATION = 203,
32
+ NO_CONTENT = 204,
33
+ RESET_CONTENT = 205,
34
+ PARTIAL_CONTENT = 206,
35
+ MULTI_STATUS = 207,
36
+ MULTIPLE_CHOICES = 300,
37
+ MOVED_PERMANENTLY = 301,
38
+ FOUND = 302,
39
+ SEE_OTHER = 303,
40
+ NOT_MODIFIED = 304,
41
+ USE_PROXY = 305,
42
+ TEMPORARY_REDIRECT = 307,
43
+ BAD_REQUEST = 400,
44
+ UNAUTHORIZED = 401,
45
+ PAYMENT_REQUIRED = 402,
46
+ FORBIDDEN = 403,
47
+ NOT_FOUND = 404,
48
+ METHOD_NOT_ALLOWED = 405,
49
+ NOT_ACCEPTABLE = 406,
50
+ PROXY_AUTHENTICATION = 407,
51
+ REQUEST_TIMEOUT = 408,
52
+ CONFLICT = 409,
53
+ GONE = 410,
54
+ LENGTH_REQUIRED = 411,
55
+ PRECONDITION_FAILED = 412,
56
+ REQUEST_ENTITY_TOO_LARGE = 413,
57
+ REQUEST_URI_TOO_LONG = 414,
58
+ UNSUPPORTED_MEDIA_TYPE = 415,
59
+ REQUESTED_RANGE_NOT_SATISFIED = 416,
60
+ EXPECTATION_FAILED = 417,
61
+ UNPROCESSABLE_ENTITY = 422,
62
+ LOCKED = 423,
63
+ FAILED_DEPENDENCY = 424,
64
+ INTERNAL_SERVER_ERROR = 500,
65
+ NOT_IMPLEMENTED = 501,
66
+ BAD_GATEWAY = 502,
67
+ SERVICE_UNAVAILABLE = 503,
68
+ GATEWAY_TIMEOUT = 504,
69
+ INSUFFICIENT_STORAGE = 506
70
+ }
71
+
72
+ struct RestResponse {
73
+ 1: required Status status,
74
+ 2: optional map<string, string> headers,
75
+ 3: optional binary body
76
+ }
77
+
78
+ service Rest {
79
+ RestResponse execute(1:required RestRequest request)
80
+ }
@@ -0,0 +1,79 @@
1
+ #
2
+ # Autogenerated by Thrift Compiler (0.8.0)
3
+ #
4
+ # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
5
+ #
6
+
7
+ require 'thrift'
8
+
9
+ module ElasticSearch
10
+ module Thrift
11
+ module Rest
12
+ class Client
13
+ include ::Thrift::Client
14
+
15
+ def execute(request)
16
+ send_execute(request)
17
+ return recv_execute()
18
+ end
19
+
20
+ def send_execute(request)
21
+ send_message('execute', Execute_args, :request => request)
22
+ end
23
+
24
+ def recv_execute()
25
+ result = receive_message(Execute_result)
26
+ return result.success unless result.success.nil?
27
+ raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'execute failed: unknown result')
28
+ end
29
+
30
+ end
31
+
32
+ class Processor
33
+ include ::Thrift::Processor
34
+
35
+ def process_execute(seqid, iprot, oprot)
36
+ args = read_args(iprot, Execute_args)
37
+ result = Execute_result.new()
38
+ result.success = @handler.execute(args.request)
39
+ write_result(result, oprot, 'execute', seqid)
40
+ end
41
+ end
42
+
43
+ # HELPER FUNCTIONS AND STRUCTURES
44
+
45
+ class Execute_args
46
+ include ::Thrift::Struct, ::Thrift::Struct_Union
47
+ REQUEST = 1
48
+
49
+ FIELDS = {
50
+ REQUEST => {:type => ::Thrift::Types::STRUCT, :name => 'request', :class => ElasticSearch::Thrift::RestRequest}
51
+ }
52
+
53
+ def struct_fields; FIELDS; end
54
+
55
+ def validate
56
+ raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Required field request is unset!') unless @request
57
+ end
58
+
59
+ ::Thrift::Struct.generate_accessors self
60
+ end
61
+
62
+ class Execute_result
63
+ include ::Thrift::Struct, ::Thrift::Struct_Union
64
+ SUCCESS = 0
65
+
66
+ FIELDS = {
67
+ SUCCESS => {:type => ::Thrift::Types::STRUCT, :name => 'success', :class => ElasticSearch::Thrift::RestResponse}
68
+ }
69
+
70
+ def struct_fields; FIELDS; end
71
+
72
+ def validate
73
+ end
74
+
75
+ ::Thrift::Struct.generate_accessors self
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,21 @@
1
+ module ElasticSearch
2
+ class TransportBase
3
+ def initialize(hosts, options = {})
4
+ @options = options
5
+ @connections = hosts.collect { |host| get_connection(host) }
6
+ end
7
+
8
+ def current_connection
9
+ @connections.sample
10
+ end
11
+
12
+ def execute(request)
13
+ raise NotImplementedError
14
+ end
15
+
16
+ private
17
+ def get_connection(host)
18
+ raise NotImplementedError
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ require 'faraday'
2
+
3
+ module ElasticSearch
4
+ class HTTPTransport < TransportBase
5
+ def execute(request)
6
+ response = current_connection.send(request.method, request.path) do |req|
7
+ req.body = request.body unless request.method.eql?(:delete)
8
+ req.params = request.parameters if request.parameters
9
+ end
10
+ ElasticSearch::Response.new(body: response.body, status: response.status)
11
+ end
12
+
13
+ private
14
+ def get_connection(host)
15
+ Faraday.new(:url => host)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,38 @@
1
+ require 'thrift'
2
+ require 'elastic_search/thrift/elastic_search_constants'
3
+ require 'elastic_search/thrift/elastic_search_types'
4
+ require 'elastic_search/thrift/rest'
5
+
6
+ module ElasticSearch
7
+ class ThriftTransport < TransportBase
8
+ def execute(request)
9
+ thrift_request = ElasticSearch::Thrift::RestRequest.new
10
+ thrift_request.method = get_method(request.method)
11
+ thrift_request.uri = request.path
12
+ thrift_request.body = request.body
13
+ thrift_request.parameters = request.parameters
14
+ response = current_connection.execute(thrift_request)
15
+ ElasticSearch::Response.new(body: response.body, status: response.status)
16
+ end
17
+
18
+ private
19
+ def get_method(method)
20
+ case method
21
+ when :get then ElasticSearch::Thrift::Method::GET
22
+ when :post then ElasticSearch::Thrift::Method::POST
23
+ when :put then ElasticSearch::Thrift::Method::PUT
24
+ when :delete then ElasticSearch::Thrift::Method::DELETE
25
+ when :head then ElasticSearch::Thrift::Method::HEAD
26
+ end
27
+ end
28
+
29
+ def get_connection(host)
30
+ host, port = host.to_s.split(":")
31
+ transport = ::Thrift::Socket.new(host, port.to_i, @options[:timeout])
32
+ buffered_transport = ::Thrift::BufferedTransport.new(transport)
33
+ buffered_transport.open
34
+ protocol = ::Thrift::BinaryProtocol.new(buffered_transport)
35
+ ElasticSearch::Thrift::Rest::Client.new(protocol)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,64 @@
1
+ module ElasticSearch
2
+ class Type
3
+ def initialize(type_name, index)
4
+ @type_name = type_name
5
+ @index = index
6
+ end
7
+
8
+ def search(body, parameters = {})
9
+ request = build_request({ method: :get, action: :search, parameters: parameters, body: body || {} })
10
+ response = execute(request)
11
+ ElasticSearch::Search::Results.new(response)
12
+ end
13
+
14
+ def put(id, doc)
15
+ request = build_request({ method: :put, id: id.to_s, body: doc })
16
+ execute(request)
17
+ end
18
+ alias :index :put
19
+
20
+ def get(id)
21
+ request = build_request({ method: :get, id: id.to_s })
22
+ response = execute(request)
23
+ ElasticSearch::Item.new(response)
24
+ end
25
+
26
+ def delete(id)
27
+ request = build_request({ method: :delete, id: id.to_s })
28
+ execute(request)
29
+ end
30
+
31
+ def delete_by_query(body, parameters = {})
32
+ request = build_request({ method: :delete, action: :search, parameters: parameters, body: body || {} })
33
+ execute(request)
34
+ end
35
+
36
+ def update(id, body, parameters = {})
37
+ request = build_request({ method: :post, id: id.to_s, action: :update, parameters: parameters, body: doc })
38
+ execute(request)
39
+ end
40
+
41
+ def count(parameters = {})
42
+ request = build_request({ method: :post, action: :update, id: id.to_s, body: doc })
43
+ execute(request).body['count']
44
+ end
45
+
46
+ def more_like_this(id, parameters = {})
47
+ request = build_request({ method: :get, id: id.to_s, action: :mlt, parameters: parameters, body: doc })
48
+ end
49
+
50
+ def delete_mapping
51
+ request = build_request({ method: :delete })
52
+ execute(request).status.eql?(200)
53
+ end
54
+
55
+ def execute(request)
56
+ @index.client.execute(request)
57
+ end
58
+
59
+ private
60
+ def build_request(parameters = {})
61
+ Request.new({ index: @index.index_name, type: @type_name }.merge(parameters))
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module ElasticSearch
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,16 @@
1
+ require "active_support/all"
2
+
3
+ require "elastic_search/client"
4
+ require "elastic_search/index"
5
+ require "elastic_search/item"
6
+ require "elastic_search/request"
7
+ require "elastic_search/response"
8
+ require "elastic_search/search/results"
9
+ require "elastic_search/transport/base"
10
+ require "elastic_search/transport/thrift"
11
+ require "elastic_search/transport/http"
12
+ require "elastic_search/type"
13
+ require "elastic_search/version"
14
+
15
+ module ElasticSearch
16
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe ElasticSearch::Client do
4
+ TRANSPORT_CONTEXTS.each do |transport, context|
5
+ describe context do
6
+ let :client do
7
+ ElasticSearch::Client.new(transport)
8
+ end
9
+
10
+ after do
11
+ begin
12
+ client.delete_index(TEST_INDEX)
13
+ rescue
14
+ end
15
+ end
16
+
17
+ describe :create_index do
18
+ it "should create a new index" do
19
+ index = client.create_index(TEST_INDEX)
20
+ index.must_be_instance_of ElasticSearch::Index
21
+ index.refresh
22
+ client.has_index?(TEST_INDEX).must_equal true
23
+ end
24
+
25
+ it "should create a new index with a mapping" do
26
+ mapping = {
27
+ test_type: {
28
+ properties: {
29
+ foo: { type: :string, analyzer: :keyword }
30
+ }
31
+ }
32
+ }
33
+ index = client.create_index(TEST_INDEX, mappings: mapping)
34
+ index.mapping['test_index']['test_type']['properties']['foo']['analyzer'].must_equal "keyword"
35
+ index.mapping['test_index']['test_type']['properties']['foo']['type'].must_equal "string"
36
+ end
37
+ end
38
+
39
+ describe :delete_index do
40
+ it "should delete an index" do
41
+ client.has_index?(TEST_INDEX).must_equal false
42
+ end
43
+ end
44
+
45
+ describe :has_index? do
46
+ it "should know if an index exists" do
47
+ client.create_index(TEST_INDEX).refresh
48
+ client.has_index?(TEST_INDEX).must_equal true
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ describe ElasticSearch::Index do
4
+ TRANSPORT_CONTEXTS.each do |transport, context|
5
+ describe context do
6
+ let :client do
7
+ ElasticSearch::Client.new(transport)
8
+ end
9
+
10
+ let :index do
11
+ client[TEST_INDEX]
12
+ end
13
+
14
+ before do
15
+ client.create_index(TEST_INDEX).refresh
16
+ end
17
+
18
+ after do
19
+ begin
20
+ client.delete_index(TEST_INDEX)
21
+ rescue ElasticSearch::IndexMissingException
22
+ end
23
+ end
24
+
25
+ describe :search do
26
+ it "should return results" do
27
+ index['type_1'].put(1, { foo: 'bar' })
28
+ index['type_2'].put(2, { foo: 'baz' })
29
+ index.refresh
30
+ results = index.search(nil, q: '*')
31
+ results.must_be_instance_of ElasticSearch::Search::Results
32
+ end
33
+
34
+ it "should return the total" do
35
+ (1..20).each { |i| index['type'].put(i, { foo: 'bar' }) }
36
+ index.refresh
37
+ results = index.search(nil, q: '*')
38
+ results.total.must_equal 20
39
+ results.count.must_equal 10
40
+ end
41
+
42
+ it "should know the type of results" do
43
+ index['type_1'].put(1, { foo: 'bar' })
44
+ index.refresh
45
+ results = index.search(nil, q: '*')
46
+ results[0].type.must_equal 'type_1'
47
+ end
48
+ end
49
+
50
+ describe :refresh do
51
+ it "should refresh the index" do
52
+ index.refresh
53
+ end
54
+ end
55
+
56
+ describe :open do
57
+ it "should not raise an error if index is open" do
58
+ index.close
59
+ index.open
60
+ index[TEST_TYPE].put(1, { foo: 'bar' })
61
+ end
62
+ end
63
+
64
+ describe :close do
65
+ it "should throw an error when trying to put into a closed index" do
66
+ index.close
67
+ proc { index[TEST_TYPE].put(1, { foo: 'bar' }) }.must_raise ElasticSearch::ResponseError
68
+ end
69
+ end
70
+
71
+ describe :settings do
72
+ it "should return the index settings"
73
+ end
74
+
75
+ describe :settings= do
76
+ it "should set the index settings"
77
+ end
78
+
79
+ describe :mapping do
80
+ it "should return the mapping" do
81
+ index.mapping
82
+ end
83
+ end
84
+
85
+ describe :mapping= do
86
+ it "should set the index mapping"
87
+ end
88
+
89
+ describe :delete_mapping do
90
+ it "should set delete the index mapping"
91
+ end
92
+
93
+ describe :optimize do
94
+ it "should optimize the index"
95
+ end
96
+
97
+ describe :exists? do
98
+ it "should check if the index exists" do
99
+ index.exists?.must_equal true
100
+ client.delete_index(TEST_INDEX)
101
+ index.exists?.must_equal false
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe ElasticSearch::Type do
4
+ TRANSPORT_CONTEXTS.each do |transport, context|
5
+ describe context do
6
+ let :client do
7
+ ElasticSearch::Client.new(transport)
8
+ end
9
+
10
+ let :index do
11
+ client[TEST_INDEX]
12
+ end
13
+
14
+ let :type do
15
+ index[TEST_TYPE]
16
+ end
17
+
18
+ before do
19
+ client.create_index(TEST_INDEX).refresh
20
+ end
21
+
22
+ after do
23
+ begin client.delete_index(TEST_INDEX) end
24
+ end
25
+
26
+ describe :put do
27
+ it "should index a document" do
28
+ type.put(1, { foo: 'bar' })
29
+ index.refresh
30
+ type.get(1)['foo'].must_equal 'bar'
31
+ end
32
+ end
33
+
34
+ describe :get do
35
+ it "should return an error if document does not exist"
36
+ end
37
+
38
+ describe :search do
39
+ it "should return results" do
40
+ type.put(1, { foo: 'bar' })
41
+ type.put(2, { foo: 'baz' })
42
+ index.refresh
43
+ results = type.search(nil, q: '*')
44
+ results.must_be_instance_of ElasticSearch::Search::Results
45
+ end
46
+
47
+ it "should return the total" do
48
+ (1..20).each { |i| type.put(i, { foo: 'bar' }) }
49
+ index.refresh
50
+ results = type.search(nil, q: '*')
51
+ results.total.must_equal 20
52
+ results.count.must_equal 10
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,26 @@
1
+ require "bundler/setup"
2
+ require 'minitest/spec'
3
+ require 'minitest/mock'
4
+ require 'turn/autorun'
5
+ require 'active_support/all'
6
+
7
+ require 'elastic_search'
8
+
9
+ class MiniTest::Spec
10
+ alias :method_name :__name__ if defined? :__name__
11
+
12
+ class << self
13
+ alias :context :describe
14
+ end
15
+ end
16
+
17
+ Turn.config.format = :progress
18
+ Turn.config.natural = true
19
+
20
+ TEST_INDEX = 'test_index'
21
+ TEST_TYPE = 'test_type'
22
+
23
+ TRANSPORT_CONTEXTS = [
24
+ [ElasticSearch::ThriftTransport.new(['localhost:9500']), 'Using Thrift'],
25
+ [ElasticSearch::HTTPTransport.new(['http://localhost:9200']), 'Using HTTP']
26
+ ]
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elasticsearch-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Edmund Salvacion
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thrift
16
+ requirement: &70333353079280 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70333353079280
25
+ - !ruby/object:Gem::Dependency
26
+ name: faraday
27
+ requirement: &70333353078860 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70333353078860
36
+ - !ruby/object:Gem::Dependency
37
+ name: activesupport
38
+ requirement: &70333353078200 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 3.0.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70333353078200
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &70333353077540 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70333353077540
58
+ - !ruby/object:Gem::Dependency
59
+ name: minitest
60
+ requirement: &70333353077040 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70333353077040
69
+ - !ruby/object:Gem::Dependency
70
+ name: turn
71
+ requirement: &70333353076580 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70333353076580
80
+ description: Ruby Driver for Elastic Search
81
+ email:
82
+ - edmund@edmundatwork.com
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files: []
86
+ files:
87
+ - .gitignore
88
+ - Gemfile
89
+ - Rakefile
90
+ - elastic_search.gemspec
91
+ - lib/elastic_search.rb
92
+ - lib/elastic_search/client.rb
93
+ - lib/elastic_search/index.rb
94
+ - lib/elastic_search/item.rb
95
+ - lib/elastic_search/request.rb
96
+ - lib/elastic_search/response.rb
97
+ - lib/elastic_search/search/results.rb
98
+ - lib/elastic_search/thrift/elastic_search_constants.rb
99
+ - lib/elastic_search/thrift/elastic_search_types.rb
100
+ - lib/elastic_search/thrift/elasticsearch.thrift
101
+ - lib/elastic_search/thrift/rest.rb
102
+ - lib/elastic_search/transport/base.rb
103
+ - lib/elastic_search/transport/http.rb
104
+ - lib/elastic_search/transport/thrift.rb
105
+ - lib/elastic_search/type.rb
106
+ - lib/elastic_search/version.rb
107
+ - spec/elasticsearch/client_spec.rb
108
+ - spec/elasticsearch/index_spec.rb
109
+ - spec/elasticsearch/type_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: ''
112
+ licenses: []
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project: elasticsearch
131
+ rubygems_version: 1.8.17
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: Ruby Driver for Elastic Search
135
+ test_files:
136
+ - spec/elasticsearch/client_spec.rb
137
+ - spec/elasticsearch/index_spec.rb
138
+ - spec/elasticsearch/type_spec.rb
139
+ - spec/spec_helper.rb