rubberband 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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