这篇文章是看了HBase权威指南之后,依据上面的解说搬下来的样例,可是略微有些不一样。

HBase与mapreduce的集成无非就是mapreduce作业以HBase表作为输入,或者作为输出,也或者作为mapreduce作业之间共享数据的介质。

这篇文章将解说两个样例:

1、读取存储在hdfs上的txt文本数据,简单地以json字符串的形式存储到HBase表中。

2、将第一步存储的HBase表中的json字符串读取出来,解析存储到新的HBase表中,能够进行查询。

本文具体给出了源代码以及怎样执行,旨在加深HBase与mapreduce集成的学习。

假设你还不知道怎么搭建基于HDFS的HBase单机环境,以及怎样执行mapreduce任务,那么请先參考我这两篇文章:

(1) HBase环境搭建(一)Ubuntu下基于Hadoop文件系统的单机模式

(2) Hadoop基础学习(一)分析、编写并执行WordCount词频统计程序

1、读取存储在hdfs上的txt文本数据,简单地以json字符串的形式存储到HBase表中。

源代码:

/**
* @author 季义钦
* @date 2014-6
* @reference HBase权威指南 chapter7
*
*/ import java.io.IOException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableOutputFormat;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.util.GenericOptionsParser; public class HdfsToHBase
{
private static final Log LOG = LogFactory.getLog(HdfsToHBase.class);
public static final String NAME = "ImportFromFile";
public enum Counters { LINES } /**
* Map类
*
*/
static class ImportMapper
extends Mapper<LongWritable, Text, ImmutableBytesWritable, Writable>
{
private byte[] family = null;
private byte[] qualifier = null; @Override
protected void setup(Context context) throws IOException, InterruptedException
{
//获取通过Configuration传过来的列名
String columns = context.getConfiguration().get("conf.column"); //解析出列族和列的名称
byte[][] columnsBytes = KeyValue.parseColumn(Bytes.toBytes(columns));
family = columnsBytes[0];
qualifier = columnsBytes[1]; LOG.info("family:"+family.toString()+"qualifiers:"+qualifier);
} @Override
public void map(LongWritable offset, Text line, Context context) throws IOException
{
try
{
String lineStr = line.toString();
byte[] rowkey = DigestUtils.md5(lineStr); //构造Put对象
Put put = new Put(rowkey);
put.add(family, qualifier, Bytes.toBytes(lineStr)); //发射Put对象
context.write(new ImmutableBytesWritable(rowkey), put);
context.getCounter(Counters.LINES).increment(1); }catch(Exception e)
{
e.printStackTrace();
}
} } /**
* 将命令行參数解析为HBase的CommandLine对象
* @param args
* @return
* @throws ParseException
*/
private static CommandLine parseArgs(String[] args) throws ParseException
{
Options options = new Options();
Option o = new Option("t", "table", true, "table to import into (must exist)");
o.setArgName("table-name");
o.setRequired(true);
options.addOption(o); o = new Option("c", "column", true, "column to store row data into (must exist)");
o.setArgName("family:qualifier");
o.setRequired(true);
options.addOption(o); o = new Option("i", "input", true, "the directory or file to read from");
o.setArgName("path-in-HDFS");
o.setRequired(true);
options.addOption(o); CommandLineParser parser = new PosixParser();
CommandLine cmd = null; try
{
cmd = parser.parse(options, args);
} catch (Exception e) {
System.err.println("ERROR: " + e.getMessage() + "\n");
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(NAME + " ", options, true);
System.exit(-1);
} return cmd;
} /**
* 主函数
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception
{
//将输入參数解析为CommandLine对象
Configuration conf = HBaseConfiguration.create();
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
CommandLine cmd = parseArgs(otherArgs); //取出各项參数
String tableName = cmd.getOptionValue("t");
String inputFileName = cmd.getOptionValue("i");
String columnName = cmd.getOptionValue("c");
conf.set("conf.column", columnName); Job job = new Job(conf, "Import from file " + inputFileName + " into table " + tableName);
job.setJarByClass(HdfsToHBase.class); //设置map和reduce类
job.setMapperClass(ImportMapper.class);
job.setNumReduceTasks(0); //设置map阶段输出的键值对类型
job.setOutputKeyClass(ImmutableBytesWritable.class);
job.setOutputValueClass(Writable.class); //设置job输入输出格式
job.setOutputFormatClass(TableOutputFormat.class);
job.getConfiguration().set(TableOutputFormat.OUTPUT_TABLE, tableName); //设置输入输出路径
FileInputFormat.addInputPath(job, new Path(inputFileName)); System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}

引入的jar文件包含:

这是在eclispe中开发的,放在默认的包以下,导出为普通的jar文件。

然后利用命令start-all.sh和start-hbase.sh分别启动hadoop和HBase。



(1)首先登陆HBase shell,创建一个仅仅包括一个列族的表



(2)然后将txt数据上传到HDFS上面(数据在HBase权威指南随书的源代码包中有)。



(3)然后运行job:

当中指定了main函数所在的类名,然后就各自是habse 表名,hdfs文件名称,hbase表的列名。

作业运行完毕之后能够到:http://localhost:50030/jobtracker.jsp 查看作业运行状态。

然后能够登陆hbase shell查看article表中有多少行数据,也能够用scan所有打印出来看。

2、将第一步存储的HBase表中的json字符串读取出来,解析存储到新的HBase表中,能够进行查询。

源代码:

/**
* @author 季义钦
* @date 2014-6
* @reference HBase权威指南 chapter7
*
*/
import java.io.IOException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.KeyValue;
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.IdentityTableReducer;
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.io.Writable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.util.GenericOptionsParser;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser; public class HBaseToHBase
{
private static final Log LOG = LogFactory.getLog(HBaseToHBase.class);
public static final String NAME = "HBaseToHBase";
public enum Counters { ROWS, COLS, ERROR, VALID } /**
* Map类
* 以HBase表作为输入,所以继承自TableMapper
*
*/
static class ParseMapper
extends TableMapper<ImmutableBytesWritable, Writable>
{
private JSONParser parser = new JSONParser();
private byte[] family = null; @Override
protected void setup(Context context) throws IOException, InterruptedException
{
family = Bytes.toBytes(context.getConfiguration().get("conf.family"));
} @Override
public void map(ImmutableBytesWritable rowKey, Result columns, Context context) throws IOException
{
String value = null; try
{
String author = "null";
Put put = new Put(rowKey.get()); //循环取得每一列(这里实际上仅仅有一列存储json字符串)
for(KeyValue kv:columns.list())
{
context.getCounter(Counters.COLS).increment(1);
value = Bytes.toStringBinary(kv.getValue()); //解析获取的json字符串
JSONObject json = (JSONObject)parser.parse(value);
for(Object key : json.keySet())
{
Object val = json.get(key);
if(key.equals("author"))
{
author = val.toString();
} put.add(family, Bytes.toBytes(key.toString()), Bytes.toBytes(val.toString()));
}
} //以解析到的author作为行键发射出去
context.write(new ImmutableBytesWritable(Bytes.toBytes(author)), put);
context.getCounter(Counters.VALID).increment(1);
LOG.info("存储作者 "+author+"的数据完毕!");
}catch(Exception e)
{
e.printStackTrace();
System.err.println("Error: " + e.getMessage() + ", Row: " +
Bytes.toStringBinary(rowKey.get()) + ", JSON: " + value);
context.getCounter(Counters.ERROR).increment(1);
}
}
} /**
* 解析命令行參数
* @param args
* @return
* @throws ParseException
*/
private static CommandLine parseArgs(String[] args) throws ParseException
{
Options options = new Options(); Option o = new Option("i", "input", true, "table to read from (must exist)");
o.setArgName("input-table-name");
o.setRequired(true);
options.addOption(o); o = new Option("ic", "column", true, "column to read data from (must exist)");
o.setArgName("family:qualifier");
o.setRequired(true);
options.addOption(o); o = new Option("o", "output", true, "table to write to (must exist)");
o.setArgName("output-table-name");
o.setRequired(true);
options.addOption(o); o = new Option("oc", "family", true, "cf to write data to (must exist)");
o.setArgName("family");
o.setRequired(true);
options.addOption(o); CommandLineParser parser = new PosixParser();
CommandLine cmd = null;
try
{
cmd = parser.parse(options, args);
}
catch (Exception e)
{
System.err.println("ERROR: " + e.getMessage() + "\n");
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(NAME + " ", options, true);
System.exit(-1);
}
return cmd;
} /**
* 主函数
* @param args
*/
public static void main(String[] args) throws Exception
{
Configuration conf = HBaseConfiguration.create();
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
CommandLine cmd = parseArgs(otherArgs); String inputTable = cmd.getOptionValue("i"); //HBase源表
String outputTable = cmd.getOptionValue("o"); //HBase目标表
String inputColumn = cmd.getOptionValue("ic"); //HBase源表的列名
String outputColumnFamily = cmd.getOptionValue("oc"); //HBase目标表的列族名
conf.set("conf.family", outputColumnFamily); //提供Scan实例指定要扫描的列
Scan scan = new Scan();
byte[][] colkey = KeyValue.parseColumn(Bytes.toBytes(inputColumn));
scan.addColumn(colkey[0], colkey[1]); Job job = new Job(conf, "Parse data in " + inputTable + ", write to " + outputTable);
job.setJarByClass(HBaseToHBase.class); //高速配置作业以HBase作为输入源和输出源
TableMapReduceUtil.initTableMapperJob(inputTable, scan, ParseMapper.class, ImmutableBytesWritable.class, Put.class, job);
TableMapReduceUtil.initTableReducerJob(outputTable, IdentityTableReducer.class, job); System.exit(job.waitForCompletion(true) ? 0 : 1);
} }

注意:

(1)以HBase表作为mapreduce作业的输入时,一方面要继承字TableMapper类,一方面须要提供一个scan实例,指定要扫描来作为输入的记录。

(2)当中配置的Reduce是IdentityTableReducer,其作用和IdentityTableMapper一样,仅仅是简单地将键值对传递到下一个阶段而已,没有什么实质性作用,它对于数据存储到HBase表中不是必须的,全然能够用另外一句话替代,即: setNumReduceTasks(0).

实际上作业运行的时候你应该也能够看到reduce一直是0%。



引入的jar文件包含:





(1)创建HBase表:



(2)导出jar包:

注意:里面引入了一个第三方的jar包,即simple json的jar包,用于解析json字符串。

simple json jar文件在这里下载:http://www.java2s.com/Code/Jar/j/Downloadjsonsimple111jar.htm

之前在一个站点下了一个山寨的,结果没有parse(string)这个接口,仅仅有parse(Reader)这个接口,将String转换成StringReader传进去结果作业老是报错,坑死了。

引入第三方jar包运行Mapreduce作业的时候会报出classnotFound的异常,解决方法有下面几种:

1.把要依赖的包部署到每台tasktracker上面

这种方法最简单,可是要部署到每台tasktracker,并且可能引起包污染的问题。比方应用A和应用B都用到同一个libray,可是版本号不同,就会出现冲突的问题。

2.把依赖的包和直接合并到mapreducejob的包

这种方法的问题是合并后的包可能很大,也不利于的包的升级

3.使用DistributedCache

这种方法就是先把这些包上传到HDFS,能够在程序启动的时候做一次。然后在submitjob的时候把hdfspath加到classpath里面。

演示样例:

$bin/hadoop fs -copyFromLocal ib/protobuf-java-2.0.3.jar/myapp/protobuf-java-2.0.3.jar //Setup the application's JobConf:JobConf job = new JobConf(); DistributedCache.addFileToClassPath(newPath("/myapp/protobuf-java-2.0.3.jar"),
job);

