使用MultipleOutputs在MapReduce中写入HBase

时间:2011-05-12 19:07:43

标签: hadoop mapreduce hbase

我目前有一个MapReduce作业,它使用MultipleOutputs将数据发送到多个HDFS位置。完成后,我使用HBase客户端调用(在MR之外)将一些相同的元素添加到几个HBase表中。使用TableOutputFormat将HBase输出添加为额外的MultipleOutputs会很不错。这样,我就会分发我的HBase处理。

问题是,我无法让这个工作。有没有人曾在MultipleOutputs中使用过TableOutputFormat ...?有多个HBase输出?

基本上,我正在设置我的收藏家,就像这样......

Outputcollector<ImmutableBytesWritable, Writable> hbaseCollector1 = multipleOutputs.getCollector("hbase1", reporter); 
Outputcollector<ImmutableBytesWritable, Writable> hbaseCollector2 = multipleOutputs.getCollector("hbase2", reporter); 
Put put = new Put(mykey.getBytes());
put.add("family".getBytes(), "column".getBytes(), somedata1);
hbaseCollector1.collect(NullWritable.get(), put);

put = new Put(mykey.getBytes());
put.add("family".getBytes(), "column".getBytes(), somedata2);
hbaseCollector2.collect(newImmutableBytesWritable(mykey.getBytes()), put);

我认为这似乎遵循了hbase写作的一般概念。

部分问题,正如我输入的那样,可能在作业定义中更多。看起来像MR(和Hbase)想要一个全局参数集,就像这样....

conf.set(TableOutputFormat.OUTPUT_TABLE, "articles");

提供表名。麻烦的是,我有两张桌子......

有什么想法吗?

由于

3 个答案:

答案 0 :(得分:4)

我以不同的方式将数据放入HBase 3中。最有效(和分布式)是使用HFileOutputFormat类。

我按如下方式设置工作...(请注意,这是根据实际代码编辑的,但核心内容仍然存在)

cubeBuilderETLJob.setJobName(jobName);
cubeBuilderETLJob.setMapOutputKeyClass(ImmutableBytesWritable.class);
cubeBuilderETLJob.setMapOutputValueClass(Put.class);
cubeBuilderETLJob.setMapperClass(HiveToHBaseMapper.class);      
cubeBuilderETLJob.setJarByClass(CubeBuilderDriver.class);       
cubeBuilderETLJob.setInputFormatClass(TextInputFormat.class);
cubeBuilderETLJob.setOutputFormatClass(HFileOutputFormat.class);
HFileOutputFormat.setOutputPath(cubeBuilderETLJob, cubeOutputPath);
HTable hTable = null;
Configuration hConf = HBaseConfiguration.create(conf);
hConf.set("ZOOKEEPER_QUORUM", hbaseZookeeperQuorum);
hConf.set("ZOOKEEPER_CLIENTPORT", hbaseZookeeperClientPort);
hTable = new HTable(hConf, tableName);
HFileOutputFormat.configureIncrementalLoad(cubeBuilderETLJob, hTable);

正如我们所看到的,我的Mapper类被称为HiveToHBaseMapper - 很好且原创。 :)这是它的(再次,粗略的)定义

public class HiveToHBaseMapper extends
    Mapper<WritableComparable, Writable, ImmutableBytesWritable, Put> {
@Override
public void map(WritableComparable key, Writable val, Context context)
    throws IOException, InterruptedException {
    Configuration config = context.getConfiguration();
    String family = config.get("FAMILY");
    Double value = Double.parseDouble(sValue);
    String sKey = generateKey(config);
    byte[] bKey = Bytes.toBytes(sKey);
    Put put = new Put(bKey);
    put.add(Bytes.toBytes(family), Bytes.toBytes(column), (value <= 0) 
        ? Bytes.toBytes(Double.MIN_VALUE)
        : Bytes.toBytes(value));        
    ImmutableBytesWritable ibKey = new ImmutableBytesWritable(bKey);
    context.write(ibKey, put);
}

我不知道您是否可以使用它来使其适合MultipleOutputs或需要创建新的MR作业。这是我遇到将数据导入HBase的最佳方式。 :)

这有望帮助您找到解决方案的正确方向。

答案 1 :(得分:1)

根据我的经验,最好的方法是在数据可用时立即将数据放入hbase表中(除非您是批量加载数据)。如果您的地图任务中有可用的数据,那么这是将其推送到hbase的最佳时间。如果在reduce任务之前没有数据,那么将push添加到hbase。在你知道HBase是你的瓶颈之前,让HBase担心缓存问题。

答案 2 :(得分:1)

所以,显然,旧的mapred包不可能实现这一点。 mapreduce包集中有一个新的OutputFormat,但我现在不想转换为它。所以,我将不得不写多个MR工作。