rubberband-pure 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.autotest +12 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +2 -0
  4. data/CONTRIBUTORS +13 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +202 -0
  7. data/README.rdoc +44 -0
  8. data/Rakefile +13 -0
  9. data/TODO +9 -0
  10. data/lib/elasticsearch.rb +14 -0
  11. data/lib/elasticsearch/client.rb +20 -0
  12. data/lib/elasticsearch/client/abstract_client.rb +55 -0
  13. data/lib/elasticsearch/client/admin_cluster.rb +56 -0
  14. data/lib/elasticsearch/client/admin_index.rb +149 -0
  15. data/lib/elasticsearch/client/auto_discovering_client.rb +21 -0
  16. data/lib/elasticsearch/client/default_scope.rb +36 -0
  17. data/lib/elasticsearch/client/hits.rb +82 -0
  18. data/lib/elasticsearch/client/index.rb +143 -0
  19. data/lib/elasticsearch/client/retrying_client.rb +81 -0
  20. data/lib/elasticsearch/encoding.rb +7 -0
  21. data/lib/elasticsearch/encoding/base.rb +17 -0
  22. data/lib/elasticsearch/encoding/json.rb +19 -0
  23. data/lib/elasticsearch/transport.rb +15 -0
  24. data/lib/elasticsearch/transport/base.rb +41 -0
  25. data/lib/elasticsearch/transport/base_protocol.rb +298 -0
  26. data/lib/elasticsearch/transport/http.rb +66 -0
  27. data/lib/elasticsearch/transport/memcached.rb +72 -0
  28. data/lib/elasticsearch/transport/thrift.rb +111 -0
  29. data/lib/elasticsearch/transport/thrift/elasticsearch_constants.rb +12 -0
  30. data/lib/elasticsearch/transport/thrift/elasticsearch_types.rb +124 -0
  31. data/lib/elasticsearch/transport/thrift/rest.rb +83 -0
  32. data/lib/elasticsearch/version.rb +3 -0
  33. data/lib/rubberband.rb +1 -0
  34. data/rubberband-pure.gemspec +37 -0
  35. data/spec/admin_spec.rb +43 -0
  36. data/spec/bulk_spec.rb +57 -0
  37. data/spec/connect_spec.rb +61 -0
  38. data/spec/hits_spec.rb +67 -0
  39. data/spec/http_spec.rb +15 -0
  40. data/spec/index_spec.rb +84 -0
  41. data/spec/spec_helper.rb +20 -0
  42. data/spec/type_spec.rb +47 -0
  43. data/vendor/elasticsearch/elasticsearch.thrift +81 -0
  44. metadata +183 -0
