Author: stack
Date: Tue Nov 24 19:44:32 2009
New Revision: 883833

URL: http://svn.apache.org/viewvc?rev=883833&view=rev
Log:
HBASE-1901 General partitioner for hbase-48 bulk (behind the api, write hfiles 
direct) uploader

Added:
    
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/SimpleTotalOrderPartitioner.java
    
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestSimpleTotalOrderPartitioner.java
Modified:
    hadoop/hbase/trunk/CHANGES.txt
    
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/package-info.java
    
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java

Modified: hadoop/hbase/trunk/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/CHANGES.txt?rev=883833&r1=883832&r2=883833&view=diff
==============================================================================
--- hadoop/hbase/trunk/CHANGES.txt (original)
+++ hadoop/hbase/trunk/CHANGES.txt Tue Nov 24 19:44:32 2009
@@ -199,6 +199,10 @@
    HBASE-1961  HBase EC2 scripts
    HBASE-1971  Unit test the full WAL replay cycle
 
+  NEW FEATURES
+   HBASE-1901  "General" partitioner for "hbase-48" bulk (behind the api, write
+               hfiles direct) uploader
+
   OPTIMIZATIONS
    HBASE-410   [testing] Speed up the test suite
 

Added: 
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/SimpleTotalOrderPartitioner.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/SimpleTotalOrderPartitioner.java?rev=883833&view=auto
==============================================================================
--- 
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/SimpleTotalOrderPartitioner.java
 (added)
+++ 
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/SimpleTotalOrderPartitioner.java
 Tue Nov 24 19:44:32 2009
@@ -0,0 +1,96 @@
+/**
+ * Copyright 2009 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.mapreduce;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configurable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.mapreduce.Partitioner;
+
+/**
+ * A partitioner that takes start and end keys and uses bigdecimal to figure
+ * which reduce a key belongs to.  Pass the start and end
+ * keys in the Configuration using <code>hbase.simpletotalorder.start</code>
+ * and <code>hbase.simpletotalorder.end</code>.  The end key needs to be
+ * exclusive; i.e. one larger than the biggest key in your key space.
+ * You may be surprised at how this class partitions the space; it may not
+ * align with preconceptions; e.g. a start key of zero and an end key of 100
+ * divided in ten will not make regions whose range is 0-10, 10-20, and so on.
+ * Make your own partitioner if you need the region spacing to come out a
+ * particular way.
+ * @param <VALUE>
+ * @see #START
+ * @see #END
+ */
+public class SimpleTotalOrderPartitioner<VALUE> extends 
Partitioner<ImmutableBytesWritable, VALUE>
+implements Configurable {
+  private final Log LOG = LogFactory.getLog(this.getClass());
+  public static final String START = "hbase.simpletotalorder.start";
+  public static final String END = "hbase.simpletotalorder.end";
+  private Configuration c;
+  private byte [] startkey;
+  private byte [] endkey;
+  private byte [][] splits;
+  private int lastReduces = -1;
+  
+  @Override
+  public int getPartition(final ImmutableBytesWritable key, final VALUE value,
+      final int reduces) {
+    if (reduces == 1) return 0;
+    if (this.lastReduces != reduces) {
+      this.splits = Bytes.split(this.startkey, this.endkey, reduces - 1);
+      for (int i = 0; i < splits.length; i++) {
+        LOG.info(Bytes.toString(splits[i]));
+      }
+    }
+    int pos = Bytes.binarySearch(this.splits, key.get(), key.getOffset(),
+      key.getLength(), Bytes.BYTES_RAWCOMPARATOR);
+    // Below code is from hfile index search.
+    if (pos < 0) {
+      pos++;
+      pos *= -1;
+      if (pos == 0) {
+        // falls before the beginning of the file.
+        throw new RuntimeException("Key outside start/stop range: " +
+          key.toString());
+      }
+      pos--;
+    }
+    return pos;
+  }
+
+  @Override
+  public Configuration getConf() {
+    return this.c;
+  }
+
+  @Override
+  public void setConf(Configuration conf) {
+    this.c = conf;
+    String startStr = this.c.get(START);
+    String endStr = this.c.get(END);
+    LOG.info("startkey=" + startStr + ", endkey=" + endStr);
+    this.startkey = Bytes.toBytes(startStr);
+    this.endkey = Bytes.toBytes(endStr);
+  }
+}
\ No newline at end of file

