elastics-client 1.0.4

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.
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