@@ -0,0 +1,149 @@
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
+ def index_mapping(*args)
15
+ options = args.last.is_a?(Hash) ? args.pop : {}
16
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
17
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
18
+ execute(:index_mapping, indices, options)
19
+ end
20
+
21
+ # options: number_of_shards, number_of_replicas
22
+ def create_index(index, create_options={}, options={})
23
+ unless create_options[:index]
24
+ create_options = { :index => create_options }
25
+ end
26
+ execute(:create_index, index, create_options, options)
27
+ end
28
+
29
+ def delete_index(index, options={})
30
+ execute(:delete_index, index, options)
31
+ end
32
+
33
+ # :add => { "index" => "alias" }
34
+ # :add => [{"index" => "alias"}, {"index2" => "alias2"}]
35
+ # :add => { "index" => "alias", "index2" => "alias2" }
36
+ # :remove => { "index" => "alias" }
37
+ # :remove => [{"index" => "alias", {"index2" => "alias2"}]
38
+ # :remove => { "index" => "alias", "index2" => "alias2" }
39
+ # :actions => [{:add => {:index => "index", :alias => "alias"}}]
40
+ def alias_index(operations, options={})
41
+ if operations[:actions]
42
+ alias_ops = operations
43
+ else
44
+ alias_ops = { :actions => [] }
45
+ [:add, :remove].each do |op|
46
+ next unless operations.has_key?(op)
47
+ op_actions = operations[op].is_a?(Array) ? operations[op] : [operations[op]]
48
+ op_actions.each do |action_hash|
49
+ action_hash.each do |index, index_alias|
50
+ alias_ops[:actions] << { op => { :index => index, :alias => index_alias }}
51
+ end
52
+ end
53
+ end
54
+ end
55
+ execute(:alias_index, alias_ops, options)
56
+ end
57
+
58
+ def get_aliases(index=default_index, options={})
59
+ index, type, options = extract_scope(options)
60
+ execute(:get_aliases, index, options)
61
+ end
62
+
63
+ # options: ignore_conflicts
64
+ def update_mapping(mapping, options={})
65
+ index, type, options = extract_required_scope(options)
66
+
67
+ options = options.dup
68
+ indices = Array(index)
69
+ unless mapping[type]
70
+ mapping = { type => mapping }
71
+ end
72
+
73
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
74
+ execute(:update_mapping, indices, type, mapping, options)
75
+ end
76
+
77
+ def delete_mapping(options={})
78
+ index, type, options = extract_required_scope(options)
79
+ execute(:delete_mapping, index, type, options)
80
+ end
81
+
82
+ def update_settings(settings, options={})
83
+ index, type, options = extract_scope(options)
84
+ execute(:update_settings, index, settings, options)
85
+ end
86
+
87
+ def get_settings(index=default_index, options={})
88
+ execute(:get_settings, index, options)
89
+ end
90
+
91
+ # list of indices, or :all
92
+ # options: refresh
93
+ # default: default_index if defined, otherwise :all
94
+ def flush(*args)
95
+ options = args.last.is_a?(Hash) ? args.pop : {}
96
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
97
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
98
+ execute(:flush, indices, options)
99
+ end
100
+
101
+ # list of indices, or :all
102
+ # no options
103
+ # default: default_index if defined, otherwise all
104
+ def refresh(*args)
105
+ options = args.last.is_a?(Hash) ? args.pop : {}
106
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
107
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
108
+ execute(:refresh, indices, options)
109
+ end
110
+
111
+ # list of indices, or :all
112
+ # no options
113
+ # default: default_index if defined, otherwise all
114
+ def snapshot(*args)
115
+ options = args.last.is_a?(Hash) ? args.pop : {}
116
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
117
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
118
+ execute(:snapshot, indices, options)
119
+ end
120
+
121
+ # list of indices, or :all
122
+ # options: max_num_segments, only_expunge_deletes, refresh, flush
123
+ # default: default_index if defined, otherwise all
124
+ def optimize(*args)
125
+ options = args.last.is_a?(Hash) ? args.pop : {}
126
+ indices = args.empty? ? [(default_index || :all)] : args.flatten
127
+ indices.collect! { |i| PSEUDO_INDICES.include?(i) ? "_#{i}" : i }
128
+ execute(:optimize, indices, options)
129
+ end
130
+
131
+ def create_river(type, create_options, options={})
132
+ execute(:create_river, type, create_options, options)
133
+ end
134
+
135
+ def get_river(type, options={})
136
+ execute(:get_river, type, options)
137
+ end
138
+
139
+ def river_status(type, options={})
140
+ execute(:river_status, type, options)
141
+ end
142
+
143
+ def delete_river(type=nil, options={})
144
+ execute(:delete_river, type, options)
145
+ end
146
+ end
147
+ end
148
+ end
149
+ 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,36 @@
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 extract_scope(options)
23
+ options = options.dup
24
+ index = options.delete(:index) || default_index
25
+ type = options.delete(:type) || default_type
26
+ [index, type, options]
27
+ end
28
+
29
+ def extract_required_scope(options)
30
+ scope = extract_scope(options)
31
+ raise "index and type or defaults required" unless scope[0] && scope[1]
32
+ scope
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,82 @@
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
+ end
14
+
15
+ def attributes
16
+ @table
17
+ end
18
+ end
19
+
20
+ module Pagination
21
+ def current_page
22
+ (@options[:page].respond_to?(:empty?) ? @options[:page].empty? : !@options[:page]) ? 1 : @options[:page].to_i
23
+ end
24
+
25
+ def next_page
26
+ current_page >= total_pages ? nil : current_page + 1
27
+ end
28
+
29
+ def previous_page
30
+ current_page == 1 ? nil : current_page - 1
31
+ end
32
+
33
+ def per_page
34
+ @options[:per_page] || 10
35
+ end
36
+
37
+ def total_pages
38
+ (total_entries / per_page.to_f).ceil
39
+ end
40
+ alias_method :page_count, :total_pages
41
+ end
42
+
43
+
44
+ class Hits
45
+ include Pagination
46
+ attr_reader :hits, :total_entries, :_shards, :response, :facets, :scroll_id
47
+
48
+ def initialize(response, options={})
49
+ @response = response
50
+ @options = options
51
+ @total_entries = response["hits"]["total"]
52
+ @_shards = response["_shards"]
53
+ @facets = response["facets"]
54
+ @scroll_id = response["_scroll_id"] || response["_scrollId"]
55
+ populate(@options[:ids_only])
56
+ end
57
+
58
+ def to_a
59
+ @hits
60
+ end
61
+
62
+ def freeze
63
+ @hits.freeze
64
+ super
65
+ end
66
+
67
+ def method_missing(method, *args, &block)
68
+ @hits.send(method, *args, &block)
69
+ end
70
+
71
+ def respond_to?(method, include_private = false)
72
+ super || @hits.respond_to?(method, include_private)
73
+ end
74
+
75
+ private
76
+
77
+ def populate(ids_only=false)
78
+ @hits = @response["hits"]["hits"].collect { |h| ids_only ? h["_id"] : Hit.new(h) }
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,143 @@
1
+ require 'client/hits'
2
+
3
+ module ElasticSearch
4
+ module Api
5
+ module Index
6
+ def index(document, options={})
7
+ index, type, options = extract_required_scope(options)
8
+ # type
9
+ # index
10
+ # id (optional)
11
+ # op_type (optional)
12
+ # timeout (optional)
13
+ # document (optional)
14
+
15
+ id = options.delete(:id)
16
+ if @batch
17
+ #TODO add routing, parent
18
+ @batch << { :index => { :_index => index, :_type => type, :_id => id }.merge(options)}
19
+ @batch << document
20
+ else
21
+ result = execute(:index, index, type, id, document, options)
22
+ if result["ok"]
23
+ result["_id"]
24
+ else
25
+ false
26
+ end
27
+ end
28
+ end
29
+
30
+ def get(id, options={})
31
+ index, type, options = extract_required_scope(options)
32
+ # index
33
+ # type
34
+ # id
35
+ # fields
36
+
37
+ hit = execute(:get, index, type, id, options)
38
+ if hit
39
+ Hit.new(hit)
40
+ end
41
+ end
42
+
43
+ def delete(id, options={})
44
+ index, type, options = extract_required_scope(options)
45
+
46
+ if @batch
47
+ #TODO add routing, parent
48
+ @batch << { :delete => { :_index => index, :_type => type, :_id => id }}
49
+ else
50
+ result = execute(:delete, index, type, id, options)
51
+ result["ok"]
52
+ end
53
+ end
54
+
55
+ def delete_by_query(query, options = {})
56
+ index, type, options = extract_required_scope(options)
57
+ execute(:delete_by_query, index, type, query, options)
58
+ end
59
+
60
+ #df The default field to use when no field prefix is defined within the query.
61
+ #analyzer The analyzer name to be used when analyzing the query string.
62
+ #default_operator The default operator to be used, can be AND or OR. Defaults to OR.
63
+ #explain For each hit, contain an explanation of how to scoring of the hits was computed.
64
+ #fields The selective fields of the document to return for each hit (fields must be stored), comma delimited. Defaults to the internal _source field.
65
+ #field Same as fields above, but each parameter contains a single field name to load. There can be several field parameters.
66
+ #sort Sorting to perform. Can either be in the form of fieldName, or fieldName:desc (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).
67
+ #from The starting from index of the hits to return. Defaults to 0.
68
+ #size The number of hits to return. Defaults to 10.
69
+ #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.
70
+ #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
71
+ #ids_only Return ids instead of hits
72
+ def search(query, options={})
73
+ index, type, options = extract_scope(options)
74
+
75
+ options[:size] ||= (options[:per_page] || options[:limit] || 10)
76
+ options[:from] ||= options[:size] * (options[:page].to_i-1) if options[:page] && options[:page].to_i > 1
77
+ options[:from] ||= options[:offset] if options[:offset]
78
+
79
+ options[:fields] = "_id" if options[:ids_only]
80
+
81
+ # options that elasticsearch doesn't recognize: page, per_page, ids_only, limit, offset
82
+ search_options = options.reject { |k, v| [:page, :per_page, :ids_only, :limit, :offset].include?(k) }
83
+
84
+ response = execute(:search, index, type, query, search_options)
85
+
86
+ Hits.new(response, {:per_page => options[:per_page], :page => options[:page], :ids_only => options[:ids_only]}) #ids_only returns array of ids instead of hits
87
+ end
88
+
89
+ #ids_only Return ids instead of hits
90
+ #pass a block to execute the block for each batch of hits
91
+ def scroll(scroll_id, options={}, &block)
92
+ begin
93
+ search_options = options.reject { |k, v| [:page, :per_page, :ids_only, :limit, :offset].include?(k) }
94
+ response = execute(:scroll, scroll_id, options)
95
+ hits = Hits.new(response, { :ids_only => options[:ids_only] })
96
+ if block_given? && !hits.empty?
97
+ yield hits
98
+ scroll_id = hits.scroll_id
99
+ end
100
+ end until !block_given? || hits.empty?
101
+ hits
102
+ end
103
+
104
+ #df The default field to use when no field prefix is defined within the query.
105
+ #analyzer The analyzer name to be used when analyzing the query string.
106
+ #default_operator The default operator to be used, can be AND or OR. Defaults to OR.
107
+ def count(query, options={})
108
+ index, type, options = extract_scope(options)
109
+
110
+ response = execute(:count, index, type, query, options)
111
+ response["count"].to_i #TODO check if count is nil
112
+ end
113
+
114
+ # Starts a bulk operation batch and yields self. Index and delete requests will be
115
+ # queued until the block closes, then sent as a single _bulk call.
116
+ def bulk(options={})
117
+ # allow nested bulk calls
118
+ if @batch
119
+ yield(self)
120
+ else
121
+ begin
122
+ @batch = []
123
+ yield(self)
124
+ response = execute(:bulk, @batch, options)
125
+ ensure
126
+ @batch = nil
127
+ end
128
+ end
129
+ end
130
+
131
+ # minor multi get support
132
+ def multi_get(ids, options={})
133
+ index, type, options = extract_required_scope(options)
134
+ results = execute(:multi_get, index, type, ids, options)
135
+ if(results)
136
+ hits = []
137
+ results.each { |hit| hits << Hit.new(hit) }
138
+ hits
139
+ end
140
+ end
141
+ end
142
+ end
143
+ 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