hbase-jruby 0.1.2-java → 0.1.3-java

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 0.1.3
5
+ -----
6
+ - Supports Ruby 1.8 compatibility mode
7
+ - Fix: Correct return value from `HBase::resolve_dependency!`
8
+ - Fix: Appropriately close result scanners
9
+
4
10
  0.1.2
5
11
  -----
6
12
 
data/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  *hbase-jruby* is a Ruby-esque interface for accessing HBase from JRuby.
4
4
 
5
- You can of course just use the native Java APIs of HBase,
6
- but doing so requires a lot of keystrokes even for the most basic operations and
7
- can easily lead to overly verbose code that will be frowned upon by Rubyists.
5
+ With JRuby, you can of course just use the native Java APIs of HBase,
6
+ but doing so requires lots of keystrokes even for the most basic operations and
7
+ can lead to having overly verbose code that will be frowned upon by Rubyists.
8
8
  Anyhow, JRuby is Ruby, not Java, right?
9
9
 
10
10
  *hbase-jruby* provides the followings:
@@ -34,9 +34,10 @@ string = row.string('cf1:b')
34
34
  table.range('rowkey1'..'rowkey9').
35
35
  filter('cf1:a' => 100..200, # cf1:a between 100 and 200
36
36
  'cf1:b' => 'Hello', # cf1:b = 'Hello'
37
- 'cf2:c' => /world/i). # cf2:c matches /world/i
38
- 'cf2:d' => ['foo', /^BAR/i], # cf2:d = 'foo' OR matches /^BAR/i
39
- project('cf1:a', 'cf2').each do |row|
37
+ 'cf2:c' => /world/i, # cf2:c matches /world/i
38
+ 'cf2:d' => ['foo', /^BAR/i]). # cf2:d = 'foo' OR matches /^BAR/i
39
+ project('cf1:a', 'cf2').
40
+ each do |row|
40
41
  puts row.fixnum('cf1:a')
41
42
  end
42
43
 
@@ -46,16 +47,6 @@ table.delete(:rowkey9)
46
47
 
47
48
  ## Installation
48
49
 
49
- Add this line to your application's Gemfile:
50
-
51
- gem 'hbase-jruby'
52
-
53
- And then execute:
54
-
55
- $ bundle
56
-
57
- Or install it yourself as:
58
-
59
50
  $ gem install hbase-jruby
60
51
 
61
52
  ## Setting up
@@ -63,13 +54,10 @@ Or install it yourself as:
63
54
  ### Resolving Hadoop/HBase dependency
64
55
 
65
56
  To be able to access HBase from JRuby, Hadoop/HBase dependency must be satisfied.
66
- This can be done by setting up CLASSPATH variable beforehand
67
- or by `require`ing relevant JAR files after launch.
68
- However, downloading all the JAR files and manually putting them in CLASSPATH is a PITA,
69
- especially when HBase is not installed on local system.
70
-
71
- *hbase-jruby* includes `HBase.resolve_dependency!` helper method,
72
- which resolves Hadoop/HBase dependency.
57
+ This can be done by either setting up CLASSPATH variable beforehand
58
+ or by `require`ing relevant JAR files after launching JRuby.
59
+ However, that's a lot of work, so *hbase-jruby* provides `HBase.resolve_dependency!` helper method,
60
+ which automatically resolves Hadoop/HBase dependency.
73
61
 
74
62
  #### Preconfigured dependencies
75
63
 
@@ -88,10 +76,13 @@ require 'hbase-jruby'
88
76
  HBase.resolve_dependency! 'cdh4.1.2'
89
77
  ```
90
78
 
91
- #### Customized dependencies
79
+ (If you're behind an http proxy, set up your ~/.m2/settings.xml file
80
+ as described in [this page](http://maven.apache.org/guides/mini/guide-proxies.html))
81
+
82
+ #### Custom dependency
92
83
 
93
- If you use another version of HBase and Hadoop,
94
- you can use your own Maven pom.xml file with its customized Hadoop/HBase dependency
84
+ If you use other versions of HBase and Hadoop,
85
+ you can use your own Maven pom.xml file with its Hadoop/HBase dependency.
95
86
 
96
87
  ```ruby
97
88
  HBase.resolve_dependency! '/project/my-hbase/pom.xml'
@@ -99,7 +90,7 @@ HBase.resolve_dependency! '/project/my-hbase/pom.xml'
99
90
 
100
91
  #### Using `hbase classpath` command
101
92
 
