【问题标题】:HBase using Put from Hadoop, but not seeing value in HBase shellHBase 使用 Hadoop 中的 Put,但在 HBase shell 中看不到价值
【发布时间】:2012-02-28 06:17:41
【问题描述】:

我有一个简单的 map/reduce 作业,它扫描一个 hbase 表,并修改另一个 hbase 表。 hadoop 作业似乎成功完成,但是当我检查 hbase 表时,该条目没有出现在那里。

这里是hadoop程序:

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.output.NullOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

public class HBaseInsertTest extends Configured implements Tool {

    @Override
    public int run(String[] args) throws Exception {
        String table = "duplicates";

        Scan scan = new Scan();
        scan.setCaching(500);
        scan.setCacheBlocks(false);

        Job job = new Job(getConf(), "HBaseInsertTest");
        job.setJarByClass(HBaseInsertTest.class);

        TableMapReduceUtil.initTableMapperJob(table, scan, Mapper.class, /* mapper output key = */null,
            /* mapper output value= */null, job);
        TableMapReduceUtil.initTableReducerJob("tablecopy", /*output table=*/null, /*reducer class=*/job);

        job.setNumReduceTasks(0);

        // Note that these are the default.
        job.setOutputFormatClass(NullOutputFormat.class);

        return job.waitForCompletion(true) ? 0 : 1;
    }

    private static class Mapper extends TableMapper<ImmutableBytesWritable, Put> {
        @Override
        protected void setup(Context context) throws IOException, InterruptedException {
            super.setup(context);
        }

        @Override
        public void map(ImmutableBytesWritable row, Result columns, Context context) throws IOException {
            long id = 1260018L;

            try {
                Put put = new Put(Bytes.toBytes(id));
                put.add(Bytes.toBytes("mapping"), Bytes.toBytes("foo"), Bytes.toBytes("bar"));
                context.write(row, put);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration config = HBaseConfiguration.create();
        int res = ToolRunner.run(config, new HBaseInsertTest(), args);
        System.exit(res);
    }
}

来自 HBase 外壳:

hbase(main):008:0> get 'tablecopy', '1260018', 'mapping'
COLUMN                          CELL                                                                                    
0 row(s) in 0.0100 seconds

我已经对程序进行了很多简化以尝试演示/隔离问题。我对 hadoop/hbase 也比较陌生。我确实验证了映射是 tablecopy 表中存在的列族。

【问题讨论】:

  • 可能没有输出?尝试在context.write之前打印出rowput
  • 有输出。切换到字符串键可以解决问题。

标签: mapreduce hbase


【解决方案1】:

我认为问题在于您要查询 hbase(main):008:0> 获取 'tablecopy', '1260018', 'mapping'

相反,您应该对此进行查询: hbase(main):008:0> 获取 'tablecopy', 1260018, 'mapping'

由于引号,HBase 认为它是您要查询的字符串键。此外,如果您只是在最后运行一个简单的客户端作业以从 HBase 检索此密钥,如果它已经存在,它将正确地为您获取值。

【讨论】:

  • 我以为我在没有引号的情况下尝试过,但我想不是。感谢您的回答!
【解决方案2】:

您的问题在于缺少减速器。您需要创建一个扩展TableReducer 的类,该类将Put 作为输入并使用context.write(ImmutableBytesWritable key, Put put) 将该Put 写入目标表。

我想象它看起来像这样:

public static class MyReducer extends TableReducer<ImmutableBytesWritable, Put, ImmutableBytesWritable> {

  public void reduce(ImmutableBytesWritable key, Iterable<Put> values, Context context)
      throws IOException, InterruptedException {
    for (Put record : values) {
      context.write(key, record);
    }
  }
}

然后,您将 table reducer 初始化程序修改为: TableMapReduceUtil.initTableReducerJob("tablecopy", MyReducer.class, job);

应该这样做。另一种选择是继续没有减速器并在映射器中打开一个HTable 对象,然后像这样直接通过它编写 put:

HTable table = new HTable(Context.getConfiguration(), "output_table_name");
Put myPut = ...;
table.put(myPut);
table.close();

希望这会有所帮助!

【讨论】:

  • 我实际上使用的是您提出的第二种方式,但这也不起作用。我认为问题与密钥很长并且 hbase shell 获取字符串密钥有关。
  • 一般来说,我认为您永远不会希望使用 reducer 将数据放入 hbase,除非您有比这复杂得多的任务。通过将 hbase 放入减速器中,您将引入整个 shuffle/sort 阶段,这将扼杀您的性能而没有明显的好处:hbase 是随机访问,不需要按顺序排列密钥
  • 是的——好点。回想起来,你绝对是对的
猜你喜欢
  • 1970-01-01
  • 2015-01-15
  • 2017-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-18
相关资源
最近更新 更多