lowang-rubberband 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ module ElasticSearch
2
+ module Api
3
+ module Admin
4
+ module Index
5
+ PSEUDO_INDICES = [:all]
6
+
7
+ def index_status(*args)
8
+ options = args.last.is_a?(Hash) ? args.pop : {}
9
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
10
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
11
+ execute(:index_status, indices, options)
12
+ end
13
+
14
+ # options: number_of_shards, number_of_replicas
15
+ def create_index(index, create_options={}, options={})
16
+ unless create_options[:index]
17
+ create_options = { :index => create_options }
18
+ end
19
+ execute(:create_index, index, create_options, options)
20
+ end
21
+
22
+ def delete_index(index, options={})
23
+ execute(:delete_index, index, options)
24
+ end
25
+
26
+ # :add => { "index" => "alias" }
27
+ # :add => [{"index" => "alias"}, {"index2" => "alias2"}]
28
+ # :add => { "index" => "alias", "index2" => "alias2" }
29
+ # :remove => { "index" => "alias" }
30
+ # :remove => [{"index" => "alias", {"index2" => "alias2"}]
31
+ # :remove => { "index" => "alias", "index2" => "alias2" }
32
+ # :actions => [{:add => {:index => "index", :alias => "alias"}}]
33
+ def alias_index(operations, options={})
34
+ if operations[:actions]
35
+ alias_ops = operations
36
+ else
37
+ alias_ops = { :actions => [] }
38
+ [:add, :remove].each do |op|
39
+ next unless operations.has_key?(op)
40
+ op_actions = operations[op].is_a?(Array) ? operations[op] : [operations[op]]
41
+ op_actions.each do |action_hash|
42
+ action_hash.each do |index, index_alias|
43
+ alias_ops[:actions] << { op => { :index => index, :alias => index_alias }}
44
+ end
45
+ end
46
+ end
47
+ end
48
+ execute(:alias_index, alias_ops, options)
49
+ end
50
+
51
+ # options: ignore_conflicts
52
+ def update_mapping(mapping, options={})
53
+ set_default_scope!(options)
54
+ raise "index and type or defaults required" unless options[:index] && options[:type]
55
+
56
+ options = options.dup
57
+ indices = Array(options.delete(:index))
58
+ type = options.delete(:type)
59
+ unless mapping[type]
60
+ mapping = { type => mapping }
61
+ end
62
+
63
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
64
+ execute(:update_mapping, indices, type, mapping, options)
65
+ end
66
+
67
+ # list of indices, or :all
68
+ # options: refresh
69
+ # default: default_index if defined, otherwise :all
70
+ def flush(*args)
71
+ options = args.last.is_a?(Hash) ? args.pop : {}
72
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
73
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
74
+ execute(:flush, indices, options)
75
+ end
76
+
77
+ # list of indices, or :all
78
+ # no options
79
+ # default: default_index if defined, otherwise all
80
+ def refresh(*args)
81
+ options = args.last.is_a?(Hash) ? args.pop : {}
82
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
83
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
84
+ execute(:refresh, indices, options)
85
+ end
86
+
87
+ # list of indices, or :all
88
+ # no options
89
+ # default: default_index if defined, otherwise all
90
+ def snapshot(*args)
91
+ options = args.last.is_a?(Hash) ? args.pop : {}
92
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
93
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
94
+ execute(:snapshot, indices, options)
95
+ end
96
+
97
+ # list of indices, or :all
98
+ # options: max_num_segments, only_expunge_deletes, refresh, flush
99
+ # default: default_index if defined, otherwise all
100
+ def optimize(*args)
101
+ options = args.last.is_a?(Hash) ? args.pop : {}
102
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
103
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
104
+ execute(:optimize, indices, options)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,21 @@
1
+ module ElasticSearch
2
+ module AutoDiscoveringClient
3
+
4
+ AUTO_DISCOVERING_DEFAULTS = {
5
+ :auto_discovery => true
6
+ }.freeze
7
+
8
+ def initialize(servers, options={})
9
+ super
10
+ @options = AUTO_DISCOVERING_DEFAULTS.merge(@options)
11
+ if @options[:auto_discovery]
12
+ auto_discover_nodes!
13
+ end
14
+ end
15
+
16
+ #TODO how to autodiscover on reconnect? don't want to overwrite methods of RetryingClient
17
+ def auto_discover_nodes!
18
+ @server_list = execute(:all_nodes)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ module ElasticSearch
2
+ module Api
3
+ module DefaultScope
4
+ def default_index
5
+ @default_index ||= @options[:index]
6
+ end
7
+
8
+ def default_index=(index)
9
+ @default_index = index
10
+ end
11
+
12
+ def default_type
13
+ @default_type ||= @options[:type]
14
+ end
15
+
16
+ def default_type=(type)
17
+ @default_type = type
18
+ end
19
+
20
+ private
21
+
22
+ def set_default_scope!(options)
23
+ options[:index] ||= default_index
24
+ options[:type] ||= default_type
25
+ nil
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,83 @@
1
+ require 'ostruct'
2
+
3
+ module ElasticSearch
4
+ module Api
5
+ class Hit < OpenStruct
6
+ undef_method :id if method_defined?(:id)
7
+
8
+ def initialize(hit)
9
+ hit = hit.dup
10
+ hit.merge!(hit["_source"]) if hit["_source"]
11
+ hit["id"] ||= hit["_id"]
12
+ super(hit)
13
+ @table.freeze
14
+ end
15
+
16
+ def attributes
17
+ @table
18
+ end
19
+ end
20
+
21
+ module Pagination
22
+ def current_page
23
+ (@options[:page].respond_to?(:empty?) ? @options[:page].empty? : !@options[:page]) ? 1 : @options[:page].to_i
24
+ end
25
+
26
+ def next_page
27
+ current_page >= total_pages ? nil : current_page + 1
28
+ end
29
+
30
+ def previous_page
31
+ current_page == 1 ? nil : current_page - 1
32
+ end
33
+
34
+ def per_page
35
+ @options[:per_page] || 10
36
+ end
37
+
38
+ def total_pages
39
+ (total_entries / per_page.to_f).ceil
40
+ end
41
+ alias_method :page_count, :total_pages
42
+ end
43
+
44
+
45
+ class Hits
46
+ include Pagination
47
+ attr_reader :hits, :total_entries, :_shards, :response, :facets, :scroll_id
48
+
49
+ def initialize(response, options={})
50
+ @response = response
51
+ @options = options
52
+ @total_entries = response["hits"]["total"]
53
+ @_shards = response["_shards"]
54
+ @facets = response["facets"]
55
+ @scroll_id = response["_scrollId"]
56
+ populate(@options[:ids_only])
57
+ end
58
+
59
+ def to_a
60
+ @hits
61
+ end
62
+
63
+ def freeze
64
+ @hits.freeze
65
+ super
66
+ end
67
+
68
+ def method_missing(method, *args, &block)
69
+ @hits.send(method, *args, &block)
70
+ end
71
+
72
+ def respond_to?(method, include_private = false)
73
+ super || @hits.respond_to?(method, include_private)
74
+ end
75
+
76
+ private
77
+
78
+ def populate(ids_only=false)
79
+ @hits = @response["hits"]["hits"].collect { |h| ids_only ? h["_id"] : Hit.new(h).freeze }
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,102 @@
1
+ require 'client/hits'
2
+
3
+ module ElasticSearch
4
+ module Api
5
+ module Index
6
+ def index(document, options={})
7
+ set_default_scope!(options)
8
+ raise "index and type or defaults required" unless options[:index] && options[:type]
9
+ # type
10
+ # index
11
+ # id (optional)
12
+ # op_type (optional)
13
+ # timeout (optional)
14
+ # document (optional)
15
+
16
+ result = execute(:index, options[:index], options[:type], options[:id], document, options)
17
+ if result["ok"]
18
+ result["_id"]
19
+ else
20
+ false
21
+ end
22
+ end
23
+
24
+ def get(id, options={})
25
+ set_default_scope!(options)
26
+ raise "index and type or defaults required" unless options[:index] && options[:type]
27
+ # index
28
+ # type
29
+ # id
30
+ # fields
31
+
32
+ hit = execute(:get, options[:index], options[:type], id, options)
33
+ if hit
34
+ Hit.new(hit).freeze
35
+ end
36
+ end
37
+
38
+ def delete(id, options={})
39
+ set_default_scope!(options)
40
+ raise "index and type or defaults required" unless options[:index] && options[:type]
41
+ result = execute(:delete, options[:index], options[:type], id, options)
42
+ result["ok"]
43
+ end
44
+
45
+ #df The default field to use when no field prefix is defined within the query.
46
+ #analyzer The analyzer name to be used when analyzing the query string.
47
+ #default_operator The default operator to be used, can be AND or OR. Defaults to OR.
48
+ #explain For each hit, contain an explanation of how to scoring of the hits was computed.
49
+ #fields The selective fields of the document to return for each hit (fields must be stored), comma delimited. Defaults to the internal _source field.
50
+ #field Same as fields above, but each parameter contains a single field name to load. There can be several field parameters.
51
+ #sort Sorting to perform. Can either be in the form of fieldName, or fieldName:reverse (for reverse sorting). The fieldName can either be an actual field within the document, or the special score name to indicate sorting based on scores. There can be several sort parameters (order is important).
52
+ #from The starting from index of the hits to return. Defaults to 0.
53
+ #size The number of hits to return. Defaults to 10.
54
+ #search_type The type of the search operation to perform. Can be dfs_query_then_fetch, dfs_query_and_fetch, query_then_fetch, query_and_fetch. Defaults to query_then_fetch.
55
+ #scroll Get a scroll id to continue paging through the search results. Value is the time to keep a scroll request around, e.g. 5m
56
+ #ids_only Return ids instead of hits
57
+ def search(query, options={})
58
+ set_default_scope!(options)
59
+
60
+ #TODO this doesn't work for facets, because they have a valid query key as element. need a list of valid toplevel keys in the search dsl
61
+ #query = {:query => query} if query.is_a?(Hash) && !query[:query] # if there is no query element, wrap query in one
62
+
63
+ search_options = slice_hash(options, :df, :analyzer, :default_operator, :explain, :fields, :field, :sort, :from, :size, :search_type, :limit, :per_page, :page, :offset, :scroll)
64
+
65
+ search_options[:size] ||= (search_options[:per_page] || search_options[:limit] || 10)
66
+ search_options[:from] ||= search_options[:size] * (search_options[:page].to_i-1) if search_options[:page] && search_options[:page].to_i > 1
67
+ search_options[:from] ||= search_options[:offset] if search_options[:offset]
68
+
69
+ search_options[:fields] = "_id" if options[:ids_only]
70
+
71
+ response = execute(:search, options[:index], options[:type], query, search_options)
72
+ Hits.new(response, slice_hash(options, :per_page, :page, :ids_only)).freeze #ids_only returns array of ids instead of hits
73
+ end
74
+
75
+ #ids_only Return ids instead of hits
76
+ def scroll(scroll_id, options={})
77
+ response = execute(:scroll, scroll_id)
78
+ Hits.new(response, slice_hash(options, :ids_only)).freeze
79
+ end
80
+
81
+ #df The default field to use when no field prefix is defined within the query.
82
+ #analyzer The analyzer name to be used when analyzing the query string.
83
+ #default_operator The default operator to be used, can be AND or OR. Defaults to OR.
84
+ def count(query, options={})
85
+ set_default_scope!(options)
86
+
87
+ count_options = slice_hash(options, :df, :analyzer, :default_operator)
88
+ response = execute(:count, options[:index], options[:type], query, count_options)
89
+ response["count"].to_i #TODO check if count is nil
90
+ end
91
+
92
+ private
93
+
94
+ def slice_hash(hash, *keys)
95
+ h = {}
96
+ keys.each { |k| h[k] = hash[k] if hash.has_key?(k) }
97
+ h
98
+ end
99
+
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,81 @@
1
+ # mostly ripped from thrift_client
2
+
3
+ module ElasticSearch
4
+ class NoServersAvailable < StandardError; end
5
+
6
+ module RetryingClient
7
+
8
+ RETRYING_DEFAULTS = {
9
+ :randomize_server_list => true,
10
+ :retries => nil,
11
+ :server_retry_period => 1,
12
+ :server_max_requests => nil,
13
+ :retry_overrides => {}
14
+ }.freeze
15
+
16
+ # use cluster status to get server list
17
+ def initialize(servers, options={})
18
+ super
19
+ @options = RETRYING_DEFAULTS.merge(@options)
20
+ @retries = options[:retries] || @server_list.size
21
+ @request_count = 0
22
+ @max_requests = @options[:server_max_requests]
23
+ @retry_period = @options[:server_retry_period]
24
+ rebuild_live_server_list!
25
+ end
26
+
27
+ def connect!
28
+ @current_server = next_server
29
+ super
30
+ rescue ElasticSearch::RetryableError
31
+ retry
32
+ end
33
+
34
+ def disconnect!
35
+ # Keep live servers in the list if we have a retry period. Otherwise,
36
+ # always eject, because we will always re-add them.
37
+ if @retry_period && @current_server
38
+ @live_server_list.unshift(@current_server)
39
+ end
40
+
41
+ super
42
+ @request_count = 0
43
+ end
44
+
45
+ #TODO this can spin indefinitely if timeout > retry_period
46
+ def next_server
47
+ if @retry_period
48
+ rebuild_live_server_list! if Time.now > @last_rebuild + @retry_period
49
+ raise NoServersAvailable, "No live servers in #{@server_list.inspect} since #{@last_rebuild.inspect}." if @live_server_list.empty?
50
+ elsif @live_server_list.empty?
51
+ rebuild_live_server_list!
52
+ end
53
+ @live_server_list.pop
54
+ end
55
+
56
+ def rebuild_live_server_list!
57
+ @last_rebuild = Time.now
58
+ if @options[:randomize_server_list]
59
+ @live_server_list = @server_list.sort_by { rand }
60
+ else
61
+ @live_server_list = @server_list.dup
62
+ end
63
+ end
64
+
65
+ def execute(method_name, *args)
66
+ disconnect_on_max! if @max_requests and @request_count >= @max_requests
67
+ @request_count += 1
68
+ begin
69
+ super
70
+ rescue ElasticSearch::RetryableError
71
+ disconnect!
72
+ retry
73
+ end
74
+ end
75
+
76
+ def disconnect_on_max!
77
+ @live_server_list.push(@current_server)
78
+ disconnect!
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,7 @@
1
+ require 'encoding/base'
2
+
3
+ module ElasticSearch
4
+ module Encoding
5
+ autoload :JSON, 'encoding/json'
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ module ElasticSearch
2
+ module Encoding
3
+ class Base
4
+ def encode(object)
5
+ raise "not implemented"
6
+ end
7
+
8
+ def decode(string)
9
+ raise "not implemented"
10
+ end
11
+
12
+ def is_encoded?(object)
13
+ raise "not implemented"
14
+ end
15
+ end
16
+ end
17
+ end