hbase-driver 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +25 -0
- data/lib/hbase.rb +9 -0
- data/lib/hbase/cell.rb +9 -0
- data/lib/hbase/hbase.rb +42 -0
- data/lib/hbase/record.rb +22 -0
- data/lib/hbase/support.rb +9 -0
- data/lib/hbase/table.rb +75 -0
- data/lib/stargate.rb +7 -0
- data/lib/stargate/client.rb +93 -0
- data/lib/stargate/exception.rb +21 -0
- data/lib/stargate/model.rb +19 -0
- data/lib/stargate/model/column.rb +9 -0
- data/lib/stargate/model/column_descriptor.rb +32 -0
- data/lib/stargate/model/region_descriptor.rb +9 -0
- data/lib/stargate/model/row.rb +18 -0
- data/lib/stargate/model/scanner.rb +16 -0
- data/lib/stargate/model/table_descriptor.rb +8 -0
- data/lib/stargate/operation/meta_operation.rb +20 -0
- data/lib/stargate/operation/row_operation.rb +86 -0
- data/lib/stargate/operation/scanner_operation.rb +90 -0
- data/lib/stargate/operation/table_operation.rb +95 -0
- data/lib/stargate/request.rb +7 -0
- data/lib/stargate/request/basic_request.rb +27 -0
- data/lib/stargate/request/meta_request.rb +25 -0
- data/lib/stargate/request/row_request.rb +34 -0
- data/lib/stargate/request/scanner_request.rb +25 -0
- data/lib/stargate/request/table_request.rb +43 -0
- data/lib/stargate/response.rb +7 -0
- data/lib/stargate/response/basic_response.rb +30 -0
- data/lib/stargate/response/meta_response.rb +35 -0
- data/lib/stargate/response/row_response.rb +47 -0
- data/lib/stargate/response/scanner_response.rb +41 -0
- data/lib/stargate/response/table_response.rb +26 -0
- data/readme.md +47 -0
- metadata +103 -0
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new('spec') do |t|
|
6
|
+
t.pattern = "spec/**/[^_]*_spec.rb"
|
7
|
+
end
|
8
|
+
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
spec = Gem::Specification.new do |s|
|
12
|
+
s.name = "hbase-driver"
|
13
|
+
s.version = '0.0.1'
|
14
|
+
s.summary = "HBase Ruby Driver"
|
15
|
+
s.homepage = "http://github.com/railsware/hbase-driver"
|
16
|
+
s.email = ["Alexey.Petrushin@railsware.com", "dmitry.larkin@railsware.com"]
|
17
|
+
s.authors = ["Alexey Petrushin", "Dmitry Larkin"]
|
18
|
+
s.files = FileList["{lib}/**/*"].to_a + %w(readme.md Rakefile)
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.has_rdoc = false
|
21
|
+
end
|
22
|
+
|
23
|
+
Rake::GemPackageTask.new(spec) do |p|
|
24
|
+
p.gem_spec = spec
|
25
|
+
end
|
data/lib/hbase.rb
ADDED
data/lib/hbase/cell.rb
ADDED
data/lib/hbase/hbase.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
class HBase
|
2
|
+
attr_reader :stargate
|
3
|
+
|
4
|
+
def initialize *args
|
5
|
+
@stargate = Stargate::Client.new *args
|
6
|
+
end
|
7
|
+
|
8
|
+
def get table_name
|
9
|
+
HBase::Table.new stargate, table_name
|
10
|
+
end
|
11
|
+
alias_method :[], :get
|
12
|
+
|
13
|
+
def delete table_name
|
14
|
+
stargate.delete_table table_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def truncate table_name
|
18
|
+
stargate.truncate table_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def all
|
22
|
+
stargate.list_tables
|
23
|
+
end
|
24
|
+
alias_method :list, :all
|
25
|
+
|
26
|
+
def include? table_name
|
27
|
+
all.any?{|meta| meta.name == table_name}
|
28
|
+
end
|
29
|
+
alias_method :exist?, :include?
|
30
|
+
|
31
|
+
def create *args
|
32
|
+
stargate.create_table *args
|
33
|
+
end
|
34
|
+
|
35
|
+
def disable *args
|
36
|
+
stargate.disable_table *args
|
37
|
+
end
|
38
|
+
|
39
|
+
def enable *args
|
40
|
+
stargate.enable_table *args
|
41
|
+
end
|
42
|
+
end
|
data/lib/hbase/record.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
class HBase
|
2
|
+
class Record
|
3
|
+
attr_reader :cells
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@cells = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(key)
|
10
|
+
if cell = cells[key]
|
11
|
+
cell.value
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
end
|
16
|
+
alias_method :[], :get
|
17
|
+
|
18
|
+
def size
|
19
|
+
cells.size
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/hbase/table.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
class HBase
|
2
|
+
class Table
|
3
|
+
attr_reader :stargate, :table_name
|
4
|
+
|
5
|
+
def initialize(stargate, table_name)
|
6
|
+
@stargate, @table_name = stargate, table_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(key, with_timestamps = false)
|
10
|
+
begin
|
11
|
+
record = Record.new
|
12
|
+
old_row = stargate.show_row(table_name, key)
|
13
|
+
old_row.columns.each do |old_cell|
|
14
|
+
record.cells[old_cell.name] = Cell.new old_cell.value, old_cell.timestamp
|
15
|
+
end
|
16
|
+
record
|
17
|
+
rescue Stargate::RowNotFoundError
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
alias_method :[], :get
|
22
|
+
|
23
|
+
def update(key, attributes)
|
24
|
+
raise "ivalid usage, attributes should be a hash!" unless attributes.is_a? Hash
|
25
|
+
timestamp = attributes.delete(:timestamp) || attributes.delete('timestamp') # || Time.now.to_i
|
26
|
+
attr_in_driver_format = attributes.to_a.collect do |attr_name, attr_value|
|
27
|
+
{:name => attr_name, :value => attr_value}
|
28
|
+
end
|
29
|
+
stargate.create_row(table_name, key, timestamp, attr_in_driver_format)
|
30
|
+
end
|
31
|
+
alias_method :[]=, :update
|
32
|
+
|
33
|
+
def delete(key)
|
34
|
+
stargate.delete_row table_name, key
|
35
|
+
end
|
36
|
+
|
37
|
+
def include?(key)
|
38
|
+
!!get(key)
|
39
|
+
end
|
40
|
+
alias_method :exist?, :include?
|
41
|
+
|
42
|
+
def metadata
|
43
|
+
stargate.show_table table_name
|
44
|
+
end
|
45
|
+
|
46
|
+
TRANSLATION = {
|
47
|
+
:start => :start_row,
|
48
|
+
:end => :end_row
|
49
|
+
}
|
50
|
+
def scan(options = {})
|
51
|
+
options.symbolize_keys
|
52
|
+
|
53
|
+
stargate_options = {}
|
54
|
+
options.each do |k, v|
|
55
|
+
stargate_options[TRANSLATION[k] || k] = v
|
56
|
+
end
|
57
|
+
|
58
|
+
scanner = stargate.open_scanner(table_name, stargate_options)
|
59
|
+
begin
|
60
|
+
old_rows = stargate.get_rows(scanner)
|
61
|
+
records = []
|
62
|
+
old_rows.each do |old_row|
|
63
|
+
old_row.columns.each do |old_cell|
|
64
|
+
record = Record.new
|
65
|
+
record.cells[old_cell.name] = Cell.new old_cell.value, old_cell.timestamp
|
66
|
+
records << record
|
67
|
+
end
|
68
|
+
end
|
69
|
+
records
|
70
|
+
ensure
|
71
|
+
stargate.close_scanner(scanner) if scanner
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/stargate.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
module Stargate end
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), "stargate", "client")
|
4
|
+
require File.join(File.dirname(__FILE__), "stargate", "exception")
|
5
|
+
require File.join(File.dirname(__FILE__), "stargate", "model")
|
6
|
+
require File.join(File.dirname(__FILE__), "stargate", "request")
|
7
|
+
require File.join(File.dirname(__FILE__), "stargate", "response")
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require File.dirname(__FILE__) + '/operation/meta_operation'
|
3
|
+
require File.dirname(__FILE__) + '/operation/table_operation'
|
4
|
+
require File.dirname(__FILE__) + '/operation/row_operation'
|
5
|
+
require File.dirname(__FILE__) + '/operation/scanner_operation'
|
6
|
+
|
7
|
+
module Stargate
|
8
|
+
class Client
|
9
|
+
VERSION = 1 #File.read(File.join(File.dirname(__FILE__), "..", "..", "VERSION")).chomp.freeze
|
10
|
+
|
11
|
+
include Operation::MetaOperation
|
12
|
+
include Operation::TableOperation
|
13
|
+
include Operation::RowOperation
|
14
|
+
include Operation::ScannerOperation
|
15
|
+
|
16
|
+
attr_reader :url, :connection
|
17
|
+
|
18
|
+
def initialize(url = "http://localhost:8080", opts = {})
|
19
|
+
@url = URI.parse(url)
|
20
|
+
unless @url.kind_of? URI::HTTP
|
21
|
+
raise "invalid http url: #{url}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Not actually opening the connection yet, just setting up the persistent connection.
|
25
|
+
if opts[:proxy]
|
26
|
+
proxy_address, proxy_port = opts[:proxy].split(':')
|
27
|
+
@connection = Net::HTTP.Proxy(proxy_address, proxy_port).new(@url.host, @url.port)
|
28
|
+
else
|
29
|
+
@connection = Net::HTTP.new(@url.host, @url.port)
|
30
|
+
end
|
31
|
+
@connection.read_timeout = opts[:timeout] if opts[:timeout]
|
32
|
+
end
|
33
|
+
|
34
|
+
def get(path, options = {})
|
35
|
+
safe_request { @connection.get(@url.path + path, {'Content-Type' => 'text/xml', "Accept" => "application/json"}.merge(options)) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_response(path, options = {})
|
39
|
+
safe_response { @connection.get(@url.path + path, {"Accept" => "application/json"}.merge(options)) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def post(path, data = nil, options = {})
|
43
|
+
safe_request { @connection.post(@url.path + path, data, {'Content-Type' => 'text/xml', "Accept" => "application/json"}.merge(options)) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def post_response(path, data = nil, options = {})
|
47
|
+
safe_response { @connection.post(@url.path + path, data, {'Content-Type' => 'text/xml', "Accept" => "application/json"}.merge(options)) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def delete(path, options = {})
|
51
|
+
safe_request { @connection.delete(@url.path + path, options) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_response(path, options = {})
|
55
|
+
safe_response { @connection.delete(@url.path + path, options) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def put(path, data = nil, options = {})
|
59
|
+
safe_request { @connection.put(@url.path + path, data, {'Content-Type' => 'text/xml', "Accept" => "application/json"}.merge(options)) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def put_response(path, data = nil, options = {})
|
63
|
+
safe_response { @connection.put(@url.path + path, data, {'Content-Type' => 'text/xml', "Accept" => "application/json"}.merge(options)) }
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Part of safe_request was broken up into safe_response because when working with scanners
|
69
|
+
# in Stargate, you need to have access to the response itself, and not just the body.
|
70
|
+
def safe_response(&block)
|
71
|
+
begin
|
72
|
+
yield
|
73
|
+
rescue Errno::ECONNREFUSED
|
74
|
+
raise ConnectionNotEstablishedError, "can't connect to #{@url}"
|
75
|
+
rescue Timeout::Error => e
|
76
|
+
puts e.backtrace.join("\n")
|
77
|
+
raise ConnectionTimeoutError, "execution expired. Maybe query disabled tables"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def safe_request(&block)
|
82
|
+
response = safe_response{ yield block }
|
83
|
+
|
84
|
+
case response
|
85
|
+
when Net::HTTPSuccess
|
86
|
+
response.body
|
87
|
+
else
|
88
|
+
response.error!
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Stargate::Exception < StandardError; end
|
2
|
+
|
3
|
+
class Stargate::ConnectionNotEstablishedError < Stargate::Exception; end
|
4
|
+
|
5
|
+
class Stargate::ConnectionTimeoutError < Stargate::Exception; end
|
6
|
+
|
7
|
+
class Stargate::TableNotFoundError < Stargate::Exception; end
|
8
|
+
|
9
|
+
class Stargate::TableExistsError < Stargate::Exception; end
|
10
|
+
|
11
|
+
class Stargate::TableFailCreateError < Stargate::Exception; end
|
12
|
+
|
13
|
+
class Stargate::TableNotDisabledError < Stargate::Exception; end
|
14
|
+
|
15
|
+
class Stargate::TableFailDisableError < Stargate::Exception; end
|
16
|
+
|
17
|
+
class Stargate::TableFailEnableError < Stargate::Exception; end
|
18
|
+
|
19
|
+
class Stargate::RowNotFoundError < Stargate::Exception; end
|
20
|
+
|
21
|
+
class Stargate::ScannerError < Stargate::Exception; end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Model
|
3
|
+
class Record
|
4
|
+
def initialize (params)
|
5
|
+
params.each do |key, value|
|
6
|
+
name = key.to_s
|
7
|
+
instance_variable_set("@#{name}", value) if respond_to?(name)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require File.dirname(__FILE__) + '/model/column'
|
15
|
+
require File.dirname(__FILE__) + '/model/column_descriptor'
|
16
|
+
require File.dirname(__FILE__) + '/model/region_descriptor'
|
17
|
+
require File.dirname(__FILE__) + '/model/row'
|
18
|
+
require File.dirname(__FILE__) + '/model/table_descriptor'
|
19
|
+
require File.dirname(__FILE__) + '/model/scanner'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Model
|
3
|
+
module CompressionType
|
4
|
+
NONE = "NONE"
|
5
|
+
RECORD = "RECORD"
|
6
|
+
BLOCK = "BLOCK"
|
7
|
+
|
8
|
+
CTYPES = [NONE, RECORD, BLOCK]
|
9
|
+
|
10
|
+
def to_compression_type(type_string)
|
11
|
+
CTYPES.include?(type_string) ? type_string : NONE
|
12
|
+
end
|
13
|
+
|
14
|
+
module_function :to_compression_type
|
15
|
+
end
|
16
|
+
|
17
|
+
class ColumnDescriptor < Record
|
18
|
+
AVAILABLE_OPTS = { :name => "name", :max_versions => "VERSIONS", :versions => "VERSIONS",
|
19
|
+
:compression => "COMPRESSION", :in_memory => "IN_MEMORY",
|
20
|
+
:block_cache => "BLOCKCACHE", :blockcache => "BLOCKCACHE",
|
21
|
+
:blocksize => "BLOCKSIZE", :length => "LENGTH", :ttl => "TTL",
|
22
|
+
:bloomfilter => "BLOOMFILTER"}
|
23
|
+
attr_accessor :name
|
24
|
+
attr_accessor :compression
|
25
|
+
attr_accessor :bloomfilter
|
26
|
+
attr_accessor :maximum_cell_size
|
27
|
+
attr_accessor :max_versions
|
28
|
+
|
29
|
+
attr_accessor :versions
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Model
|
3
|
+
class Row < Record
|
4
|
+
attr_accessor :table_name
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :total_count
|
7
|
+
attr_accessor :columns
|
8
|
+
|
9
|
+
def timestamp
|
10
|
+
warn "[DEPRECATION] timestamp attribute will be removed from the Row model. "
|
11
|
+
end
|
12
|
+
|
13
|
+
def timestamp=
|
14
|
+
timestamp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Model
|
3
|
+
class Scanner < Record
|
4
|
+
AVAILABLE_OPTS = { :start_row => "startRow", :end_row => "endRow",
|
5
|
+
:start_time => "startTime", :end_time => "endTime",
|
6
|
+
:batch => "batch" }
|
7
|
+
|
8
|
+
attr_accessor :table_name
|
9
|
+
attr_accessor :scanner_url
|
10
|
+
attr_accessor :batch_size
|
11
|
+
|
12
|
+
# Deprecation: scanner_url is used instead of just the ID
|
13
|
+
attr_accessor :scanner_id
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Operation
|
3
|
+
module MetaOperation
|
4
|
+
def list_tables
|
5
|
+
request = Request::MetaRequest.new
|
6
|
+
Response::MetaResponse.new(get(request.list_tables), :list_tables).parse
|
7
|
+
end
|
8
|
+
|
9
|
+
def version
|
10
|
+
request = Request::MetaRequest.new
|
11
|
+
get(request.version, {"Accept" => "text/plain"}).strip
|
12
|
+
end
|
13
|
+
|
14
|
+
def cluster_version
|
15
|
+
request = Request::MetaRequest.new
|
16
|
+
get(request.cluster_version, {"Accept" => "text/plain"}).strip
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Operation
|
3
|
+
module RowOperation
|
4
|
+
Converter = {
|
5
|
+
'&' => '&',
|
6
|
+
'<' => '<',
|
7
|
+
'>' => '>',
|
8
|
+
"'" => ''',
|
9
|
+
'"' => '"'
|
10
|
+
}
|
11
|
+
|
12
|
+
def row_timestamps(table_name, name)
|
13
|
+
raise NotImplementedError, "Currently not supported in Stargate client"
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_row(table_name, name, timestamp = nil, columns = nil, options = { })
|
17
|
+
begin
|
18
|
+
options[:version] ||= 1
|
19
|
+
|
20
|
+
request = Request::RowRequest.new(table_name, name, timestamp)
|
21
|
+
row = Response::RowResponse.new(get(request.show(columns, options)), :show_row).parse.first
|
22
|
+
row.table_name = table_name
|
23
|
+
row
|
24
|
+
rescue Net::ProtocolError => e
|
25
|
+
# TODO: Use better handling instead of this.
|
26
|
+
if e.to_s.include?("Table")
|
27
|
+
raise TableNotFoundError, "Table '#{table_name}' Not Found"
|
28
|
+
elsif e.to_s.include?("404")
|
29
|
+
raise RowNotFoundError, "Row '#{name}' Not Found"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_row(table_name, name, timestamp = nil, columns = nil)
|
35
|
+
begin
|
36
|
+
request = Request::RowRequest.new(table_name, name, timestamp)
|
37
|
+
data = []
|
38
|
+
if columns
|
39
|
+
if columns.instance_of? Array
|
40
|
+
data = columns
|
41
|
+
elsif columns.instance_of? Hash
|
42
|
+
data = [columns]
|
43
|
+
else
|
44
|
+
raise StandardError, "Only Array or Hash data accepted"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
xml_data = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><CellSet>"
|
49
|
+
xml_data << "<Row key='#{[name].pack('m') rescue ''}'>"
|
50
|
+
data.each do |d|
|
51
|
+
escape_name = d[:name].gsub(/[&<>'"]/) { |match| Converter[match] }
|
52
|
+
xml_data << "<Cell "
|
53
|
+
xml_data << "timestamp='#{timestamp}' " if timestamp
|
54
|
+
xml_data << "column='#{[escape_name].pack('m') rescue ''}'>"
|
55
|
+
xml_data << "#{[d[:value]].pack("m") rescue ''}"
|
56
|
+
xml_data << "</Cell>"
|
57
|
+
end
|
58
|
+
xml_data << "</Row></CellSet>"
|
59
|
+
|
60
|
+
Response::RowResponse.new(post_response(request.create(data.map{|col| col[:name]}), xml_data), :create_row).parse
|
61
|
+
rescue Net::ProtocolError => e
|
62
|
+
if e.to_s.include?("Table")
|
63
|
+
raise TableNotFoundError, "Table '#{table_name}' Not Found"
|
64
|
+
elsif e.to_s.include?("Row")
|
65
|
+
raise RowNotFoundError, "Row '#{name}' Not Found"
|
66
|
+
else
|
67
|
+
raise StandardError, "Error encountered while trying to create row: #{e.message}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_row(table_name, name, timestamp = nil, columns = nil)
|
73
|
+
begin
|
74
|
+
request = Request::RowRequest.new(table_name, name, timestamp)
|
75
|
+
Response::RowResponse.new(delete_response(request.delete(columns)), :delete_row).parse
|
76
|
+
rescue Net::ProtocolError => e
|
77
|
+
if e.to_s.include?("Table")
|
78
|
+
raise TableNotFoundError, "Table '#{table_name}' Not Found"
|
79
|
+
elsif e.to_s.include?("Row")
|
80
|
+
raise RowNotFoundError, "Row '#{name}' Not Found"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Operation
|
3
|
+
module ScannerOperation
|
4
|
+
# Trying to maintain some API stability for now
|
5
|
+
def open_scanner(table_name, columns, start_row, stop_row = nil, timestamp = nil)
|
6
|
+
warn "[DEPRECATION] This method is deprecated. Use #open_scanner(table_name, options = {}) instead."
|
7
|
+
|
8
|
+
open_scanner(table_name, {:columns => columns, :start_row => start_row, :stop_row => stop_row, :timestamp => timestamp})
|
9
|
+
end
|
10
|
+
|
11
|
+
def open_scanner(table_name, options = {})
|
12
|
+
raise ArgumentError, "options should be given as a Hash" unless options.instance_of? Hash
|
13
|
+
columns = options.delete(:columns)
|
14
|
+
batch = options.delete(:batch) || "10"
|
15
|
+
|
16
|
+
begin
|
17
|
+
request = Request::ScannerRequest.new(table_name)
|
18
|
+
|
19
|
+
xml_data = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><Scanner batch='#{batch}' "
|
20
|
+
options.each do |key,value|
|
21
|
+
if Model::Scanner::AVAILABLE_OPTS.include? key
|
22
|
+
xml_data << "#{Model::Scanner::AVAILABLE_OPTS[key]}='#{[value.to_s].flatten.pack('m')}' "
|
23
|
+
else
|
24
|
+
warn "[open_scanner] Received invalid option key :#{key}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
if columns
|
28
|
+
xml_data << ">"
|
29
|
+
[columns].flatten.each do |col|
|
30
|
+
xml_data << "<column>#{[col].flatten.pack('m')}</column>"
|
31
|
+
end
|
32
|
+
xml_data << "</Scanner>"
|
33
|
+
else
|
34
|
+
xml_data << "/>"
|
35
|
+
end
|
36
|
+
|
37
|
+
scanner = Response::ScannerResponse.new(post_response(request.open, xml_data), :open_scanner).parse
|
38
|
+
scanner.table_name = table_name
|
39
|
+
scanner.batch_size = batch
|
40
|
+
scanner
|
41
|
+
rescue Net::ProtocolError => e
|
42
|
+
raise StandardError, e.to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_rows(scanner, limit = nil)
|
47
|
+
begin
|
48
|
+
request = Request::ScannerRequest.new(scanner.table_name)
|
49
|
+
request_url = request.get_rows(scanner) # The url to the scanner is the same for each batch
|
50
|
+
|
51
|
+
rows = []
|
52
|
+
begin
|
53
|
+
# Loop until we've reached the limit, or the scanner was exhausted (HTTP 204 returned)
|
54
|
+
until (limit && rows.size >= limit) || (response = get_response(request_url)).code == "204"
|
55
|
+
rows.concat Response::ScannerResponse.new(response.body, :get_rows).parse
|
56
|
+
|
57
|
+
rows.each do |row|
|
58
|
+
row.table_name = scanner.table_name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
rescue Exception => e
|
62
|
+
raise Stargate::ScannerError, "Scanner failed while getting rows. #{e.message}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Prune the last few rows if the limit was passed.
|
66
|
+
(limit) ? rows.slice(0, limit) : rows
|
67
|
+
rescue StandardError => e
|
68
|
+
if e.to_s.include?("TableNotFoundException")
|
69
|
+
raise TableNotFoundError, "Table #{table_name} Not Found!"
|
70
|
+
else
|
71
|
+
raise StandardError, e.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def close_scanner(scanner)
|
77
|
+
begin
|
78
|
+
request = Request::ScannerRequest.new(scanner.table_name)
|
79
|
+
Response::ScannerResponse.new(delete_response(request.close(scanner)), :close_scanner).parse
|
80
|
+
rescue StandardError => e
|
81
|
+
if e.to_s.include?("TableNotFoundException")
|
82
|
+
raise TableNotFoundError, "Table #{table_name} Not Found!"
|
83
|
+
else
|
84
|
+
raise StandardError, e.to_s
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Operation
|
3
|
+
module TableOperation
|
4
|
+
def show_table(name)
|
5
|
+
begin
|
6
|
+
request = Request::TableRequest.new(name)
|
7
|
+
Response::TableResponse.new(get(request.show)).parse
|
8
|
+
rescue Net::ProtocolError
|
9
|
+
raise TableNotFoundError, "Table '#{name}' Not found"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_table(name, *args)
|
14
|
+
request = Request::TableRequest.new(name)
|
15
|
+
|
16
|
+
raise StandardError, "Table name must be of type String" unless name.instance_of? String
|
17
|
+
|
18
|
+
begin
|
19
|
+
xml_data = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><TableSchema name='#{name}' IS_META='false' IS_ROOT='false'>"
|
20
|
+
for arg in args
|
21
|
+
if arg.instance_of? String
|
22
|
+
xml_data << "<ColumnSchema name='#{arg}' />"
|
23
|
+
elsif arg.instance_of? Hash
|
24
|
+
xml_data << "<ColumnSchema "
|
25
|
+
|
26
|
+
arg.each do |k,v|
|
27
|
+
if Model::ColumnDescriptor::AVAILABLE_OPTS.include? k
|
28
|
+
xml_data << "#{Model::ColumnDescriptor::AVAILABLE_OPTS[k]}='#{v}' "
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
xml_data << "/>"
|
33
|
+
else
|
34
|
+
raise StandardError, "#{arg.class.to_s} of #{arg.to_s} is not of Hash Type"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
xml_data << "</TableSchema>"
|
38
|
+
Response::TableResponse.new(post(request.create, xml_data))
|
39
|
+
rescue Net::ProtocolError => e
|
40
|
+
if e.to_s.include?("TableExistsException")
|
41
|
+
raise TableExistsError, "Table '#{name}' already exists"
|
42
|
+
else
|
43
|
+
raise TableFailCreateError, e.message
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def alter_table(name, *args)
|
49
|
+
raise StandardError, "Table name must be of type String" unless name.instance_of? String
|
50
|
+
|
51
|
+
request = Request::TableRequest.new(name)
|
52
|
+
|
53
|
+
begin
|
54
|
+
xml_data = construct_xml_stream(name, *args)
|
55
|
+
Response::TableResponse.new(put(request.update, xml_data))
|
56
|
+
rescue Net::ProtocolError => e
|
57
|
+
if e.to_s.include?("TableNotFoundException")
|
58
|
+
raise TableNotFoundError, "Table '#{name}' not exists"
|
59
|
+
else
|
60
|
+
raise TableFailCreateError, e.message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def delete_table(name, columns = nil)
|
66
|
+
begin
|
67
|
+
request = Request::TableRequest.new(name)
|
68
|
+
Response::TableResponse.new(delete(request.delete(columns)))
|
69
|
+
rescue Net::ProtocolError => e
|
70
|
+
if e.to_s.include?("TableNotFoundException")
|
71
|
+
raise TableNotFoundError, "Table '#{name}' not exists"
|
72
|
+
elsif e.to_s.include?("TableNotDisabledException")
|
73
|
+
raise TableNotDisabledError, "Table '#{name}' not disabled"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def destroy_table(name, columns = nil)
|
79
|
+
delete_table(name, columns)
|
80
|
+
end
|
81
|
+
|
82
|
+
def enable_table(name)
|
83
|
+
warn "[DEPRECATION] Explicitly enabling tables isn't required anymore. HBase Stargate will enable/disable as needed."
|
84
|
+
end
|
85
|
+
|
86
|
+
def disable_table(name)
|
87
|
+
warn "[DEPRECATION] Explicitly disabling tables isn't required anymore. HBase Stargate will enable/disable as needed."
|
88
|
+
end
|
89
|
+
|
90
|
+
def table_regions(name, start_row = nil, end_row = nil)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Stargate module Request; end; end
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/request/basic_request'
|
4
|
+
require File.dirname(__FILE__) + '/request/meta_request'
|
5
|
+
require File.dirname(__FILE__) + '/request/table_request'
|
6
|
+
require File.dirname(__FILE__) + '/request/row_request'
|
7
|
+
require File.dirname(__FILE__) + '/request/scanner_request'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Stargate
|
4
|
+
module Request
|
5
|
+
class BasicRequest
|
6
|
+
attr_reader :path
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
@path = path
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def pack_params columns
|
16
|
+
if columns.is_a? String
|
17
|
+
columns = [columns]
|
18
|
+
elsif columns.is_a? Array
|
19
|
+
else
|
20
|
+
raise StandardError, "Only String or Array type allows for columns"
|
21
|
+
end
|
22
|
+
|
23
|
+
columns.join(',')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Request
|
3
|
+
class MetaRequest < BasicRequest
|
4
|
+
def initialize
|
5
|
+
super("")
|
6
|
+
end
|
7
|
+
|
8
|
+
def list_tables
|
9
|
+
@path << "/"
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_table
|
13
|
+
@path << "/tables"
|
14
|
+
end
|
15
|
+
|
16
|
+
def version
|
17
|
+
@path << "/version"
|
18
|
+
end
|
19
|
+
|
20
|
+
def cluster_version
|
21
|
+
@path << "/version/cluster"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Request
|
3
|
+
class RowRequest < BasicRequest
|
4
|
+
attr_reader :table_name
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :timestamp
|
7
|
+
|
8
|
+
def initialize(table_name, name, timestamp=nil)
|
9
|
+
@table_name, @name, @timestamp = CGI.escape(table_name), CGI.escape(name), timestamp
|
10
|
+
path = "/#{@table_name}/#{@name}"
|
11
|
+
super(path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def show(columns = nil, options = { })
|
15
|
+
@path << (columns ? "/#{pack_params(columns)}" : "/")
|
16
|
+
@path << "/#{@timestamp}" if @timestamp
|
17
|
+
@path << "?v=#{options[:version]}" if options[:version]
|
18
|
+
@path
|
19
|
+
end
|
20
|
+
|
21
|
+
def create(columns = nil)
|
22
|
+
@path << (columns ? "/#{pack_params(columns)}" : "/")
|
23
|
+
@path << "/#{@timestamp}" if @timestamp
|
24
|
+
@path
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete(columns = nil)
|
28
|
+
@path << (columns ? "/#{pack_params(columns)}" : "/")
|
29
|
+
@path << "/#{@timestamp}" if @timestamp
|
30
|
+
@path
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Request
|
3
|
+
class ScannerRequest < BasicRequest
|
4
|
+
attr_reader :table_name
|
5
|
+
|
6
|
+
def initialize(table_name)
|
7
|
+
@table_name = CGI.escape(table_name)
|
8
|
+
path = "/#{@table_name}/scanner"
|
9
|
+
super(path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def open
|
13
|
+
@path
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_rows(scanner)
|
17
|
+
@path = URI.parse(scanner.scanner_url).path
|
18
|
+
end
|
19
|
+
|
20
|
+
def close(scanner)
|
21
|
+
@path = URI.parse(scanner.scanner_url).path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Request
|
3
|
+
class TableRequest < BasicRequest
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :body
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
super("")
|
9
|
+
@name = CGI.escape(name) if name
|
10
|
+
end
|
11
|
+
|
12
|
+
def show
|
13
|
+
@path << "/#{name}/schema"
|
14
|
+
end
|
15
|
+
|
16
|
+
def regions(start_row = nil, end_row = nil)
|
17
|
+
#TODO no handle the args!
|
18
|
+
@path << "/#{name}/regions"
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
@path << "/#{name}/schema"
|
23
|
+
end
|
24
|
+
|
25
|
+
def update
|
26
|
+
@path << "/#{name}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def enable
|
30
|
+
@path << "/#{name}/enable"
|
31
|
+
end
|
32
|
+
|
33
|
+
def disable
|
34
|
+
@path << "/#{name}/disable"
|
35
|
+
end
|
36
|
+
|
37
|
+
def delete(columns = nil)
|
38
|
+
warn "[DEPRECATION] the use of the 'columns' argument is deprecated. Please use the delete method without any arguments." if columns
|
39
|
+
@path << "/#{name}/schema"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Stargate module Response; end; end
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/response/basic_response'
|
4
|
+
require File.dirname(__FILE__) + '/response/meta_response'
|
5
|
+
require File.dirname(__FILE__) + '/response/table_response'
|
6
|
+
require File.dirname(__FILE__) + '/response/row_response'
|
7
|
+
require File.dirname(__FILE__) + '/response/scanner_response'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
begin
|
2
|
+
require 'json'
|
3
|
+
rescue LoadError => e
|
4
|
+
puts "[hbase-stargate] json is required. Install it with 'gem install json' (or json-jruby for JRuby)"
|
5
|
+
raise e
|
6
|
+
end
|
7
|
+
|
8
|
+
module Stargate
|
9
|
+
module Response
|
10
|
+
class BasicResponse
|
11
|
+
|
12
|
+
def initialize(raw_data)
|
13
|
+
@raw_data = raw_data
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse
|
17
|
+
parse_content @raw_data
|
18
|
+
end
|
19
|
+
|
20
|
+
def verify_success(response)
|
21
|
+
case response
|
22
|
+
when Net::HTTPSuccess
|
23
|
+
true
|
24
|
+
else
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Response
|
3
|
+
class MetaResponse < BasicResponse
|
4
|
+
attr_reader :method
|
5
|
+
|
6
|
+
def initialize(raw_data, method)
|
7
|
+
@method = method
|
8
|
+
super(raw_data)
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_content(raw_data)
|
12
|
+
case @method
|
13
|
+
when :list_tables
|
14
|
+
if raw_data.to_s.empty? || raw_data == "null" # "null" from json
|
15
|
+
puts "There are no available tables in the HBase"
|
16
|
+
return []
|
17
|
+
end
|
18
|
+
|
19
|
+
tables = []
|
20
|
+
doc = JSON.parse(raw_data)
|
21
|
+
|
22
|
+
doc["table"].each do |table|
|
23
|
+
name = table["name"].strip rescue nil
|
24
|
+
t = Model::TableDescriptor.new(:name => name)
|
25
|
+
tables << t
|
26
|
+
end
|
27
|
+
|
28
|
+
tables
|
29
|
+
else
|
30
|
+
puts "method '#{@method}' not supported yet"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Response
|
3
|
+
class RowResponse < BasicResponse
|
4
|
+
attr_reader :method
|
5
|
+
|
6
|
+
def initialize(raw_data, method)
|
7
|
+
@method = method
|
8
|
+
super(raw_data)
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_content(raw_data)
|
12
|
+
case @method
|
13
|
+
when :show_row
|
14
|
+
doc = JSON.parse(raw_data)
|
15
|
+
rows = doc["Row"]
|
16
|
+
|
17
|
+
model_rows = []
|
18
|
+
rows.each do |row|
|
19
|
+
rname = row["key"].strip.unpack("m").first
|
20
|
+
count = row["Cell"].size
|
21
|
+
columns = []
|
22
|
+
|
23
|
+
row["Cell"].each do |col|
|
24
|
+
name = col["column"].strip.unpack('m').first
|
25
|
+
value = col["$"].strip.unpack('m').first rescue nil
|
26
|
+
timestamp = col["timestamp"].to_i
|
27
|
+
|
28
|
+
columns << Stargate::Model::Column.new( :name => name,
|
29
|
+
:value => value,
|
30
|
+
:timestamp => timestamp)
|
31
|
+
end
|
32
|
+
|
33
|
+
model_rows << Stargate::Model::Row.new(:name => rname, :total_count => count, :columns => columns)
|
34
|
+
end
|
35
|
+
|
36
|
+
model_rows
|
37
|
+
when :create_row
|
38
|
+
verify_success(raw_data)
|
39
|
+
when :delete_row
|
40
|
+
verify_success(raw_data)
|
41
|
+
else
|
42
|
+
puts "method '#{@method}' not supported yet"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Response
|
3
|
+
class ScannerResponse < BasicResponse
|
4
|
+
attr_reader :method
|
5
|
+
|
6
|
+
def initialize(raw_data, method)
|
7
|
+
@method = method
|
8
|
+
super(raw_data)
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_content(raw_data)
|
12
|
+
case @method
|
13
|
+
when :open_scanner
|
14
|
+
case raw_data
|
15
|
+
when Net::HTTPCreated
|
16
|
+
Stargate::Model::Scanner.new(:scanner_url => raw_data["Location"])
|
17
|
+
else
|
18
|
+
if raw_data.message.include?("TableNotFoundException")
|
19
|
+
raise TableNotFoundError, "Table #{table_name} Not Found!"
|
20
|
+
else
|
21
|
+
raise StandardError, "Unable to open scanner. Received the following message: #{raw_data.message}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
when :get_rows
|
25
|
+
# Dispatch it to RowResponse, since that method is made
|
26
|
+
# to deal with rows already.
|
27
|
+
RowResponse.new(raw_data, :show_row).parse
|
28
|
+
when :close_scanner
|
29
|
+
case raw_data
|
30
|
+
when Net::HTTPOK
|
31
|
+
return true
|
32
|
+
else
|
33
|
+
raise StandardError, "Unable to close scanner. Received the following message: #{raw_data.message}"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
puts "method '#{@method}' not supported yet"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Stargate
|
2
|
+
module Response
|
3
|
+
class TableResponse < BasicResponse
|
4
|
+
def parse_content(raw_data)
|
5
|
+
table = JSON.parse(raw_data)
|
6
|
+
name = table["name"].strip
|
7
|
+
|
8
|
+
column_families = []
|
9
|
+
table["ColumnSchema"].each do |columnfamily|
|
10
|
+
colname = columnfamily["name"].strip
|
11
|
+
compression = columnfamily["COMPRESSION"].strip
|
12
|
+
bloomfilter = (columnfamily["BLOOMFILTER"].strip =~ /^true$/i ? true : false)
|
13
|
+
max_versions = columnfamily["VERSIONS"].strip.to_i
|
14
|
+
|
15
|
+
column_descriptor = Model::ColumnDescriptor.new(:name => colname,
|
16
|
+
:compression => Model::CompressionType.to_compression_type(compression),
|
17
|
+
:bloomfilter => bloomfilter,
|
18
|
+
:max_versions => max_versions)
|
19
|
+
column_families << column_descriptor
|
20
|
+
end
|
21
|
+
|
22
|
+
Model::TableDescriptor.new(:name => name, :column_families => column_families)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Ruby driver for HBase
|
2
|
+
|
3
|
+
Small and handy Ruby driver for HBase (via Stargate RESTfull interface).
|
4
|
+
|
5
|
+
# Usage
|
6
|
+
|
7
|
+
**Warning:** HBase and Stargate should be installed and running.
|
8
|
+
|
9
|
+
require 'hbase'
|
10
|
+
|
11
|
+
hbase = HBase.new('http://localhost:8080')
|
12
|
+
|
13
|
+
# creating table
|
14
|
+
hbase.create 'users'
|
15
|
+
|
16
|
+
# listing all tables
|
17
|
+
p hbase.all # => ['users']
|
18
|
+
|
19
|
+
# create record
|
20
|
+
users.update 'john', 'attr:email' => 'john@mail.com'
|
21
|
+
|
22
|
+
# get record
|
23
|
+
john = users['john']
|
24
|
+
p john['attr:email'] # => "john@mail.com"
|
25
|
+
|
26
|
+
# update record
|
27
|
+
users.update 'john', 'attr:email' => "another@mail.com"
|
28
|
+
p john['attr:email'] # => "another@mail.com"
|
29
|
+
|
30
|
+
# deleting record
|
31
|
+
users.delete 'john'
|
32
|
+
|
33
|
+
# scanning
|
34
|
+
users.update 'john', 'attr:email' => 'john@mail.com'
|
35
|
+
users.update 'mario', 'attr:email' => 'mario@mail.com'
|
36
|
+
users.update 'stanley', 'attr:email' => 'stanley@mail.com'
|
37
|
+
|
38
|
+
list = users.scan :start => 'john', :batch => 5, :columns => ['attr:']
|
39
|
+
p list.collect{|user| user['attr:email']} # => ['john@mail.com', 'mario@mail.com', 'stanley@mail.com']
|
40
|
+
|
41
|
+
# Installation
|
42
|
+
|
43
|
+
$ gem install ruby-driver
|
44
|
+
|
45
|
+
For installation of HBase and Stargate please see HBase docs (google it).
|
46
|
+
|
47
|
+
**Warning:** currently HBase distributed with RESTful interface called 'rest' and it's deprecated and broken. And because it looks very similar to Stargate it's easy to mix it up. So, be aware, you need to install and use the Stargate, not default and broken HBase REST client.
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hbase-driver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Alexey Petrushin
|
14
|
+
- Dmitry Larkin
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-11-10 00:00:00 +03:00
|
20
|
+
default_executable:
|
21
|
+
dependencies: []
|
22
|
+
|
23
|
+
description:
|
24
|
+
email:
|
25
|
+
- Alexey.Petrushin@railsware.com
|
26
|
+
- dmitry.larkin@railsware.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- lib/hbase/cell.rb
|
35
|
+
- lib/hbase/hbase.rb
|
36
|
+
- lib/hbase/record.rb
|
37
|
+
- lib/hbase/support.rb
|
38
|
+
- lib/hbase/table.rb
|
39
|
+
- lib/hbase.rb
|
40
|
+
- lib/stargate/client.rb
|
41
|
+
- lib/stargate/exception.rb
|
42
|
+
- lib/stargate/model/column.rb
|
43
|
+
- lib/stargate/model/column_descriptor.rb
|
44
|
+
- lib/stargate/model/region_descriptor.rb
|
45
|
+
- lib/stargate/model/row.rb
|
46
|
+
- lib/stargate/model/scanner.rb
|
47
|
+
- lib/stargate/model/table_descriptor.rb
|
48
|
+
- lib/stargate/model.rb
|
49
|
+
- lib/stargate/operation/meta_operation.rb
|
50
|
+
- lib/stargate/operation/row_operation.rb
|
51
|
+
- lib/stargate/operation/scanner_operation.rb
|
52
|
+
- lib/stargate/operation/table_operation.rb
|
53
|
+
- lib/stargate/request/basic_request.rb
|
54
|
+
- lib/stargate/request/meta_request.rb
|
55
|
+
- lib/stargate/request/row_request.rb
|
56
|
+
- lib/stargate/request/scanner_request.rb
|
57
|
+
- lib/stargate/request/table_request.rb
|
58
|
+
- lib/stargate/request.rb
|
59
|
+
- lib/stargate/response/basic_response.rb
|
60
|
+
- lib/stargate/response/meta_response.rb
|
61
|
+
- lib/stargate/response/row_response.rb
|
62
|
+
- lib/stargate/response/scanner_response.rb
|
63
|
+
- lib/stargate/response/table_response.rb
|
64
|
+
- lib/stargate/response.rb
|
65
|
+
- lib/stargate.rb
|
66
|
+
- readme.md
|
67
|
+
- Rakefile
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: http://github.com/railsware/hbase-driver
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.3.7
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: HBase Ruby Driver
|
102
|
+
test_files: []
|
103
|
+
|