102
- If you have HBase installed on your system, it's possible to find the JAR files
93
+ If you have HBase installed on your system, it's possible to locate the JAR files
103
94
  for that local installation with `hbase classpath` command.
104
95
  You can tell `resolve_dependency!` method to do so by passing it special `:hbase` parameter.
105
96
 
@@ -569,17 +560,16 @@ scoped.count
569
560
 
570
561
  ## Basic aggregation using coprocessor
571
562
 
572
- *hbase-jruby* provides a few basic aggregation methods using
573
- the built-in coprocessor called
563
+ You can perform some basic aggregation using the built-in coprocessor called
574
564
  `org.apache.hadoop.hbase.coprocessor.AggregateImplementation`.
575
565
 
576
566
  To enable this feature, call `enable_aggregation!` method,
577
- which will first disable the table, add the coprocessor, then enable it.
567
+ which adds the coprocessor to the table.
578
568
 
579
569
  ```ruby
580
570
  table.enable_aggregation!
581
- # Just a shorthand notation for
582
- # table.add_coprocessor! 'org.apache.hadoop.hbase.coprocessor.AggregateImplementation'
571
+ # Just a shorthand notation for
572
+ # table.add_coprocessor! 'org.apache.hadoop.hbase.coprocessor.AggregateImplementation'
583
573
  ```
584
574
 
585
575
  Then you can get the sum, average, minimum, maximum, row count, and standard deviation
@@ -598,8 +588,8 @@ table.project('cf1:a').aggregate(:row_count)
598
588
  table.project('cf1:a', 'cf1:b').aggregate(:sum)
599
589
  ```
600
590
 
601
- By default, aggregate method assumes the column values are 8-byte integers.
602
- For types other than that, you can pass your own ColumnInterpreter.
591
+ By default, aggregate method assumes that the projected values are 8-byte integers.
592
+ For other data types, you can pass your own ColumnInterpreter.
603
593
 
604
594
  ```ruby
605
595
  table.project('cf1:b').aggregate(:sum, MyColumnInterpreter.new)
@@ -685,26 +675,33 @@ table.remove_coprocessor! cp_class_name1
685
675
 
686
676
  You can perform other types of administrative tasks
687
677
  with Native Java [HBaseAdmin object](http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/HBaseAdmin.html),
688
- which can be obtained by `HBase#admin` method which will automatically close the object at the end of the given block.
678
+ which can be obtained by `HBase#admin` method. Optionally, a block can be given
679
+ so that the HBaseAdmin object is automatically closed at the end of the given block.
689
680
 
690
681
  ```ruby
691
682
  # Advanced table administration with HBaseAdmin object
692
683
  # http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/client/HBaseAdmin.html
693
- hbase.admin do |admin|
694
- # ...
695
- end
696
-
697
- # Without the block
698
684
  admin = hbase.admin
699
685
  # ...
700
686
  admin.close
687
+
688
+ # With the block
689
+ hbase.admin do |admin|
690
+ # ...
691
+ end
701
692
  ```
702
693
 
703
694
  ## Test
704
695
 
705
- ```
696
+ ```bash
697
+ # Bash script
706
698
  export HBASE_JRUBY_TEST_ZK='your-hbaase.domain.net'
