elasticsearch-ruby 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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