Modified: 
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/package-info.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/package-info.java?rev=883833&r1=883832&r2=883833&view=diff
==============================================================================
--- 
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/package-info.java 
(original)
+++ 
hadoop/hbase/trunk/src/java/org/apache/hadoop/hbase/mapreduce/package-info.java 
Tue Nov 24 19:44:32 2009
@@ -109,8 +109,8 @@
 <h2><a name="bulk">Bulk import writing HFiles directly</a></h2>
 <p>If importing into a new table, its possible to by-pass the HBase API
 and write your content directly to the filesystem properly formatted as
-HBase data files (HFiles).  Your import will run faster, perhaps as much
-as an order of magnitude faster if not more.
+HBase data files (HFiles).  Your import will run faster, perhaps an order of
+magnitude faster if not more.
 </p>
 <p>You will need to write a MapReduce job.  The map task will know how to
 pull from your data source.  Your reduce task will need to be hooked up to
@@ -131,14 +131,20 @@
 Given the default hash Partitioner, if the keys were 0-4 (inclusive), and you
 had configured two reducers, reducer 0 would have get keys 0, 2 and 4 whereas
 reducer 1 would get keys 1 and 3 (in order).  For your bulk import to work,
-the keys need to be orderd so reducer 0 gets keys 0-2 and reducer 1 gets keys
-3-4 (See TotalOrderPartitioner up in hadoop for more on what this means). 
+the keys need to be ordered so reducer 0 gets keys 0-2 and reducer 1 gets keys
+3-4 (See TotalOrderPartitioner up in hadoop for more on what this means.  See
+how it runs a sampler step first.  You may need to write one of these).
 To achieve total ordering, you will likely need to write a Partitioner
 that is intimate with your tables key namespace and that knows how
-to distribute keys among the reducers so a total order is maintained.
+to distribute keys among the reducers so a total order is maintained.  If your
+keys are distributed with some regularity across a defined key space -- i.e.
+you know the start and end keys -- then the {...@link 
SimpleTotalOrderPartitioner} 
+may be all you need.
 </p>
-<p>See org.apache.hadoop.hbase.mapreduce.TestHFileOutputFormat for an example 
that puts together
-...@link org.apache.hadoop.hbase.mapreduce.KeyValueSortReducer} and {...@link 
org.apache.hadoop.hbase.mapreduce.HFileOutputFormat}.</p>
+<p>See org.apache.hadoop.hbase.mapreduce.TestHFileOutputFormat for an example
+that puts together {...@link 
org.apache.hadoop.hbase.mapreduce.KeyValueSortReducer},
+...@link SimpleTotalOrderPartitioner}, and
+...@link org.apache.hadoop.hbase.mapreduce.HFileOutputFormat}.</p>
 
 <p>HFileOutputFormat writes HFiles.  When your MapReduce file finishes, in your
 output directory you will have many HFiles.  Run the script 
<code>bin/loadtable.rb</code>

Modified: 
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java?rev=883833&r1=883832&r2=883833&view=diff
==============================================================================
--- 
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java
 (original)
+++ 
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestHFileOutputFormat.java
 Tue Nov 24 19:44:32 2009
@@ -31,6 +31,7 @@
 import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.PerformanceEvaluation;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.io.Writable;
 import org.apache.hadoop.mapreduce.InputFormat;
 import org.apache.hadoop.mapreduce.InputSplit;
@@ -172,6 +173,15 @@
     job.setMapperClass(TestHFileOutputFormat.PEtoKVMapper.class);
     job.setMapOutputKeyClass(ImmutableBytesWritable.class);
     job.setMapOutputValueClass(KeyValue.class);
