elastics-client 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +28 -0
- data/VERSION +1 -0
- data/elastics-client.gemspec +33 -0
- data/lib/elastics.rb +108 -0
- data/lib/elastics/api_stubs.rb +1268 -0
- data/lib/elastics/api_templates/cluster_api.yml +94 -0
- data/lib/elastics/api_templates/core_api.yml +202 -0
- data/lib/elastics/api_templates/indices_api.yml +304 -0
- data/lib/elastics/class_proxy/base.rb +29 -0
- data/lib/elastics/class_proxy/templates.rb +97 -0
- data/lib/elastics/class_proxy/templates/doc.rb +91 -0
- data/lib/elastics/class_proxy/templates/search.rb +72 -0
- data/lib/elastics/configuration.rb +25 -0
- data/lib/elastics/deprecation.rb +153 -0
- data/lib/elastics/errors.rb +43 -0
- data/lib/elastics/http_clients/base.rb +15 -0
- data/lib/elastics/http_clients/loader.rb +51 -0
- data/lib/elastics/http_clients/patron.rb +29 -0
- data/lib/elastics/http_clients/rest_client.rb +36 -0
- data/lib/elastics/logger.rb +37 -0
- data/lib/elastics/prog_bar.rb +39 -0
- data/lib/elastics/rails.rb +1 -0
- data/lib/elastics/result.rb +24 -0
- data/lib/elastics/result/bulk.rb +20 -0
- data/lib/elastics/result/document.rb +67 -0
- data/lib/elastics/result/multi_get.rb +24 -0
- data/lib/elastics/result/search.rb +28 -0
- data/lib/elastics/struct/array.rb +25 -0
- data/lib/elastics/struct/hash.rb +105 -0
- data/lib/elastics/struct/paginable.rb +58 -0
- data/lib/elastics/struct/prunable.rb +60 -0
- data/lib/elastics/struct/symbolize.rb +27 -0
- data/lib/elastics/tasks.rb +62 -0
- data/lib/elastics/template.rb +124 -0
- data/lib/elastics/template/common.rb +42 -0
- data/lib/elastics/template/logger.rb +66 -0
- data/lib/elastics/template/partial.rb +28 -0
- data/lib/elastics/template/search.rb +30 -0
- data/lib/elastics/template/slim_search.rb +13 -0
- data/lib/elastics/template/tags.rb +56 -0
- data/lib/elastics/templates.rb +20 -0
- data/lib/elastics/utility_methods.rb +131 -0
- data/lib/elastics/utils.rb +103 -0
- data/lib/elastics/variables.rb +62 -0
- data/lib/tasks.rake +28 -0
- 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
|