4,另一种情况是扩展包特别多的情况下用3就不爽了,參考一下:

《Hadoop权威指南》中也有关于jar打包的处理措施,查找之

【不论什么非独立的JAR文件都必须打包到JAR文件的lib文件夹中。(这与Java的webapplication
archive或WAR文件类似,不同的是,后者的JAR文件放在WEB-INF/lib子文件夹下的WAR文件里)】

我採用的是第四种方法,在project以下创建一个lib目录,将json-simple-1.1.1.jar放进去:

然后export:



(3)运行job:

OK了,以下就能够用hbase shell登陆,并用scan ‘authorTable’查看解析进去的数据了。

HBase概念学习(七)HBase与Mapreduce集成的更多相关文章

  1. HBase 与 MapReduce 集成

    6. HBase 与 MapReduce 集成 6.1 官方 HBase 与 MapReduce 集成 查看 HBase 的 MapReduce 任务的执行:bin/hbase mapredcp; 环 ...

  2. Hbase框架原理及相关的知识点理解、Hbase访问MapReduce、Hbase访问Java API、Hbase shell及Hbase性能优化总结

    转自:http://blog.csdn.net/zhongwen7710/article/details/39577431 本blog的内容包含: 第一部分:Hbase框架原理理解 第二部分:Hbas ...

  3. HBase概念学习(九)HTablePool为何弃用?

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/jiq408694711/article/details/36526433 转载请注明出处:jiq•钦 ...

  4. HBase学习——3.HBase表设计

    1.建表高级属性 建表过程中常用的shell命令 1.1 BLOOMFILTER 默认是 NONE 是否使用布隆过虑及使用何种方式,布隆过滤可以每列族单独启用 使用HColumnDescriptor. ...

  5. 大数据技术之_11_HBase学习_01_HBase 简介+HBase 安装+HBase Shell 操作+HBase 数据结构+HBase 原理

    第1章 HBase 简介1.1 什么是 HBase1.2 HBase 特点1.3 HBase 架构1.3 HBase 中的角色1.3.1 HMaster1.3.2 RegionServer1.3.3 ...

  6. HBase 实战(1)--HBase的数据导入方式

    前言: 作为Hadoop生态系统中重要的一员, HBase作为分布式列式存储, 在线实时处理的特性, 备受瞩目, 将来能在很多应用场景, 取代传统关系型数据库的江湖地位. 本篇博文重点讲解HBase的 ...

  7. 通过HBase Shell与HBase交互

    出处:http://www.taobaotest.com/blogs/1604 业务开发测试HBase之旅二:通过HBase Shell与HBase交互 yedu 发表于:2011-10-11 浏览: ...

  8. hive和hbase本质区别——hbase本质是OLTP的nosql DB,而hive是OLAP 底层是hdfs,需从已有数据库同步数据到hdfs;hive可以用hbase中的数据,通过hive表映射到hbase表

    对于hbase当前noSql数据库的一种,最常见的应用场景就是采集的网页数据的存储,由于是key-value型数据库,可以再扩展到各种key-value应用场景,如日志信息的存储,对于内容信息不需要完 ...

  9. 【转帖】HBase之五:hbase的region分区

    HBase之五:hbase的region分区 https://www.cnblogs.com/duanxz/p/3154487.html 一.Region 概念 Region是表获取和分布的基本元素, ...

