rubberband 0.0.5 → 0.0.6

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.
@@ -9,8 +9,9 @@ Copyright 2010 Grant Rodgers. See included LICENSE file.
9
9
 
10
10
  == Features
11
11
 
12
- * Automatic failover and retry
13
- * Multiple transports and encodings (TODO)
12
+ * Automatic failover, retry, and peer discovery
13
+ * Multiple transports (HTTP, Thrift, Memcached TODO)
14
+ * Multiple encodings (JSON (Yajl), Smile TODO)
14
15
 
15
16
  == Usage
16
17
 
@@ -18,7 +19,7 @@ Instantiate a client:
18
19
 
19
20
  client = ElasticSearch.new('127.0.0.1:9200', :index => "twitter", :type => "tweet")
20
21
 
21
- API is subject to change, but here is a trivial example:
22
+ API:
22
23
 
23
24
  client.index({:body => "elasticsearch is cool"}, :id => 1)
24
25
  client.get("1")
@@ -26,8 +27,7 @@ API is subject to change, but here is a trivial example:
26
27
 
27
28
  == TODO
28
29
 
29
- lots! :)
30
-
30
+ See TODO file.
31
31
 
32
32
  == Contributing
33
33
 
data/Rakefile CHANGED
@@ -27,7 +27,7 @@ Jeweler::RubygemsDotOrgTasks.new
27
27
  require 'rake/testtask'
28
28
  Rake::TestTask.new(:test) do |test|
29
29
  test.libs << 'lib' << 'test'
30
- test.pattern = 'test/**/test_*.rb'
30
+ test.pattern = 'test/**/*_test.rb'
31
31
  test.verbose = true
32
32
  end
33
33
 
data/TODO CHANGED
@@ -1,29 +1,9 @@
1
- index api:
2
- index*
3
- get*
4
- delete*
5
- delete_by_query
6
- count*
7
- search*
8
- terms
9
- more_like_this
10
- admin index api:
11
- status*
12
- create*
13
- delete*
14
- alias*
15
- mapping*
16
- flush*
17
- refresh*
18
- snapshot*
19
- optimize*
20
- admin cluster api:
21
- health*
22
- state*
23
- nodes info*
24
- nodes stats*
25
- nodes shutdown*
26
- nodes restart*
27
-
28
- handle partial failure cases where some shards are unsuccessful (maybe raise a PartialResult exception, allow override option to return results anyway. results should have a flag that signifies incompleteness)
1
+ delete_by_query
2
+ terms
3
+ more_like_this
4
+ bulk ops
5
+ test scroll better, maybe add a scroller object
6
+ handle partial failure cases where some shards are unsuccessful (optionally raise a PartialResult exception, allow override option to return results anyway. results should have a flag that signifies incompleteness)
29
7
  tests/specs/features
8
+ memcached transport
9
+ smile encoding
@@ -13,11 +13,16 @@ module ElasticSearch
13
13
  # timeout (optional)
14
14
  # document (optional)
15
15
 
16
- result = execute(:index, options[:index], options[:type], options[:id], document, options)
17
- if result["ok"]
18
- result["_id"]
16
+ if @batch
17
+ @batch << { :index => { :_index => options[:index], :_type => options[:type], :_id => options[:id] }}
18
+ @batch << document
19
19
  else
20
- false
20
+ result = execute(:index, options[:index], options[:type], options[:id], document, options)
21
+ if result["ok"]
22
+ result["_id"]
23
+ else
24
+ false
25
+ end
21
26
  end
22
27
  end
23
28
 
@@ -38,8 +43,13 @@ module ElasticSearch
38
43
  def delete(id, options={})
39
44
  set_default_scope!(options)
40
45
  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"]
46
+
47
+ if @batch
48
+ @batch << { :delete => { :_index => options[:index], :_type => options[:type], :_id => id }}
49
+ else
50
+ result = execute(:delete, options[:index], options[:type], id, options)
51
+ result["ok"]
52
+ end
43
53
  end
44
54
 
45
55
  #df The default field to use when no field prefix is defined within the query.
@@ -89,6 +99,16 @@ module ElasticSearch
89
99
  response["count"].to_i #TODO check if count is nil
90
100
  end
91
101
 
102
+ # Starts a bulk operation batch and yields self. Index and delete requests will be
103
+ # queued until the block closes, then sent as a single _bulk call.
104
+ def bulk
105
+ @batch = []
106
+ yield(self)
107
+ response = execute(:bulk, @batch)
108
+ ensure
109
+ @batch = nil
110
+ end
111
+
92
112
  private
93
113
 
94
114
  def slice_hash(hash, *keys)
@@ -10,5 +10,6 @@ module ElasticSearch
10
10
  module Transport
11
11
  autoload :HTTP, 'transport/http'
12
12
  autoload :Thrift, 'transport/thrift'
13
+ autoload :Memcached, 'transport/memcached'
13
14
  end
14
15
  end
@@ -68,6 +68,13 @@ module ElasticSearch
68
68
  handle_error(response) unless response.status == 200
