利用MapReduce对HBase数据进行统计分析

1、HBase作为一种kv数据库,能够很好的面对高吞吐率的在线数据读写服务,尤其是写操作,但是在非rowkey多条件查询、数据分析、统计等场景下,HBase表现的就不是很好了,这些场景下就比较适合来用MapReduce来计算。

2、应用场景

假设有一张HBase表article,有一列是数据来源source,现在需要统计不同来源的文章数量(数据行数),对于这样的简单统计需求,可以利用MapReduce程序来实现。

3、Map程序

TableAnalyzeMap继承HBase的TableMapper基类,把source列看做文本,行数自然是整数,所以key-value输出类型自然是

[java]  view plain  copy
  1. public class TableAnalyzeMap extends TableMapper {  
  2.   
  3.     @Override  
  4.     protected void map(ImmutableBytesWritable key, Result value,  
  5.             Mapper.Context context)  
  6.             throws IOException, InterruptedException {  
  7.         try {  
  8.             for (Cell cell : value.listCells()) {  
  9.                 String qualifier = new String(CellUtil.cloneQualifier(cell));  
  10.                 String colValue = new String(CellUtil.cloneValue(cell), "UTF-8");  
  11.                 System.out.print(qualifier + "=" + colValue + "\t");  
  12.                 context.write(new Text(colValue), new IntWritable(1));  
  13.             }  
  14.         } catch (Exception e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.     }  
  18.   
  19. }  
4、Reduce程序

TableAnalyzeReduce继承HBase的TableReducer基类,这里需要把最终聚合后的结果写到目标表中,rowkey对应source,行数对应目标表的column:count列。

[java]  view plain  copy
  1. public class TableAnalyzeReduce extends TableReducer {  
  2.   
  3.     @Override  
  4.     protected void reduce(Text key, Iterable values, Context context)  
  5.             throws IOException, InterruptedException {  
  6.         int i = 0;  
  7.         for (IntWritable val : values) {  
  8.             i += val.get();  
  9.         }  
  10.         Put put = new Put(Bytes.toBytes(key.toString()));  
  11.         put.addColumn(Bytes.toBytes("column"), Bytes.toBytes("count"), Bytes.toBytes(i));  
  12.         System.out.println(key.toString() + "\t" + i);  
  13.         context.write(null, put);  
  14.     }  
  15.   
  16. }  
5、Combiner程序

分析map程序,可以看到map阶段处理后的数据是没有任何合并的,key为数据来源source,value都是1,这样的话,如果直接进入reduce阶段,要分发的数据量还是比较大的,会造成网络负担,针对这个问题,可以在map阶段后,做一下本地reduce,这样进入reduce的阶段的数据量会大大减少。

[java]  view plain  copy
  1. public class TableAnalyzeCombin extends Reducer {  
  2.   
  3.     @Override  
  4.     protected void reduce(Text key, Iterable values, Context context)  
  5.             throws IOException, InterruptedException {  
  6.         int i = 0;  
  7.         for (IntWritable val : values) {  
  8.             i += val.get();  
  9.         }  
  10.         context.write(key, new IntWritable(i));  
  11.     }  
  12.   
  13. }  
6、主程序

程序接收四个参数,依次为:业务表名称、source字段列族、source字段列名、目标表名,当然也可以使用Apache Commons CLI类解析命令行参数。
scan.setCaching(500)设置每次读取行数,根据实际情况进行配置,scan.setCacheBlocks(false)告诉HBase本次扫描的数据不要放入缓存中。

[java]  view plain  copy
  1. public static void main(String[] args) throws ClassNotFoundException, InterruptedException {  
  2.     String tableName = args[0];  
  3.     String family = args[1];  
  4.     String column = args[2];  
  5.     String targetTbale = args[3];  
  6.     System.out.println("tableName=" + tableName + ", family=" + family + ", column=" + column + ", targetTbale="  
  7.             + targetTbale);  
  8.   
  9.     Configuration conf = HBaseConfiguration.create();  
  10.     Scan scan = new Scan();  
  11.     scan.setCaching(500);  
  12.     scan.setCacheBlocks(false);  
  13.     scan.addColumn(Bytes.toBytes(family), Bytes.toBytes(column));  
  14.     try {  
  15.         Job job = Job.getInstance(conf, "analyze table data for " + tableName);  
  16.         job.setJarByClass(HBaseMR.class);  
  17.         TableMapReduceUtil.initTableMapperJob(Bytes.toBytes(tableName), scan, TableAnalyzeMap.class, Text.class,  
  18.                 IntWritable.class, job);  
  19.         TableMapReduceUtil.initTableReducerJob(targetTbale, TableAnalyzeReduce.class, job);  
  20.         job.setMapperClass(TableAnalyzeMap.class);  
  21.         job.setReducerClass(TableAnalyzeReduce.class);  
  22.         job.setCombinerClass(TableAnalyzeCombin.class);  
  23.         job.setNumReduceTasks(1);  
  24.         System.exit(job.waitForCompletion(true) ? 0 : 1);  
  25.     } catch (IOException e) {  
  26.         e.printStackTrace();  
  27.     }  
  28. }  
7、Job执行

整个mapreduce程序开发完成需要生成相应jar包,将jar上传到集群中某个主机上通过hadoop jar运行。
# sudo -u hdfs hadoop jar HBaseMR.jar HBaseMR article column source analyze_result
当然,如果要在hbase集群外执行的话,作业执行程序里就要配置hbase必要环境信息。
在运行时要是出现找不到HBase相关类,需要在将/usr/lib/hbase/lib/下的相关jar软连接到/usr/lib/hadoop-mapreduce/目录下
# ln -s /usr/lib/hbase/lib/*.jar /usr/lib/hadoop-mapreduce/*.jar

你可能感兴趣的:(大数据)