707
- rake test
699
+
700
+ # Test both for 1.8 and 1.9
701
+ for v in --1.8 --1.9; do
702
+ export JRUBY_OPTS=$v
703
+ rake test
704
+ done
708
705
  ```
709
706
 
710
707
  ## Contributing
@@ -57,11 +57,13 @@ class HBase
57
57
  end
58
58
 
59
59
  # Load jars
60
- jars.select { |jar| File.exists?(jar) && File.extname(jar) == '.jar' }.select do |jar|
60
+ jars_loaded = jars.select { |jar| File.exists?(jar) && File.extname(jar) == '.jar' }.select do |jar|
61
61
  require jar
62
62
  end
63
63
 
64
64
  Util.import_java_classes!
65
+
66
+ return jars_loaded
65
67
  ensure
66
68
  tempfiles.each { |tempfile| tempfile.unlink rescue nil }
67
69
  end
@@ -7,7 +7,8 @@ module Aggregation
7
7
  # Enables aggregation support for the table
8
8
  # @return [nil]
9
9
  def enable_aggregation!
10
- add_coprocessor! 'org.apache.hadoop.hbase.coprocessor.AggregateImplementation'
10
+ cpc = 'org.apache.hadoop.hbase.coprocessor.AggregateImplementation'
11
+ add_coprocessor! cpc unless has_coprocessor?(cpc)
11
12
  end
12
13
  end
13
14
 
@@ -19,14 +19,18 @@ class Scoped
19
19
  # @return [Fixnum, Bignum] The number of rows in the scope
20
20
  def count
21
21
  cnt = 0
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
22
+ begin
23
+ if block_given?
24
+ scanner = htable.getScanner(filtered_scan)
25
+ scanner.each do |result|
26
+ cnt += 1 if yield(Result.send(:new, result))
27
+ end
28
+ else
29
+ scanner = htable.getScanner(filtered_scan_minimum)
30
+ scanner.each { cnt += 1 }
29
31
  end
32
+ ensure
33
+ scanner.close if scanner
30
34
  end
31
35
  cnt
32
36
  end
@@ -111,7 +115,7 @@ class Scoped
111
115
  # table.range(:prefix => ['2010', '2012'])
112
116
  def range *key_range
113
117
  if key_range.last.is_a?(Hash)
114
- prefixes = [*key_range.last[:prefix]]
118
+ prefixes = [*key_range.last[:prefix]].compact
115
119
  raise ArgumentError,
116
120
  "Invalid range. Unknown option(s) specified." unless (key_range.last.keys - [:prefix]).empty?
117
121
  key_range = key_range[0...-1]
@@ -328,7 +332,7 @@ private
328
332
  end if range
329
333
 
330
334
  # Prefix filters
331
- filters += [*build_prefix_filter]
335
+ filters += [*build_prefix_filter].compact
332
336
 
333
337
  # RowFilter must precede the others
334
338
  filters += @filters
@@ -365,7 +369,7 @@ private
365
369
  CompareFilter::CompareOp::LESS_OR_EQUAL
366
370
  when :eq, :==
367
371
  CompareFilter::CompareOp::EQUAL
368
- when :ne, :!=
372
+ when :ne # , :!= # Ruby 1.8 compatibility
369
373
  CompareFilter::CompareOp::NOT_EQUAL
370
374
  else
371
375
  raise ArgumentError, "Unknown operator: #{op}"
@@ -375,7 +379,7 @@ private
375
379
  # XXX TODO Undocumented feature
376
380
  FilterList.new(
377
381
  case op
378
- when :ne, :!=
382
+ when :ne # , :!=
379
383
  FilterList::Operator::MUST_PASS_ALL
380
384
  else
381
385
  FilterList::Operator::MUST_PASS_ONE
@@ -428,7 +432,7 @@ private
428
432
  scan.caching = @caching if @caching
429
433
 
430
434
  # Filters
431
- prefix_filter = [*build_prefix_filter]
435
+ prefix_filter = [*build_prefix_filter].compact
432
436
  filters = prefix_filter + @filters
433
437
  filters += process_projection!(scan)
434
438
 
@@ -462,11 +462,11 @@ private
462
462
  end
463
463
 
464
464
  def const_shortcut base, v, message
465
- vs = v.to_s.upcase.to_sym
466
- #if base.constants.map { |c| base.const_get c }.include?(v)
465
+ vs = v.to_s.upcase
466
+ # const_get doesn't work with symbols in 1.8 compatibility mode
467
467
  if base.constants.map { |c| base.const_get c }.any? { |cv| v == cv }
468
468
  v
469
- elsif base.constants.include? vs
469
+ elsif base.constants.map(&:to_s).include?(vs)
470
470
  base.const_get vs
471
471
  else
472
472
  raise ArgumentError, [message, v.to_s].join(': ')
@@ -89,7 +89,7 @@ module Util
89
89
  raise ArgumentError, "Column family not specified"
90
90
  else
91
91
  cf, cq = KeyValue.parseColumn(col.to_s.to_java_bytes)
92
- cq = JAVA_BYTE_ARRAY_EMPTY if cq.nil? && col.to_s[-1] == ':'
92
+ cq = JAVA_BYTE_ARRAY_EMPTY if cq.nil? && col.to_s[-1, 1] == ':'
93
93
  return cf, cq
94
94
  end
95
95
  end
@@ -171,6 +171,8 @@ module Util
171
171
  org.apache.hadoop.hbase.client.coprocessor.LongColumnInterpreter
172
172
  ]
173
173
  end
174
+
175
+ nil
174
176
  end
175
177
  end
176
178
  end#Util
@@ -1,5 +1,5 @@
1
1
  class HBase
2
2
  module JRuby
3
- VERSION = "0.1.2"
3
+ VERSION = "0.1.3"
4
4
  end
5
5
  end
data/test/helper.rb CHANGED
@@ -11,7 +11,10 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
11
11
  require "hbase-jruby"
12
12
 
13
13
  # Required
14
- HBase.resolve_dependency! 'cdh4.1.2'
14
+ unless HBase.resolve_dependency!('cdh4.1.2').all? { |f| File.exists? f }
15
+ puts "Invalid return value from HBase.resolve_dependency!"
16
+ exit 1
17
+ end
15
18
 
16
19
  class TestHBaseJRubyBase < Test::Unit::TestCase
17
20
  TABLE = 'test_hbase_jruby'
@@ -3,22 +3,23 @@
3
3
  $LOAD_PATH.unshift File.expand_path('..', __FILE__)
4
4
  require 'helper'
5
5
 
6
- class TestAggregation < TestHBaseJRubyBase
6
+ class TestAggregation < TestHBaseJRubyBase
7
7
  def test_aggregation
8
8
  (1..100).each do |idx|
9
9
  @table.put idx, 'cf1:a' => idx, 'cf1:b' => idx * 2
10
10
  end
11
11
 
12
- @table.enable_aggregation!
12
+ assert_nil @table.enable_aggregation!
13
+ assert_nil @table.enable_aggregation! # no prob!
13
14
 
14
15
  lci = org.apache.hadoop.hbase.client.coprocessor.LongColumnInterpreter.new
15
16
  [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?
17
+ assert_equal 100, @table.project('cf1:a').aggregate(:row_count, *[*ci].compact)
18
+ assert_equal 5050, @table.project('cf1:a').aggregate(:sum, *[*ci].compact)
19
+ assert_equal 1, @table.project('cf1:a').aggregate(:min, *[*ci].compact)
20
+ assert_equal 100, @table.project('cf1:a').aggregate(:max, *[*ci].compact)
21
+ assert_equal 50.5, @table.project('cf1:a').aggregate(:avg, *[*ci].compact)
22
+ assert_equal 28, @table.project('cf1:a').aggregate(:std, *[*ci].compact).to_i # FIXME: 28 or 29?
22
23
  end
23
24
 
24
25
  [%w[cf1:a cf1:b], %w[cf1]].each do |prj|
data/test/test_scoped.rb CHANGED
@@ -45,8 +45,8 @@ class TestScoped < TestHBaseJRubyBase
45
45
 
46
46
  def test_invalid_filter
47
47
  assert_raise(ArgumentError) { @table.filter(3.14) }
48
- assert_raise(ArgumentError) { @table.filter('cf1:a' => { xxx: 50 }) }
49
- assert_raise(ArgumentError) { @table.filter('cf1:a' => { eq: { 1 => 2 } }) }
48
+ assert_raise(ArgumentError) { @table.filter('cf1:a' => { :xxx => 50 }) }
49
+ assert_raise(ArgumentError) { @table.filter('cf1:a' => { :eq => { 1 => 2 } }) }
50
50
  end
51
51
 
52
52
  def test_each_and_count
@@ -132,13 +132,13 @@ class TestScoped < TestHBaseJRubyBase
132
132
  assert_equal 0, table.filter('cf1:a' => 50, 'cf2:b' => 90...100).to_a.length
133
133
  assert_equal 6, table.filter('cf1:a' => 50..60, 'cf2:b' => 100..110).to_a.length
134
134
  assert_equal 10, table.filter('cf1:a' => { :> => 50, :<= => 60 }).to_a.length
135
- assert_equal 9, table.filter('cf1:a' => { :> => 50, :<= => 60, :!= => 55 }).to_a.length
136
- assert_equal 10, table.filter('cf1:a' => { :>= => 50, :<= => 60, :!= => 55 }).to_a.length
137
- assert_equal 9, table.filter('cf1:a' => { :>= => 50, :< => 60, :!= => 55 }).to_a.length
135
+ assert_equal 9, table.filter('cf1:a' => { :> => 50, :<= => 60, :ne => 55 }).to_a.length
136
+ assert_equal 10, table.filter('cf1:a' => { :>= => 50, :<= => 60, :ne => 55 }).to_a.length
137
+ assert_equal 9, table.filter('cf1:a' => { :>= => 50, :< => 60, :ne => 55 }).to_a.length
138
138
  assert_equal 1, table.filter('cf1:a' => { :> => 50, :<= => 60, :== => 55 }).to_a.length
139
139
  assert_equal 2, table.filter('cf1:a' => { :> => 50, :<= => 60, :== => [55, 57] }).to_a.length
140
- assert_equal 9, table.filter('cf1:a' => { gte: 50, lt: 60, ne: 55 }).to_a.length
141
- assert_equal 7, table.filter('cf1:a' => { gte: 50, lt: 60, ne: [55, 57, 59] }).to_a.length
140
+ assert_equal 9, table.filter('cf1:a' => { :gte => 50, :lt => 60, :ne => 55 }).to_a.length
141
+ assert_equal 7, table.filter('cf1:a' => { :gte => 50, :lt => 60, :ne => [55, 57, 59] }).to_a.length
142
142
 
143
143
  # filter: Hash + additive
144
144
  assert_equal 6, table.filter('cf1:a' => 50..60).filter('cf2:b' => 100..110).to_a.length
@@ -149,7 +149,7 @@ class TestScoped < TestHBaseJRubyBase
149
149
  assert_equal 3, table.filter(ColumnPaginationFilter.new(3, 1)).first.to_hash.keys.length
150
150
 
151
151
  # filter: Java filter list
152
- import org.apache.hadoop.hbase.filter.FilterList
152
+ import org.apache.hadoop.hbase.filter.FilterList
153
153
  import org.apache.hadoop.hbase.filter.ColumnRangeFilter
154
154
  assert_equal %w[cf2:b cf3:c],
155
155
  table.filter(FilterList.new [
@@ -216,7 +216,7 @@ class TestScoped < TestHBaseJRubyBase
216
216
 
217
217
  hash = @table.get('rowkey').to_hash(
218
218
  HBase::ColumnKey('cf1', 1) => :fixnum,
219
- HBase::ColumnKey('cf1', 2) => :fixnum,
219
+ HBase::ColumnKey('cf1', 2) => :fixnum
220
220
  )
221
221
  assert_equal 1, hash[HBase::ColumnKey(:cf1, 1)]
222
222
  assert_equal 2, hash[HBase::ColumnKey(:cf1, 2)]
@@ -325,12 +325,12 @@ class TestScoped < TestHBaseJRubyBase
325
325
  @table.put idx, 'cf1:a' => idx % 10, 'cf2:b' => 'Hello'
326
326
  end
327
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
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
330
 
331
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
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
334
  end
335
335
 
336
336
  def test_min_max
@@ -356,7 +356,7 @@ class TestScoped < TestHBaseJRubyBase
356
356
  assert_equal 26, @table.filter('cf1:a' => /g$/).count
357
357
  assert_equal 2, @table.filter('cf1:a' => /gg|ff/).count
358
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
359
+ assert_equal 54, @table.filter('cf1:a' => ['aa', 'cc', /^g/, { :gte => 'xa', :lt => 'y'}]).count
360
360
  end
361
361
  end
362
362
 
data/test/test_table.rb CHANGED
@@ -137,7 +137,7 @@ class TestScoped < TestHBaseJRubyBase
137
137
  'cf1:c' => 3.14,
138
138
  'cf2:d' => :world,
139
139
  'cf2:e' => false,
140
- 'cf3:f' => BigDecimal.new(1234567890123456789012345678901234567890),
140
+ 'cf3:f' => BigDecimal.new('1234567890123456789012345678901234567890'),
141
141
  'cf3' => true
142
142
  }
143
143
  schema = {
@@ -3,7 +3,7 @@
3
3
  $LOAD_PATH.unshift File.expand_path('..', __FILE__)
4
4
  require 'helper'
5
5
 
6
- class TestTableAdmin < TestHBaseJRubyBase
6
+ class TestTableAdmin < TestHBaseJRubyBase
7
7
  def teardown
8
8
  @table.drop! if @table.exists?
9
9
  end
@@ -11,7 +11,7 @@ class TestTableAdmin < TestHBaseJRubyBase
11
11
  def test_create_table_symbol_string
12
12
  t = @hbase.table(:test_hbase_jruby_create_table)
13
13
  t.drop! if t.exists?
14
- [ :cf, 'cf', :cf => {} ].each do |cf|
14
+ [ :cf, 'cf', {:cf => {}} ].each do |cf|
15
15
  assert_false t.exists?
16
16
  t.create! cf
17
17
  assert t.exists?
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: hbase-jruby
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.2
5
+ version: 0.1.3
6
6
  platform: java
7
7
  authors:
8
8
  - Junegunn Choi
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-28 00:00:00.000000000 Z
12
+ date: 2012-11-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: test-unit