69
69
  encoder.decode(response.body) # {"count", "_shards"=>{"failed", "total", "successful"}}
70
70
  end
71
+
72
+ def bulk(actions)
73
+ body = actions.inject("") { |a, s| a << encoder.encode(s) << "\n" }
74
+ response = request(:post, {:op => '_bulk'}, {}, body)
75
+ handle_error(response) unless response.status == 200
76
+ encoder.decode(response.body) # {"items => [ {"delete"/"create" => {"_index", "_type", "_id", "ok"}} ] }
77
+ end
71
78
  end
72
79
 
73
80
  module IndexAdminProtocol
@@ -154,8 +161,9 @@ module ElasticSearch
154
161
  def generate_uri(options)
155
162
  path = ""
156
163
  path << "/#{Array(options[:index]).collect { |i| escape(i.downcase) }.join(",")}" if options[:index] && !options[:index].empty?
164
+ path << "/" if options[:index] && options[:index].empty?
157
165
  path << "/#{Array(options[:type]).collect { |t| escape(t) }.join(",")}" if options[:type] && !options[:type].empty?
158
- path << "/#{Array(options[:id]).collect { |id| escape(id) }.join(",")}" if options[:id] && !options[:id].empty?
166
+ path << "/#{Array(options[:id]).collect { |id| escape(id) }.join(",")}" if options[:id] && !options[:id].to_s.empty?
159
167
  path << "/#{options[:op]}" if options[:op]
160
168
  path
161
169
  end
@@ -38,7 +38,7 @@ module ElasticSearch
38
38
  uri = generate_uri(operation)
39
39
  query = generate_query_string(params)
40
40
  path = [uri, query].join("?")
41
- #puts "request: #{@server} #{path} #{body}"
41
+ #puts "request: #{method} #{@server} #{path} #{body}"
42
42
  response = @session.request(method, path, headers, :data => body)
43
43
  handle_error(response) if response.status >= 500
44
44
  response
@@ -0,0 +1,72 @@
1
+ begin
2
+ require 'memcached'
3
+ rescue LoadError => error
4
+ raise "Please install the memcached gem to use the memcached transport."
5
+ end
6
+
7
+ module ElasticSearch
8
+ module Transport
9
+ class Memcached < Base
10
+ Response = Struct.new(:status, :headers, :body)
11
+
12
+ DEFAULTS = {
13
+ :timeout => 5
14
+ }.freeze
15
+
16
+ def initialize(server, options={})
17
+ super
18
+ @options = DEFAULTS.merge(@options)
19
+ end
20
+
21
+ def connect!
22
+ @memcached = ::Memcached.new(@server, :timeout => @options[:timeout]) #TODO allow passing other options?
23
+ end
24
+
25
+ def close
26
+ @memcached.quit
27
+ end
28
+
29
+ def all_nodes
30
+ memcached_addresses = nodes_info([])["nodes"].collect { |id, node| node["memcached_address"] }
31
+ memcached_addresses.collect! do |a|
32
+ if a =~ /inet\[.*\/([\d.:]+)\]/
33
+ $1
34
+ end
35
+ end.compact!
36
+ memcached_addresses
37
+ end
38
+
39
+ private
40
+
41
+ def request(method, operation, params={}, body=nil, headers={})
42
+ begin
43
+ uri = generate_uri(operation)
44
+ query = generate_query_string(params)
45
+ path = [uri, query].join("?")
46
+ #puts "request: #{method} #{@server} #{path} #{body}"
47
+ response = case method
48
+ when :get
49
+ @memcached.get(path, false)
50
+ when :put, :post
51
+ #TODO put vs post?
52
+ @memcached.set(path, body, 0, false)
53
+ when :delete
54
+ @memcached.delete(path)
55
+ end
56
+ #puts "response: #{response}"
57
+ response = Response.new(200, {}, response) #TODO
58
+ handle_error(response) if response.status >= 500
59
+ response
60
+ rescue Exception => e
61
+ case e
62
+ when TimeoutError
63
+ raise TimeoutError
64
+ else
65
+ raise e
66
+ end
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -76,7 +76,7 @@ module ElasticSearch
76
76
  when :get
77
77
  request.method = ElasticSearch::Thrift::Method::GET
78
78
  when :put
79
- request.method = ElasticSearch::Thrift::Method::GET
79
+ request.method = ElasticSearch::Thrift::Method::PUT
80
80
  when :post
81
81
  request.method = ElasticSearch::Thrift::Method::POST
82
82
  when :delete
@@ -2,7 +2,7 @@ module ElasticSearch
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- PATCH = 5
5
+ PATCH = 6
6
6
  BUILD = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rubberband}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["grantr"]
12
- s.date = %q{2010-12-06}
12
+ s.date = %q{2011-01-07}
13
13
  s.description = %q{An ElasticSearch client with ThriftClient-like failover handling.}