+    // This partitioner doesn't work well for number keys but using it anyways
+    // just to demonstrate how to configure it.
+    job.setPartitionerClass(SimpleTotalOrderPartitioner.class);
+    // Set start and end rows for partitioner.
+    job.getConfiguration().set(SimpleTotalOrderPartitioner.START,
+      Bytes.toString(PerformanceEvaluation.format(0)));
+    int rows = this.conf.getInt("mapred.map.tasks", 1) * ROWSPERSPLIT;
+    job.getConfiguration().set(SimpleTotalOrderPartitioner.END,
+      Bytes.toString(PerformanceEvaluation.format(rows)));
     job.setReducerClass(KeyValueSortReducer.class);
     job.setOutputFormatClass(HFileOutputFormat.class);
     FileOutputFormat.setOutputPath(job, this.testDir);
@@ -179,4 +189,4 @@
     FileStatus [] files = this.fs.listStatus(this.testDir);
     assertTrue(files.length > 0);
   }
-}
+}
\ No newline at end of file

Added: 
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestSimpleTotalOrderPartitioner.java
URL: 
http://svn.apache.org/viewvc/hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestSimpleTotalOrderPartitioner.java?rev=883833&view=auto
==============================================================================
--- 
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestSimpleTotalOrderPartitioner.java
 (added)
+++ 
hadoop/hbase/trunk/src/test/org/apache/hadoop/hbase/mapreduce/TestSimpleTotalOrderPartitioner.java
 Tue Nov 24 19:44:32 2009
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2009 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hbase.mapreduce;
+
+import org.apache.hadoop.hbase.HBaseTestCase;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+
+/**
+ * Test of simple partitioner.
+ */
+public class TestSimpleTotalOrderPartitioner extends HBaseTestCase {
+  public void testSplit() throws Exception {
+    String start = "a";
+    String end = "{";
+    SimpleTotalOrderPartitioner<byte []> p =
+      new SimpleTotalOrderPartitioner<byte []>();
+    this.conf.set(SimpleTotalOrderPartitioner.START, start);
+    this.conf.set(SimpleTotalOrderPartitioner.END, end);
+    p.setConf(this.conf);
+    ImmutableBytesWritable c = new ImmutableBytesWritable(Bytes.toBytes("c"));
+    // If one reduce, partition should be 0.
+    int partition = p.getPartition(c, HConstants.EMPTY_BYTE_ARRAY, 1);
+    assertEquals(0, partition);
+    // If two reduces, partition should be 0.
+    partition = p.getPartition(c, HConstants.EMPTY_BYTE_ARRAY, 2);
+    assertEquals(0, partition);
+    // Divide in 3.
+    partition = p.getPartition(c, HConstants.EMPTY_BYTE_ARRAY, 3);
+    assertEquals(0, partition);
+    ImmutableBytesWritable q = new ImmutableBytesWritable(Bytes.toBytes("q"));
+    partition = p.getPartition(q, HConstants.EMPTY_BYTE_ARRAY, 2);
+    assertEquals(1, partition);
+    partition = p.getPartition(q, HConstants.EMPTY_BYTE_ARRAY, 3);
+    assertEquals(2, partition);
+    // What about end and start keys.
+    ImmutableBytesWritable startBytes =
+      new ImmutableBytesWritable(Bytes.toBytes(start));
+    partition = p.getPartition(startBytes, HConstants.EMPTY_BYTE_ARRAY, 2);
+    assertEquals(0, partition);
+    partition = p.getPartition(startBytes, HConstants.EMPTY_BYTE_ARRAY, 3);
+    assertEquals(0, partition);
+    ImmutableBytesWritable endBytes =
+      new ImmutableBytesWritable(Bytes.toBytes("z"));
+    partition = p.getPartition(endBytes, HConstants.EMPTY_BYTE_ARRAY, 2);
+    assertEquals(1, partition);
+    partition = p.getPartition(endBytes, HConstants.EMPTY_BYTE_ARRAY, 3);
+    assertEquals(2, partition);
+  }
+}


Reply via email to