elastics-client 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +28 -0
  3. data/VERSION +1 -0
  4. data/elastics-client.gemspec +33 -0
  5. data/lib/elastics.rb +108 -0
  6. data/lib/elastics/api_stubs.rb +1268 -0
  7. data/lib/elastics/api_templates/cluster_api.yml +94 -0
  8. data/lib/elastics/api_templates/core_api.yml +202 -0
  9. data/lib/elastics/api_templates/indices_api.yml +304 -0
  10. data/lib/elastics/class_proxy/base.rb +29 -0
  11. data/lib/elastics/class_proxy/templates.rb +97 -0
  12. data/lib/elastics/class_proxy/templates/doc.rb +91 -0
  13. data/lib/elastics/class_proxy/templates/search.rb +72 -0
  14. data/lib/elastics/configuration.rb +25 -0
  15. data/lib/elastics/deprecation.rb +153 -0
  16. data/lib/elastics/errors.rb +43 -0
  17. data/lib/elastics/http_clients/base.rb +15 -0
  18. data/lib/elastics/http_clients/loader.rb +51 -0
  19. data/lib/elastics/http_clients/patron.rb +29 -0
  20. data/lib/elastics/http_clients/rest_client.rb +36 -0
  21. data/lib/elastics/logger.rb +37 -0
  22. data/lib/elastics/prog_bar.rb +39 -0
  23. data/lib/elastics/rails.rb +1 -0
  24. data/lib/elastics/result.rb +24 -0
  25. data/lib/elastics/result/bulk.rb +20 -0
  26. data/lib/elastics/result/document.rb +67 -0
  27. data/lib/elastics/result/multi_get.rb +24 -0
  28. data/lib/elastics/result/search.rb +28 -0
  29. data/lib/elastics/struct/array.rb +25 -0
  30. data/lib/elastics/struct/hash.rb +105 -0
  31. data/lib/elastics/struct/paginable.rb +58 -0
  32. data/lib/elastics/struct/prunable.rb +60 -0
  33. data/lib/elastics/struct/symbolize.rb +27 -0
  34. data/lib/elastics/tasks.rb +62 -0
  35. data/lib/elastics/template.rb +124 -0
  36. data/lib/elastics/template/common.rb +42 -0
  37. data/lib/elastics/template/logger.rb +66 -0
  38. data/lib/elastics/template/partial.rb +28 -0
  39. data/lib/elastics/template/search.rb +30 -0
  40. data/lib/elastics/template/slim_search.rb +13 -0
  41. data/lib/elastics/template/tags.rb +56 -0
  42. data/lib/elastics/templates.rb +20 -0
  43. data/lib/elastics/utility_methods.rb +131 -0
  44. data/lib/elastics/utils.rb +103 -0
  45. data/lib/elastics/variables.rb +62 -0
  46. data/lib/tasks.rake +28 -0
  47. metadata +148 -0