14
14
  s.email = %q{grantr@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -41,6 +41,7 @@ Gem::Specification.new do |s|
41
41
  "lib/elasticsearch/transport/base.rb",
42
42
  "lib/elasticsearch/transport/base_protocol.rb",
43
43
  "lib/elasticsearch/transport/http.rb",
44
+ "lib/elasticsearch/transport/memcached.rb",
44
45
  "lib/elasticsearch/transport/thrift.rb",
45
46
  "lib/elasticsearch/transport/thrift/elasticsearch_constants.rb",
46
47
  "lib/elasticsearch/transport/thrift/elasticsearch_types.rb",
@@ -51,6 +52,7 @@ Gem::Specification.new do |s|
51
52
  "test/elasticsearch_test.rb",
52
53
  "test/hits_test.rb",
53
54
  "test/test_helper.rb",
55
+ "test/type_test.rb",
54
56
  "vendor/elasticsearch/elasticsearch.thrift"
55
57
  ]
56
58
  s.homepage = %q{http://github.com/grantr/rubberband}
@@ -61,7 +63,8 @@ Gem::Specification.new do |s|
61
63
  s.test_files = [
62
64
  "test/elasticsearch_test.rb",
63
65
  "test/hits_test.rb",
64
- "test/test_helper.rb"
66
+ "test/test_helper.rb",
67
+ "test/type_test.rb"
65
68
  ]
66
69
 
67
70
  if s.respond_to? :specification_version then
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+
3
+ class TypeTest < Test::Unit::TestCase
4
+ context "Test with differents Types" do
5
+ #TODO figure out how to have one setup and one teardown
6
+ setup do
7
+ @client = ElasticSearch.new('127.0.0.1:9200', :index => "twitter", :type => "tweet")
8
+ @client.index({:user => "kimchy"}, :id => 1)
9
+ @client.index({:user => "kimchy"}, :id => 2, :type => "grillo")
10
+ @client.index({:user => "kimchy"}, :id => 3, :type => "cote")
11
+ @client.index({:user => "kimchy"}, :id => 4, :index => "cotes", :type => "cote")
12
+ @client.index({:user => "kimchy"}, :id => 5, :index => "menchos", :type => "mencho")
13
+ @client.index({:user => "kimchy"}, :id => 6, :index => "menchos", :type => "cote")
14
+ @client.refresh("twitter", "cotes", "menchos")
15
+ end
16
+
17
+ teardown do
18
+ #@client.delete_index("twitter")
19
+ #@client.delete_index("cotes")
20
+ #@client.delete_index("menchos")
21
+ end
22
+
23
+ should "search in all indexes" do
24
+ assert_equal @client.count("kimchy",{:index => "", :type => ""}), 6
25
+ end
26
+
27
+ should "search in all types with index twitter" do
28
+ assert_equal @client.count("kimchy",{:index => "twitter", :type => ""}), 3
29
+ end
30
+
31
+ should "search in index twitter with types tweet,cote" do
32
+ assert_equal @client.count("kimchy",{:index => "twitter", :type => "tweet,cote"}), 2
33
+ end
34
+
35
+ should "search in index twitter,cotes" do
36
+ assert_equal @client.count("kimchy",{:index => "twitter,cotes", :type => ""}), 4
37
+ end
38
+
39
+ should "search in types grillo,cote of all indexes" do
40
+ assert_equal @client.count("kimchy",{:index => "", :type => "grillo,cote"}), 4
41
+ end
42
+
43
+ end
44
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 5
9
- version: 0.0.5
8
+ - 6
9
+ version: 0.0.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - grantr
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-06 00:00:00 -08:00
17
+ date: 2011-01-07 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -133,6 +133,7 @@ files:
133
133
  - lib/elasticsearch/transport/base.rb
134
134
  - lib/elasticsearch/transport/base_protocol.rb
135
135
  - lib/elasticsearch/transport/http.rb
136
+ - lib/elasticsearch/transport/memcached.rb
136
137
  - lib/elasticsearch/transport/thrift.rb
137
138
  - lib/elasticsearch/transport/thrift/elasticsearch_constants.rb
138
139
  - lib/elasticsearch/transport/thrift/elasticsearch_types.rb
@@ -143,6 +144,7 @@ files:
143
144
  - test/elasticsearch_test.rb
144
145
  - test/hits_test.rb
145
146
  - test/test_helper.rb
147
+ - test/type_test.rb
146
148
  - vendor/elasticsearch/elasticsearch.thrift
147
149
  has_rdoc: true
148
150
  homepage: http://github.com/grantr/rubberband
@@ -158,7 +160,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
158
160
  requirements:
159
161
  - - ">="
160
162
  - !ruby/object:Gem::Version
161
- hash: -2243995552158926682
163
+ hash: -3014120754088484755
162
164
  segments:
163
165
  - 0
164
166
  version: "0"
@@ -181,3 +183,4 @@ test_files:
181
183
  - test/elasticsearch_test.rb
182
184
  - test/hits_test.rb
183
185
  - test/test_helper.rb
186
+ - test/type_test.rb