随机推荐

  1. 通过Qt样式表定制程序外观(比较通俗易懂)

    1. 何为Qt样式表[喝小酒的网摘]http://blog.hehehehehe.cn/a/10270.htm2. 样式表语法基础3. 方箱模型4. 前景与背景5. 创建可缩放样式6. 控制大小7. ...

  2. 详解Spring

    Spring SSH框架中Struts2:是基于Web层,Hibernate:是基于持久化的,Spring:业务层,管理bean,它是一个容器,List,map, Set这里的内容,是适合已经学过了S ...

  3. Python用subprocess的Popen来调用系统命令

    当我们须要调用系统的命令的时候,最先考虑的os模块.用os.system()和os.popen()来进行操作.可是这两个命令过于简单,不能完毕一些复杂的操作,如给执行的命令提供输入或者读取命令的输出, ...

  4. linux下磁盘分区

    转自于:http://pengyl.blog.51cto.com/5591604/1193963 命令:fdisk 功能:查看磁盘使用情况和分割磁盘 使用方法:                一.在 ...

  5. if else配对问题

    else语句总是与离它最近的if语句配对,所以在if语句的嵌套中一定要注意else语句与哪个if语句匹配 #include <iostream> using namespace std; ...

  6. iOS开发之视图控制器(UIViewController)

    视图控制器应该在MVC设计模式中扮演控制层(C)的角色,UIViewController的职责对内管理与之关联的View,对外跟其他UIViewController通信和协调.一个视图控制器管理一个视 ...

  7. html5 学习笔记

    一.ie8及以下对html5相关语义标签的支持 <!-[if lt IE9]> <script src="html5.js"></script> ...

  8. jquery倒计时自动跳转

    刚开始我用下面这种方法一直报错,不知是什么原因,就是多加了页面加载时调用这个方法,还请高手看到后小小留言解惑

  9. (Problem 5)Smallest multiple

    2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any rema ...

  10. 登陆整合实现-QQ互联认证(ASP.NET版本)

    原文:登陆整合实现-QQ互联认证(ASP.NET版本) 首先 我们创建一个qq.ashx的页面,这个页面会跳转到QQ的请求界面 代码如下: QQSettingConfig qqSettingConfi ...