@@ -0,0 +1,43 @@
1
+ module Elastics
2
+
3
+ class ArgumentError < ArgumentError; end
4
+ class SourceError < StandardError; end
5
+ class MissingPartialError < StandardError; end
6
+ class DocumentMappingError < StandardError; end
7
+ class MissingIndexEntryError < StandardError; end
8
+ class ExistingIndexError < StandardError; end
9
+ class MissingHttpClientError < StandardError; end
10
+ class MissingParentError < StandardError; end
11
+ class MissingVariableError < StandardError; end
12
+
13
+ class HttpError < StandardError
14
+
15
+ attr_reader :response
16
+
17
+ def initialize(response, caller_line=nil)
18
+ @response = response
19
+ @caller_line = caller_line
20
+ end
21
+
22
+ def status
23
+ response.status
24
+ end
25
+
26
+ def body
27
+ response.body
28
+ end
29
+
30
+ def to_s
31
+ log = "#@caller_line\n" if @caller_line
32
+ "#{log}#{status}: #{body}"
33
+ end
34
+
35
+ def to_hash
36
+ MultiJson.decode response.body
37
+ rescue MultiJson::DecodeError
38
+ {}
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,15 @@
1
+ module Elastics
2
+ module HttpClients
3
+ class Base
4
+
5
+ attr_accessor :options, :base_uri, :raise_proc
6
+
7
+ def initialize(base_uri='http://localhost:9200', options={})
8
+ @options = options
9
+ @base_uri = base_uri
10
+ @raise_proc = proc{|response| response.status >= 400}
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,51 @@
1
+ module Elastics
2
+ module HttpClients
3
+
4
+ class Dummy
5
+ def request(*)
6
+ raise MissingHttpClientError,
7
+ 'you should install the gem "patron" (recommended for performances) or "rest-client", ' +
8
+ 'or provide your own http-client interface and set Elastics::Configuration.http_client'
9
+ end
10
+ end
11
+
12
+ module Loader
13
+
14
+ extend self
15
+
16
+ def new_http_client
17
+ if Gem::Specification.respond_to?(:find_all_by_name)
18
+ case
19
+ # terrible way to check whether a gem is available.
20
+ # Gem.available? was just perfect: that's probably the reason it has been deprecated!
21
+ # https://github.com/rubygems/rubygems/issues/176
22
+ when Gem::Specification::find_all_by_name('patron').any? then require_patron
23
+ when Gem::Specification::find_all_by_name('rest-client').any? then require_rest_client
24
+ else Dummy.new
25
+ end
26
+ else
27
+ case
28
+ when Gem.available?('patron') then require_patron
29
+ when Gem.available?('rest-client') then require_rest_client
30
+ else Dummy.new
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def require_patron
38
+ require 'patron'
39
+ require 'elastics/http_clients/patron'
40
+ Patron.new
41
+ end
42
+
43
+ def require_rest_client
44
+ require 'rest-client'
45
+ require 'elastics/http_clients/rest_client'
46
+ RestClient.new
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,29 @@
1
+ module Elastics
2
+ module HttpClients
3
+ class Patron < Base
4
+
5
+ def request(method, path, data=nil)
6
+ # patron would raise an error for :post and :put requests with no data
7
+ # and elasticsearch ignores the data when it expects no data,
8
+ # so we silence patron by adding some dummy data
9
+ data = {} if (method == 'POST' || method == 'PUT') && data.nil?
10
+ opts = options.merge(:data => data)
11
+ session.request method.to_s.downcase.to_sym, path, {}, opts
12
+ rescue ::Patron::TimeoutError
13
+ session.request method.to_s.downcase.to_sym, path, {}, opts
14
+ end
15
+
16
+ private
17
+
18
+ def session
19
+ Thread.current[:elastics_patron_session] ||= begin
20
+ sess = ::Patron::Session.new
21
+ sess.headers['User-Agent'] = "elastics-#{Elastics::VERSION}"
22
+ sess.base_url = base_uri
23
+ sess
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,36 @@
1
+ module Elastics
2
+ module HttpClients
3
+ class RestClient < Base
4
+
5
+ def request(method, path, data=nil)
6
+ url = "#{base_uri}#{path}"
7
+ opts = options.merge( :method => method.to_s.downcase.to_sym,
8
+ :url => url,
9
+ :payload => data )
10
+ response = ::RestClient::Request.new( opts ).execute
11
+ extend_response(response, url)
12
+
13
+ rescue ::RestClient::ExceptionWithResponse => e
14
+ extend_response(e.response, url)
15
+ end
16
+
17
+ private
18
+
19
+ def extend_response(response, url)
20
+ response.extend ResponseExtension
21
+ response.url = url
22
+ response
23
+ end
24
+
25
+ module ResponseExtension
26
+ attr_accessor :url
27
+
28
+ def status
29
+ code.to_i
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,37 @@
1
+ require 'logger'
2
+
3
+ module Elastics
4
+ class Logger < ::Logger
5
+
6
+
7
+ attr_accessor :debug_variables, :debug_request, :debug_result, :curl_format
8
+
9
+ def initialize(*)
10
+ super
11
+ self.level = ::Logger::WARN
12
+ self.progname = 'ELASTICS'
13
+ self.formatter = proc do |severity, datetime, progname, msg|
14
+ elastics_format(severity, msg)
15
+ end
16
+ @debug_variables = true
17
+ @debug_request = true
18
+ @debug_result = true
19
+ @curl_format = false
20
+ end
21
+
22
+ def elastics_format(severity, msg)
23
+ prefix = Dye.dye(" ELASTICS-#{severity} ", "ELASTICS-#{severity}:", :blue, :bold, :reversed) + ' '
24
+ msg.split("\n").map{|l| prefix + l}.join("\n") + "\n"
25
+ end
26
+
27
+ # force color in console (used with jruby)
28
+ def color=(bool)
29
+ Dye.color = bool
30
+ end
31
+
32
+ def color
33
+ Dye.color?
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,39 @@
1
+ module Elastics
2
+ class ProgBar
3
+
4
+ attr_reader :pbar, :total_count
5
+
6
+ def initialize(total_count, batch_size=nil, prefix_message=nil)
7
+ @total_count = total_count
8
+ @successful_count = 0
9
+ @failed_count = 0
10
+ @pbar = ::ProgressBar.new('processing...', total_count)
11
+ @pbar.clear
12
+ @pbar.bar_mark = '|'
13
+ puts '_' * @pbar.send(:get_term_width)
14
+ message = "#{prefix_message}Processing #{total_count} documents"
15
+ message << " in batches of #{batch_size}:" unless batch_size.nil?
16
+ puts message
17
+ @pbar.send(:show)
18
+ end
19
+
20
+ def process_result(result, inc)
21
+ unless result.nil? || result.empty?
22
+ unless result.failed.size == 0
23
+ Conf.logger.error "Failed load:\n#{result.failed.to_yaml}"
24
+ @pbar.bar_mark = 'F'
25
+ end
26
+ @failed_count += result.failed.size
27
+ @successful_count += result.successful.size
28
+ end
29
+ @pbar.inc(inc)
30
+ end
31
+
32
+ def finish
33
+ @pbar.finish
34
+ puts "Processed #@total_count. Successful #@successful_count. Skipped #{@total_count - @successful_count - @failed_count}. Failed #@failed_count."
35
+ puts 'See the log for the details about the failures.' unless @failed_count == 0
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1 @@
1
+ raise NotImplementedError, %(The "flex/rails" file has been replaced by the "elastics-rails" gem. Please, use "elastics-rails" in place of "flex" in Rails applications (change "gem 'flex', require => 'flex/rails'" to "gem 'elastics-rails'" in your Gemfile). Please, read the upgrade notes at http://elastics.github.io/elastics/doc/7-Tutorials/2-Migrate-from-0.x.html.)
@@ -0,0 +1,24 @@
1
+ module Elastics
2
+ class Result < ::Hash
3
+
4
+ attr_reader :template, :response
5
+ attr_accessor :variables
6
+
7
+ def initialize(template, variables, response, result=nil)
8
+ @template = template
9
+ @variables = variables
10
+ @response = response
11
+ replace result || !response.body.empty? && MultiJson.decode(response.body) || return
12
+ Conf.result_extenders.each do |ext|
13
+ next if ext.respond_to?(:should_extend?) && !ext.should_extend?(self)
14
+ extend ext
15
+ end
16
+ end
17
+
18
+ def to_elastics_result(force=false)
19
+ return self if variables[:context].nil? || variables[:raw_result] &&! force
20
+ variables[:context].respond_to?(:elastics_result) ? variables[:context].elastics_result(self) : self
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module Elastics
2
+ class Result
3
+ module Bulk
4
+
5
+ # extend if result comes from a bulk url
6
+ def self.should_extend?(result)
7
+ result.response.url =~ /\b_bulk\b/
8
+ end
9
+
10
+ def failed
11
+ self['items'].reject{|i| i['index']['ok']}
12
+ end
13
+
14
+ def successful
15
+ self['items'].select{|i| i['index']['ok']}
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,67 @@
1
+ module Elastics
2
+ class Result
3
+
4
+ # adds sugar to documents with the following structure (_source is optional):
5
+ #
6
+ # {
7
+ # "_index" : "twitter",
8
+ # "_type" : "tweet",
9
+ # "_id" : "1",
10
+ # "_source" : {
11
+ # "user" : "kimchy",
12
+ # "postDate" : "2009-11-15T14:12:12",
13
+ # "message" : "trying out Elastics Search"
14
+ # }
15
+ # }
16
+
17
+ module Document
18
+
19
+ # extend if result has a structure like a document
20
+ def self.should_extend?(obj)
21
+ %w[_index _type _id].all? {|k| obj.has_key?(k)}
22
+ end
23
+
24
+ def respond_to?(meth, private=false)
25
+ smeth = meth.to_s
26
+ readers.has_key?(smeth) || has_key?(smeth) || has_key?("_#{smeth}") || super
27
+ end
28
+
29
+ # exposes _source and readers: automatically supply object-like reader access
30
+ # also expose meta readers like _id, _source, etc, also callable without the leading '_'
31
+ def method_missing(meth, *args, &block)
32
+ smeth = meth.to_s
33
+ case
34
+ # field name
35
+ when readers.has_key?(smeth)
36
+ readers[smeth]
37
+ # result item
38
+ when has_key?(smeth)
39
+ self[smeth]
40
+ # result item called without the '_' prefix
41
+ when has_key?("_#{smeth}")
42
+ self["_#{smeth}"]
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ # used to get the unprefixed (by live-reindex) index name
49
+ def index_basename
50
+ @index_basename ||= self['_index'].sub(/^\d{14}_/, '')
51
+ end
52
+
53
+
54
+ private
55
+
56
+ def readers
57
+ @readers ||= begin
58
+ readers = (self['_source']||{}).merge(self['fields']||{})
59
+ # flattened reader for multi_readers or attachment readers
60
+ readers.keys.each{|k| readers[k.gsub('.','_')] = readers.delete(k) if k.include?('.')}
61
+ readers
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,24 @@
1
+ module Elastics
2
+ class Result
3
+ module MultiGet
4
+
5
+ # extend if result comes from a search url
6
+ def self.should_extend?(result)
7
+ result.response.url =~ /\b_mget\b/ && result['docs']
8
+ end
9
+
10
+ # extend the hits results on extended
11
+ def self.extended(result)
12
+ result['docs'].each { |h| h.extend(Document) }
13
+ result['docs'].extend Struct::Paginable
14
+ result['docs'].setup(result['docs'].size, result.variables)
15
+ end
16
+
17
+ def docs
18
+ self['docs']
19
+ end
20
+ alias_method :collection, :docs
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ module Elastics
2
+ class Result
3
+ module Search
4
+
5
+ # extend if result comes from a search url
6
+ def self.should_extend?(result)
7
+ result.response.url =~ /\b_m?search\b/ && result['hits']
8
+ end
9
+
10
+ # extend the hits results on extended
11
+ def self.extended(result)
12
+ result['hits']['hits'].each { |h| h.extend(Document) }
13
+ result['hits']['hits'].extend Struct::Paginable
14
+ result['hits']['hits'].setup(result['hits']['total'], result.variables)
15
+ end
16
+
17
+ def collection
18
+ self['hits']['hits']
19
+ end
20
+ alias_method :documents, :collection
21
+
22
+ def facets
23
+ self['facets']
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module Elastics
2
+ module Struct
3
+ class Array < ::Array
4
+
5
+ include Symbolize
6
+
7
+ def push(*vals)
8
+ super *symbolize(vals)
9
+ end
10
+
11
+ def <<(val)
12
+ super symbolize(val)
13
+ end
14
+
15
+ def insert(*vals)
16
+ super *symbolize(vals)
17
+ end
18
+
19
+ def unshift(*vals)
20
+ super *symbolize(vals)
21
+ end
22
+
23
+ end
24
+ end
25
+ end