hbase-jruby 0.1.1-java → 0.1.2-java
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +17 -0
- data/README.md +126 -33
- data/hbase-jruby.gemspec +1 -0
- data/lib/hbase-jruby/admin.rb +1 -0
- data/lib/hbase-jruby/cell.rb +3 -11
- data/lib/hbase-jruby/result.rb +27 -51
- data/lib/hbase-jruby/scoped/aggregation.rb +47 -0
- data/lib/hbase-jruby/scoped.rb +51 -23
- data/lib/hbase-jruby/table.rb +72 -66
- data/lib/hbase-jruby/util.rb +12 -5
- data/lib/hbase-jruby/version.rb +1 -1
- data/lib/hbase-jruby.rb +1 -0
- data/test/helper.rb +1 -3
- data/test/test_aggregation.rb +40 -0
- data/test/test_cell.rb +0 -1
- data/test/test_hbase.rb +1 -1
- data/test/test_scoped.rb +45 -1
- data/test/test_table.rb +46 -11
- data/test/test_table_admin.rb +22 -0
- data/test/test_util.rb +2 -3
- metadata +37 -27
data/lib/hbase-jruby/scoped.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
class HBase
|
2
|
-
# Scope of
|
2
|
+
# Scope of data access
|
3
3
|
# @author Junegunn Choi <junegunn.c@gmail.com>
|
4
|
+
# @!attribute [r] table
|
5
|
+
# @return [HBase::Table] HBase::Table instance for this scope
|
4
6
|
class Scoped
|
5
7
|
include Enumerable
|
8
|
+
include Scoped::Aggregation
|
9
|
+
|
10
|
+
attr_reader :table
|
6
11
|
|
7
12
|
# A clean HBase::Scoped object for the same table
|
8
13
|
# @return [HBase::Scope] A clean HBase::Scoped object for the same table
|
@@ -14,8 +19,14 @@ class Scoped
|
|
14
19
|
# @return [Fixnum, Bignum] The number of rows in the scope
|
15
20
|
def count
|
16
21
|
cnt = 0
|
17
|
-
|
18
|
-
|
22
|
+
if block_given?
|
23
|
+
htable.getScanner(filtered_scan).each do |result|
|
24
|
+
cnt += 1 if yield(Result.send(:new, result))
|
25
|
+
end
|
26
|
+
else
|
27
|
+
htable.getScanner(filtered_scan_minimum).each do
|
28
|
+
cnt += 1
|
29
|
+
end
|
19
30
|
end
|
20
31
|
cnt
|
21
32
|
end
|
@@ -124,26 +135,14 @@ class Scoped
|
|
124
135
|
# @param [Array<Hash, FilterBase, FilterList>] filters
|
125
136
|
# @return [HBase::Scoped] HBase::Scoped object also with the specified filters
|
126
137
|
def filter *filters
|
127
|
-
spawn :@filters, @filters + filters
|
128
|
-
|
129
|
-
when Hash
|
130
|
-
f.map { |col, val|
|
131
|
-
cf, cq = Util.parse_column_name col
|
138
|
+
spawn :@filters, @filters + parse_filter_input(filters)
|
139
|
+
end
|
132
140
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
filter_for cf, cq, val
|
139
|
-
end
|
140
|
-
}.flatten
|
141
|
-
when FilterBase, FilterList
|
142
|
-
f
|
143
|
-
else
|
144
|
-
raise ArgumentError, "Unknown filter type"
|
145
|
-
end
|
146
|
-
}.flatten
|
141
|
+
# Returns an HBase::Scoped object with the additional filters which will cause early termination of scan
|
142
|
+
# @param [Array<Hash, FilterBase, FilterList>] filters
|
143
|
+
# @return [HBase::Scoped]HBase::Scoped object with the additional filters which will cause early termination of scan
|
144
|
+
def while *filters
|
145
|
+
spawn :@filters, @filters + parse_filter_input(filters).map { |filter| WhileMatchFilter.new(filter) }
|
147
146
|
end
|
148
147
|
|
149
148
|
# Returns an HBase::Scoped object with the specified row number limit
|
@@ -354,7 +353,7 @@ private
|
|
354
353
|
when Hash
|
355
354
|
FilterList.new(FilterList::Operator::MUST_PASS_ALL,
|
356
355
|
val.map { |op, v|
|
357
|
-
operator =
|
356
|
+
operator =
|
358
357
|
case op
|
359
358
|
when :gt, :>
|
360
359
|
CompareFilter::CompareOp::GREATER
|
@@ -392,6 +391,12 @@ private
|
|
392
391
|
end
|
393
392
|
}
|
394
393
|
)
|
394
|
+
when Regexp
|
395
|
+
SingleColumnValueFilter.new(
|
396
|
+
cf, cq,
|
397
|
+
CompareFilter::CompareOp::EQUAL,
|
398
|
+
RegexStringComparator.new(val.to_s)
|
399
|
+
)
|
395
400
|
else
|
396
401
|
SingleColumnValueFilter.new(
|
397
402
|
cf, cq,
|
@@ -484,6 +489,29 @@ private
|
|
484
489
|
|
485
490
|
[start.java, stop.stopkey_bytes_for_prefix]
|
486
491
|
end
|
492
|
+
|
493
|
+
def parse_filter_input filters
|
494
|
+
filters.map { |f|
|
495
|
+
case f
|
496
|
+
when Hash
|
497
|
+
f.map { |col, val|
|
498
|
+
cf, cq = Util.parse_column_name col
|
499
|
+
|
500
|
+
case val
|
501
|
+
when Array
|
502
|
+
FilterList.new(FilterList::Operator::MUST_PASS_ONE,
|
503
|
+
val.map { |v| filter_for cf, cq, v })
|
504
|
+
else
|
505
|
+
filter_for cf, cq, val
|
506
|
+
end
|
507
|
+
}.flatten
|
508
|
+
when FilterBase, FilterList
|
509
|
+
f
|
510
|
+
else
|
511
|
+
raise ArgumentError, "Unknown filter type"
|
512
|
+
end
|
513
|
+
}.flatten
|
514
|
+
end
|
487
515
|
end#Scoped
|
488
516
|
end#HBase
|
489
517
|
|
data/lib/hbase-jruby/table.rb
CHANGED
@@ -4,11 +4,15 @@ require 'thread'
|
|
4
4
|
class HBase
|
5
5
|
# @!attribute [r] name
|
6
6
|
# @return [String] The name of the table
|
7
|
+
# @!attribute [r] config
|
8
|
+
# @return [org.apache.hadoop.conf.Configuration]
|
7
9
|
class Table
|
8
10
|
attr_reader :name
|
11
|
+
attr_reader :config
|
9
12
|
|
10
13
|
include Enumerable
|
11
14
|
include Admin
|
15
|
+
include Scoped::Aggregation::Admin
|
12
16
|
|
13
17
|
# Returns a read-only org.apache.hadoop.hbase.HTableDescriptor object
|
14
18
|
# @return [org.apache.hadoop.hbase.client.UnmodifyableHTableDescriptor]
|
@@ -160,11 +164,59 @@ class Table
|
|
160
164
|
end
|
161
165
|
end
|
162
166
|
|
167
|
+
# Adds the table coprocessor to the table
|
168
|
+
# @param [String] class_name Full class name of the coprocessor
|
169
|
+
# @param [Hash] props Coprocessor properties
|
170
|
+
# @option props [String] path The path of the JAR file
|
171
|
+
# @option props [Fixnum] priority Coprocessor priority
|
172
|
+
# @option props [Hash<#to_s, #to_s>] params Arbitrary key-value parameter pairs passed into the coprocessor
|
173
|
+
def add_coprocessor! class_name, props = {}
|
174
|
+
with_admin do |admin|
|
175
|
+
while_disabled(admin) do
|
176
|
+
|
177
|
+
htd = admin.get_table_descriptor(@name.to_java_bytes)
|
178
|
+
if props.empty?
|
179
|
+
htd.addCoprocessor class_name
|
180
|
+
else
|
181
|
+
path, priority, params = props.values_at :path, :priority, :params
|
182
|
+
params = Hash[ params.map { |k, v| [k.to_s, v.to_s] } ]
|
183
|
+
htd.addCoprocessor class_name, path, priority || Coprocessor::PRIORITY_USER, params
|
184
|
+
end
|
185
|
+
admin.modifyTable @name.to_java_bytes, htd
|
186
|
+
wait_async_admin(admin)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Removes the coprocessor from the table.
|
192
|
+
# @param [String] class_name Full class name of the coprocessor
|
193
|
+
# @return [nil]
|
194
|
+
def remove_coprocessor! name
|
195
|
+
unless org.apache.hadoop.hbase.HTableDescriptor.respond_to?(:removeCoprocessor)
|
196
|
+
raise NotImplementedError, "org.apache.hadoop.hbase.HTableDescriptor.removeCoprocessor not implemented"
|
197
|
+
end
|
198
|
+
with_admin do |admin|
|
199
|
+
while_disabled(admin) do
|
200
|
+
htd = admin.get_table_descriptor(@name.to_java_bytes)
|
201
|
+
htd.removeCoprocessor name
|
202
|
+
admin.modifyTable @name.to_java_bytes, htd
|
203
|
+
wait_async_admin(admin)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Return if the table has the coprocessor of the given class name
|
209
|
+
# @param [String] class_name Full class name of the coprocessor
|
210
|
+
# @return [true, false]
|
211
|
+
def has_coprocessor? class_name
|
212
|
+
descriptor.hasCoprocessor(class_name)
|
213
|
+
end
|
214
|
+
|
163
215
|
# Enables the table
|
164
216
|
# @return [nil]
|
165
217
|
def enable!
|
166
218
|
with_admin do |admin|
|
167
|
-
admin.enableTable @name unless admin.isTableEnabled(@name)
|
219
|
+
admin.enableTable @name unless admin.isTableEnabled(@name)
|
168
220
|
end
|
169
221
|
end
|
170
222
|
|
@@ -172,7 +224,7 @@ class Table
|
|
172
224
|
# @return [nil]
|
173
225
|
def disable!
|
174
226
|
with_admin do |admin|
|
175
|
-
admin.disableTable @name if admin.isTableEnabled(@name)
|
227
|
+
admin.disableTable @name if admin.isTableEnabled(@name)
|
176
228
|
end
|
177
229
|
end
|
178
230
|
|
@@ -190,24 +242,19 @@ class Table
|
|
190
242
|
with_admin do |admin|
|
191
243
|
raise RuntimeError, 'Table does not exist' unless admin.tableExists @name
|
192
244
|
|
193
|
-
admin.disableTable @name if admin.isTableEnabled(@name)
|
245
|
+
admin.disableTable @name if admin.isTableEnabled(@name)
|
194
246
|
admin.deleteTable @name
|
195
247
|
close
|
196
248
|
end
|
197
249
|
end
|
198
250
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
# Nonexistent records will be returned as nils.
|
207
|
-
# @param [Array<Object>] rowkeys Rowkeys
|
208
|
-
# @return [Array<HBase::Result>]
|
209
|
-
def get rowkeys
|
210
|
-
each.get rowkeys
|
251
|
+
[:get, :count, :aggregate,
|
252
|
+
:range, :project, :filter, :while,
|
253
|
+
:limit, :versions, :caching, :batch
|
254
|
+
].each do |method|
|
255
|
+
define_method(method) do |*args|
|
256
|
+
self.each.send(method, *args)
|
257
|
+
end
|
211
258
|
end
|
212
259
|
|
213
260
|
# @overload put(rowkey, data)
|
@@ -272,7 +319,7 @@ class Table
|
|
272
319
|
rowkey, cfcq, *ts = spec
|
273
320
|
cf, cq = Util.parse_column_name(cfcq) if cfcq
|
274
321
|
|
275
|
-
Delete.new(Util.to_bytes rowkey).tap { |del|
|
322
|
+
Delete.new(Util.to_bytes rowkey).tap { |del|
|
276
323
|
if !ts.empty?
|
277
324
|
ts.each do |t|
|
278
325
|
del.deleteColumn cf, cq, t
|
@@ -317,12 +364,6 @@ class Table
|
|
317
364
|
end
|
318
365
|
end
|
319
366
|
|
320
|
-
# Returns the count of the rows in the table
|
321
|
-
# @return [Fixnum]
|
322
|
-
def count
|
323
|
-
each.count
|
324
|
-
end
|
325
|
-
|
326
367
|
# Scan through the table
|
327
368
|
# @yield [HBase::Result] Yields each row in the scope
|
328
369
|
# @return [HBase::Scoped]
|
@@ -334,48 +375,6 @@ class Table
|
|
334
375
|
end
|
335
376
|
end
|
336
377
|
|
337
|
-
# @see HBase::Scoped#range
|
338
|
-
# @return [HBase::Scoped]
|
339
|
-
def range *key_range
|
340
|
-
each.range(*key_range)
|
341
|
-
end
|
342
|
-
|
343
|
-
# @see HBase::Scoped#project
|
344
|
-
# @return [HBase::Scoped]
|
345
|
-
def project *columns
|
346
|
-
each.project(*columns)
|
347
|
-
end
|
348
|
-
|
349
|
-
# @see HBase::Scoped#filter
|
350
|
-
# @return [HBase::Scoped]
|
351
|
-
def filter *filters
|
352
|
-
each.filter(*filters)
|
353
|
-
end
|
354
|
-
|
355
|
-
# @see HBase::Scoped#limit
|
356
|
-
# @return [HBase::Scoped]
|
357
|
-
def limit rows
|
358
|
-
each.limit rows
|
359
|
-
end
|
360
|
-
|
361
|
-
# @see HBase::Scoped#versions
|
362
|
-
# @return [HBase::Scoped]
|
363
|
-
def versions vs
|
364
|
-
each.versions vs
|
365
|
-
end
|
366
|
-
|
367
|
-
# @see HBase::Scoped#caching
|
368
|
-
# @return [HBase::Scoped]
|
369
|
-
def caching rows
|
370
|
-
each.caching rows
|
371
|
-
end
|
372
|
-
|
373
|
-
# @see HBase::Scoped#batch
|
374
|
-
# @return [HBase::Scoped]
|
375
|
-
def batch b
|
376
|
-
each.batch b
|
377
|
-
end
|
378
|
-
|
379
378
|
# Returns the underlying org.apache.hadoop.hbase.client.HTable object (local to current thread)
|
380
379
|
# @return [org.apache.hadoop.hbase.client.HTable]
|
381
380
|
def htable
|
@@ -405,7 +404,7 @@ private
|
|
405
404
|
|
406
405
|
def while_disabled admin
|
407
406
|
begin
|
408
|
-
admin.disableTable @name if admin.isTableEnabled(@name)
|
407
|
+
admin.disableTable @name if admin.isTableEnabled(@name)
|
409
408
|
yield
|
410
409
|
ensure
|
411
410
|
admin.enableTable @name
|
@@ -416,7 +415,14 @@ private
|
|
416
415
|
Put.new(Util.to_bytes rowkey).tap { |put|
|
417
416
|
props.each do |col, val|
|
418
417
|
cf, cq = Util.parse_column_name(col)
|
419
|
-
|
418
|
+
case val
|
419
|
+
when Hash
|
420
|
+
val.each do |ts, v|
|
421
|
+
put.add cf, cq, ts, Util.to_bytes(v)
|
422
|
+
end
|
423
|
+
else
|
424
|
+
put.add cf, cq, Util.to_bytes(val)
|
425
|
+
end
|
420
426
|
end
|
421
427
|
}
|
422
428
|
end
|
data/lib/hbase-jruby/util.rb
CHANGED
@@ -2,7 +2,7 @@ require 'bigdecimal'
|
|
2
2
|
|
3
3
|
class HBase
|
4
4
|
module Util
|
5
|
-
JAVA_BYTE_ARRAY_EMPTY = [].to_java(Java::byte)
|
5
|
+
JAVA_BYTE_ARRAY_EMPTY = [].to_java(Java::byte)
|
6
6
|
JAVA_BYTE_ARRAY_CLASS = JAVA_BYTE_ARRAY_EMPTY.java_class
|
7
7
|
|
8
8
|
class << self
|
@@ -24,7 +24,7 @@ module Util
|
|
24
24
|
when nil
|
25
25
|
''.to_java_bytes
|
26
26
|
when Bignum
|
27
|
-
|
27
|
+
raise ArgumentError, "Integer too large. Consider storing it as a BigDecimal."
|
28
28
|
when BigDecimal
|
29
29
|
Bytes.java_send :toBytes, [java.math.BigDecimal], v.to_java
|
30
30
|
when java.math.BigDecimal
|
@@ -52,8 +52,6 @@ module Util
|
|
52
52
|
Bytes.to_long val
|
53
53
|
when :symbol, :sym
|
54
54
|
Bytes.to_string(val).to_sym
|
55
|
-
when :bignum, :bigint, :biginteger
|
56
|
-
BigDecimal.new(Bytes.to_big_decimal(val).to_s).to_i
|
57
55
|
when :bigdecimal
|
58
56
|
BigDecimal.new(Bytes.to_big_decimal(val).to_s)
|
59
57
|
when :float, :double
|
@@ -133,6 +131,10 @@ module Util
|
|
133
131
|
org.apache.hadoop.hbase.KeyValue
|
134
132
|
]
|
135
133
|
|
134
|
+
imp.call HBase::Result, %w[
|
135
|
+
org.apache.hadoop.hbase.util.Bytes
|
136
|
+
]
|
137
|
+
|
136
138
|
imp.call HBase::ColumnKey, %w[
|
137
139
|
java.util.Arrays
|
138
140
|
org.apache.hadoop.hbase.util.Bytes
|
@@ -146,6 +148,7 @@ module Util
|
|
146
148
|
org.apache.hadoop.hbase.client.Put
|
147
149
|
org.apache.hadoop.hbase.io.hfile.Compression
|
148
150
|
org.apache.hadoop.hbase.regionserver.StoreFile
|
151
|
+
org.apache.hadoop.hbase.Coprocessor
|
149
152
|
]
|
150
153
|
|
151
154
|
imp.call HBase::Scoped, %w[
|
@@ -153,15 +156,19 @@ module Util
|
|
153
156
|
org.apache.hadoop.hbase.client.Scan
|
154
157
|
org.apache.hadoop.hbase.filter.BinaryComparator
|
155
158
|
org.apache.hadoop.hbase.filter.ColumnPaginationFilter
|
156
|
-
org.apache.hadoop.hbase.filter.MultipleColumnPrefixFilter
|
157
159
|
org.apache.hadoop.hbase.filter.ColumnRangeFilter
|
158
160
|
org.apache.hadoop.hbase.filter.CompareFilter
|
159
161
|
org.apache.hadoop.hbase.filter.FilterBase
|
160
162
|
org.apache.hadoop.hbase.filter.FilterList
|
161
163
|
org.apache.hadoop.hbase.filter.KeyOnlyFilter
|
164
|
+
org.apache.hadoop.hbase.filter.MultipleColumnPrefixFilter
|
162
165
|
org.apache.hadoop.hbase.filter.PrefixFilter
|
166
|
+
org.apache.hadoop.hbase.filter.RegexStringComparator
|
163
167
|
org.apache.hadoop.hbase.filter.RowFilter
|
164
168
|
org.apache.hadoop.hbase.filter.SingleColumnValueFilter
|
169
|
+
org.apache.hadoop.hbase.filter.WhileMatchFilter
|
170
|
+
org.apache.hadoop.hbase.client.coprocessor.AggregationClient
|
171
|
+
org.apache.hadoop.hbase.client.coprocessor.LongColumnInterpreter
|
165
172
|
]
|
166
173
|
end
|
167
174
|
end
|
data/lib/hbase-jruby/version.rb
CHANGED
data/lib/hbase-jruby.rb
CHANGED
@@ -9,6 +9,7 @@ require "hbase-jruby/byte_array"
|
|
9
9
|
require "hbase-jruby/column_key"
|
10
10
|
require "hbase-jruby/cell"
|
11
11
|
require "hbase-jruby/admin"
|
12
|
+
require "hbase-jruby/scoped/aggregation"
|
12
13
|
require "hbase-jruby/scoped"
|
13
14
|
require "hbase-jruby/table"
|
14
15
|
require "hbase-jruby/result"
|
data/test/helper.rb
CHANGED
@@ -38,9 +38,7 @@ class TestHBaseJRubyBase < Test::Unit::TestCase
|
|
38
38
|
@table.enable! if @table.disabled?
|
39
39
|
|
40
40
|
unless RECREATE
|
41
|
-
@table.
|
42
|
-
@table.delete row.rowkey :raw
|
43
|
-
end
|
41
|
+
@table.delete(*@table.map { |row| [row.rowkey(:raw)] })
|
44
42
|
assert_equal 0, @table.count
|
45
43
|
end
|
46
44
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path('..', __FILE__)
|
4
|
+
require 'helper'
|
5
|
+
|
6
|
+
class TestAggregation < TestHBaseJRubyBase
|
7
|
+
def test_aggregation
|
8
|
+
(1..100).each do |idx|
|
9
|
+
@table.put idx, 'cf1:a' => idx, 'cf1:b' => idx * 2
|
10
|
+
end
|
11
|
+
|
12
|
+
@table.enable_aggregation!
|
13
|
+
|
14
|
+
lci = org.apache.hadoop.hbase.client.coprocessor.LongColumnInterpreter.new
|
15
|
+
[nil, :fixnum, :int, :integer, lci].each do |ci|
|
16
|
+
assert_equal 100, @table.project('cf1:a').aggregate(:row_count, *[*ci])
|
17
|
+
assert_equal 5050, @table.project('cf1:a').aggregate(:sum, *[*ci])
|
18
|
+
assert_equal 1, @table.project('cf1:a').aggregate(:min, *[*ci])
|
19
|
+
assert_equal 100, @table.project('cf1:a').aggregate(:max, *[*ci])
|
20
|
+
assert_equal 50.5, @table.project('cf1:a').aggregate(:avg, *[*ci])
|
21
|
+
assert_equal 28, @table.project('cf1:a').aggregate(:std, *[*ci]).to_i # FIXME: 28 or 29?
|
22
|
+
end
|
23
|
+
|
24
|
+
[%w[cf1:a cf1:b], %w[cf1]].each do |prj|
|
25
|
+
assert_equal 5050 * 3, @table.project(*prj).aggregate(:sum)
|
26
|
+
assert_equal 1, @table.project(*prj).aggregate(:min)
|
27
|
+
assert_equal 200, @table.project(*prj).aggregate(:max)
|
28
|
+
end
|
29
|
+
|
30
|
+
# No projection
|
31
|
+
assert_raise(ArgumentError) { @table.aggregate(:sum) }
|
32
|
+
assert_raise(ArgumentError) { @table.each.aggregate(:sum) }
|
33
|
+
|
34
|
+
# Invalid type
|
35
|
+
assert_raise(ArgumentError) { @table.project('cf1:a').aggregate(:sum, :float) }
|
36
|
+
|
37
|
+
@table.drop!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
data/test/test_cell.rb
CHANGED
data/test/test_hbase.rb
CHANGED
data/test/test_scoped.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path('..', __FILE__)
|
4
4
|
require 'helper'
|
5
5
|
|
6
|
-
class TestScoped < TestHBaseJRubyBase
|
6
|
+
class TestScoped < TestHBaseJRubyBase
|
7
7
|
def test_invalid_limit
|
8
8
|
assert_raise(ArgumentError) { @table.limit }
|
9
9
|
assert_raise(ArgumentError) { @table.limit(-1) }
|
@@ -88,9 +88,14 @@ class TestScoped < TestHBaseJRubyBase
|
|
88
88
|
assert_equal 9, @table.range(111..150).filter('cf1:a' => 131...140).count
|
89
89
|
assert_equal 2, @table.range(111..150).filter('cf1:a' => 131...140, 'cf2:b' => 132..133).count
|
90
90
|
|
91
|
+
# Count with block
|
92
|
+
assert_equal 5, @table.range(111..150).filter('cf1:a' => 131..140).
|
93
|
+
count { |result| result.fixnum('cf1:a') % 2 == 0 }
|
94
|
+
|
91
95
|
# Unscope
|
92
96
|
assert_equal 50, @table.range(111..150).filter('cf1:a' => 131...140, 'cf2:b' => 132..133).unscope.count
|
93
97
|
end
|
98
|
+
|
94
99
|
def test_scan
|
95
100
|
insert = lambda do
|
96
101
|
(40..70).each do |i|
|
@@ -314,5 +319,44 @@ class TestScoped < TestHBaseJRubyBase
|
|
314
319
|
# batch(10).
|
315
320
|
# map { |row| [row.rowkey(:fixnum), row.count].map(&:to_s).join ': ' }
|
316
321
|
end
|
322
|
+
|
323
|
+
def test_while
|
324
|
+
(0...100).each do |idx|
|
325
|
+
@table.put idx, 'cf1:a' => idx % 10, 'cf2:b' => 'Hello'
|
326
|
+
end
|
327
|
+
|
328
|
+
assert_equal 20, @table.filter('cf1:a' => { lte: 1 }, 'cf2:b' => 'Hello').count
|
329
|
+
assert_equal 2, @table.while( 'cf1:a' => { lte: 1 }, 'cf2:b' => 'Hello').count
|
330
|
+
|
331
|
+
# while == filter for gets
|
332
|
+
assert_equal 20, @table.filter('cf1:a' => { lte: 1 }, 'cf2:b' => 'Hello').get((0..100).to_a).compact.length
|
333
|
+
assert_equal 20, @table.while( 'cf1:a' => { lte: 1 }, 'cf2:b' => 'Hello').get((0..100).to_a).compact.length
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_min_max
|
337
|
+
(0...100).each do |idx|
|
338
|
+
@table.put idx, 'cf1:a' => 1
|
339
|
+
assert_equal 0, @table.to_a.reverse.min.rowkey(:fixnum)
|
340
|
+
assert_equal idx, @table.to_a.reverse.max.rowkey(:fixnum)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_regex
|
345
|
+
('aa'..'zz').each do |rowkey|
|
346
|
+
@table.put rowkey, 'cf1:a' => rowkey
|
347
|
+
end
|
348
|
+
|
349
|
+
assert_equal 1, @table.filter('cf1:a' => /gg/).count
|
350
|
+
assert_equal 1, @table.filter('cf1:a' => /GG/i).count
|
351
|
+
assert_equal 51, @table.filter('cf1:a' => /g/).count
|
352
|
+
assert_equal 0, @table.filter('cf1:a' => /G/).count
|
353
|
+
assert_equal 51, @table.filter('cf1:a' => /G/i).count
|
354
|
+
assert_equal 26, @table.filter('cf1:a' => /g./).count
|
355
|
+
assert_equal 26, @table.filter('cf1:a' => /^g/).count
|
356
|
+
assert_equal 26, @table.filter('cf1:a' => /g$/).count
|
357
|
+
assert_equal 2, @table.filter('cf1:a' => /gg|ff/).count
|
358
|
+
assert_equal 28, @table.filter('cf1:a' => ['aa', 'cc', /^g/]).count
|
359
|
+
assert_equal 54, @table.filter('cf1:a' => ['aa', 'cc', /^g/, { gte: 'xa', lt: 'y'}]).count
|
360
|
+
end
|
317
361
|
end
|
318
362
|
|
data/test/test_table.rb
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
$LOAD_PATH.unshift File.expand_path('..', __FILE__)
|
4
4
|
require 'helper'
|
5
|
+
require 'bigdecimal'
|
5
6
|
|
6
|
-
class TestScoped < TestHBaseJRubyBase
|
7
|
+
class TestScoped < TestHBaseJRubyBase
|
7
8
|
def test_table
|
8
9
|
@hbase.table(TABLE) do |table|
|
9
10
|
assert_equal TABLE, table.name
|
@@ -23,14 +24,12 @@ class TestScoped < TestHBaseJRubyBase
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def test_put_then_get
|
26
|
-
bignum = 123456789123456789123456789
|
27
27
|
# Single record put
|
28
28
|
assert_equal 1, @table.put('row1',
|
29
29
|
'cf1:a' => 2,
|
30
30
|
'cf1:b' => 'b',
|
31
31
|
'cf1:c' => 6.28,
|
32
32
|
'cf1:d' => false,
|
33
|
-
'cf1:e' => bignum + 1,
|
34
33
|
'cf1:f' => :bol,
|
35
34
|
'cf1:g' => BigDecimal.new("456.123"),
|
36
35
|
'cf1:str1' => "Goodbye", 'cf1:str2' => "Cruel world")
|
@@ -39,7 +38,6 @@ class TestScoped < TestHBaseJRubyBase
|
|
39
38
|
'cf1:b' => 'a',
|
40
39
|
'cf1:c' => 3.14,
|
41
40
|
'cf1:d' => true,
|
42
|
-
'cf1:e' => bignum,
|
43
41
|
'cf1:f' => :sym,
|
44
42
|
'cf1:g' => BigDecimal.new("123.456"),
|
45
43
|
'cf1:str1' => "Hello", 'cf1:str2' => "World")
|
@@ -49,13 +47,16 @@ class TestScoped < TestHBaseJRubyBase
|
|
49
47
|
'row3' => { 'cf1:a' => 4, 'cf1:b' => 'c', 'cf1:c' => 6.28 })
|
50
48
|
|
51
49
|
# single-get (latest version)
|
50
|
+
result = @table.get('row1')
|
51
|
+
assert_equal result, result.each
|
52
|
+
|
53
|
+
assert_equal 'row1', @table.get('row1').rowkey
|
52
54
|
assert_equal 'row1', @table.get('row1').rowkey
|
53
55
|
assert_equal 1, @table.get('row1').fixnum('cf1:a')
|
54
56
|
assert_equal 'a', @table.get('row1').string('cf1:b')
|
55
57
|
assert_equal 'a', String.from_java_bytes(@table.get('row1').raw('cf1:b'))
|
56
58
|
assert_equal 3.14, @table.get('row1').float('cf1:c')
|
57
59
|
assert_equal true, @table.get('row1').boolean('cf1:d')
|
58
|
-
assert_equal bignum, @table.get('row1').bignum('cf1:e')
|
59
60
|
assert_equal :sym, @table.get('row1').symbol('cf1:f')
|
60
61
|
assert_equal BigDecimal.new("123.456"), @table.get('row1').bigdecimal('cf1:g')
|
61
62
|
|
@@ -68,7 +69,6 @@ class TestScoped < TestHBaseJRubyBase
|
|
68
69
|
assert_equal %w[a b], @table.get('row1').raws('cf1:b').values.map { |v| String.from_java_bytes v }
|
69
70
|
assert_equal [3.14, 6.28], @table.get('row1').floats('cf1:c').values
|
70
71
|
assert_equal [true, false], @table.get('row1').booleans('cf1:d').values
|
71
|
-
assert_equal [bignum, bignum + 1], @table.get('row1').bignums('cf1:e').values
|
72
72
|
assert_equal [:sym, :bol], @table.get('row1').symbols('cf1:f').values
|
73
73
|
assert_equal [
|
74
74
|
BigDecimal.new("123.456"),
|
@@ -77,9 +77,9 @@ class TestScoped < TestHBaseJRubyBase
|
|
77
77
|
assert @table.get('row1').fixnums('cf1:a').keys.all? { |k| k.instance_of? Fixnum }
|
78
78
|
|
79
79
|
# single-get-multi-col-multi=ver
|
80
|
-
|
81
|
-
assert_equal ['Hello', 'World'],
|
82
|
-
assert_equal ['Goodbye', 'Cruel world'],
|
80
|
+
rets = @table.get('row1').strings(['cf1:str1', 'cf1:str2'])
|
81
|
+
assert_equal ['Hello', 'World'], rets.map(&:values).map(&:first)
|
82
|
+
assert_equal ['Goodbye', 'Cruel world'], rets.map(&:values).map(&:last)
|
83
83
|
|
84
84
|
# multi-get
|
85
85
|
assert_equal %w[row1 row2 row3], @table.get(['row1', 'row2', 'row3']).map { |r| r.rowkey }
|
@@ -91,10 +91,45 @@ class TestScoped < TestHBaseJRubyBase
|
|
91
91
|
assert_equal nil, @table.get('row1').symbol('cf1:xxx')
|
92
92
|
assert_equal nil, @table.get('row1').integer('cf1:xxx')
|
93
93
|
|
94
|
+
# Unavailable columns (plural form)
|
95
|
+
assert_equal({}, @table.get('row1').strings('cf1:xxx'))
|
96
|
+
assert_equal({}, @table.get('row1').strings('cfx:xxx'))
|
97
|
+
|
94
98
|
# Row not found
|
95
99
|
assert_equal nil, @table.get('xxx')
|
96
100
|
end
|
97
101
|
|
102
|
+
# Put added after a delete is overshadowed if its timestamp is older than than that of the tombstone
|
103
|
+
# https://issues.apache.org/jira/browse/HBASE-2847
|
104
|
+
def test_put_delete_put
|
105
|
+
pend("https://issues.apache.org/jira/browse/HBASE-2847") do
|
106
|
+
data = { 'cf1:pdp' => { 1250000000000 => 'A1' } }
|
107
|
+
@table.put :rowkey => data
|
108
|
+
assert_equal 'A1', @table.get(:rowkey).string('cf1:pdp')
|
109
|
+
@table.delete :rowkey
|
110
|
+
assert_nil @table.get(:rowkey)
|
111
|
+
@table.put :rowkey => data
|
112
|
+
assert_equal 'A1', @table.get(:rowkey).string('cf1:pdp')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_put_timestamp
|
117
|
+
rowkey = :test_put_timestamp
|
118
|
+
@table.put rowkey => {
|
119
|
+
'cf1:b' => 'B1',
|
120
|
+
'cf1:a' => {
|
121
|
+
1250000000000 => 'A1',
|
122
|
+
1260000000000 => 'A2',
|
123
|
+
1270000000000 => 'A3',
|
124
|
+
},
|
125
|
+
}
|
126
|
+
|
127
|
+
assert_equal [1270000000000, 'A3'], @table.get(rowkey).strings('cf1:a').first
|
128
|
+
assert_equal 'A2', @table.get(rowkey).strings('cf1:a')[1260000000000]
|
129
|
+
assert_equal [1250000000000, 'A1'], @table.get(rowkey).strings('cf1:a').to_a.last
|
130
|
+
assert_equal ['B1'], @table.get(rowkey).strings('cf1:b').values
|
131
|
+
end
|
132
|
+
|
98
133
|
def test_to_hash
|
99
134
|
data = {
|
100
135
|
'cf1:a' => 'Hello',
|
@@ -102,7 +137,7 @@ class TestScoped < TestHBaseJRubyBase
|
|
102
137
|
'cf1:c' => 3.14,
|
103
138
|
'cf2:d' => :world,
|
104
139
|
'cf2:e' => false,
|
105
|
-
'cf3:f' => 1234567890123456789012345678901234567890,
|
140
|
+
'cf3:f' => BigDecimal.new(1234567890123456789012345678901234567890),
|
106
141
|
'cf3' => true
|
107
142
|
}
|
108
143
|
schema = {
|
@@ -111,7 +146,7 @@ class TestScoped < TestHBaseJRubyBase
|
|
111
146
|
'cf1:c' => :float,
|
112
147
|
HBase::ColumnKey(:cf2, :d) => :symbol,
|
113
148
|
HBase::ColumnKey(:cf2, :e) => :boolean,
|
114
|
-
HBase::ColumnKey(:cf3, :f) => :
|
149
|
+
HBase::ColumnKey(:cf3, :f) => :bigdecimal,
|
115
150
|
'cf3' => :boolean
|
116
151
|
}
|
117
152
|
@table.put('row1', data)
|