《HBase in Action》 第三章节的学习总结 ---- 如何编写和运行基于HBase的MapReduce程序
HBase之所以与Hadoop是最好的伙伴,我理解就因为两点:1.HADOOP的HDFS,为HBase提供了分布式的存储方式;2.HADOOP的MR为HBase提供的分布式的计算方法。u
其中第一点,主要是HBase在HDFS的支撑下,实现了HRegion来进行分布式的管理。HBase中除了我们定义的数据表格外,其自身还有两类表格:-ROOT-表和.META.表。在分布式的环境下,客户端定位到要访问的具体某行数据,需要依次通过:唯一的-ROOT-表,具体某个.META.表,具体某个RegionServer,具体某个Region,到具体的行。这部分的应用主要在于如何搭建分布式环境
接来下,这里就总结一下我对于基于HBase的MR程序的编写和运行的理解
1.准备工作
环境:CDH4.5,其中提供了hadoop-2.0.0-cdh4.5.0,hbase-0.94.6-cdh4.5.0。基于ubuntu12.04,搭建伪分布式环境
将hadoop和hbase解压缩后,除了常规的一系列xml文件定义外,还要让hadoop在执行MR时,能调用到HBase。为此,需要特别做的事情,如下:
A.定义环境 变量:export HADOOP_CLASSPATH=${HBASE_HOME}/hbase-0.94.6-cdh4.5.0-security.jar:${HBASE_HOME}/conf:${HBASE_HOME}/lib/zookeeper-3.4.5-cdh4.5.0.jar
B.将HBase里面的hbase-site.xml文件 拷贝到 CDH4Dev/hadoop/etc/hadoop 目录;
C.将HBase里面的hbase-0.94.6-cdh4.5.0-security.jar 拷贝到 CDH4Dev/hadoop/share/hadoop/common 目录;将HBase里面的 lib/zookeeper-3.4.5-cdh4.5.0.jar 拷贝到/home/hadoop/CDH4Dev/hadoop/share/hadoop/common 目录;
D.依次启动:start-dfs.sh; start-yarn.sh和start-hbase.sh
2. 编写基于HBase的MR程序
/**
* 基于HBase的Mapreduce处理
* 参考 http://www.cnblogs.com/liangzh/archive/2012/04/19/2457703.html
*/
package net.lagujw.hbase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
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.mapreduce.TableReducer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.mapreduce.Job;
/**
* @author hadoop
*
*/
public class HBasePracticeMR {
/**
* @param args
*/
//打印表信息
private static void showtableinfo(HTable table) {
Scan s = new Scan();
try {
ResultScanner sResult = table.getScanner(s);
for(Result rr : sResult) {
for(KeyValue kvrr:rr.raw()) {
System.out.println("rowkey is:" + Bytes.toString(kvrr.getRow()));
System.out.println("family is:" + Bytes.toString(kvrr.getFamily()));
System.out.println("qualify is:" + Bytes.toString(kvrr.getQualifier()));
System.out.println("timestamp is: " + kvrr.getTimestamp());
System.out.println("value is:" + Bytes.toString(kvrr.getValue()));
}
}
}catch (IOException e) {
System.out.println("in showtableinfo, error is " + e.toString());
}
}
//创建表
public static void create_intable(Configuration conf) {
try {
HBaseAdmin admin = new HBaseAdmin(conf);
/*创建一个表:blog*/
if(admin.tableExists("blog")) {
admin.disableTable("blog");
admin.deleteTable("blog");
}
HTableDescriptor tdesc = new HTableDescriptor("blog");
HColumnDescriptor cdesc1 = new HColumnDescriptor("article");
cdesc1.setMaxVersions(3);
tdesc.addFamily(cdesc1);
HColumnDescriptor cdesc2 = new HColumnDescriptor("author");
cdesc2.setMaxVersions(3);
tdesc.addFamily(cdesc2);
admin.createTable(tdesc);
//写批量数据
System.out.println("To add a lots !! \n");
HTable blogTable = new HTable(conf, "blog");
blogTable.setAutoFlush(false);
List<Put> puts = new ArrayList<Put>();
Put p1 = new Put(Bytes.toBytes("1"));
p1.add(Bytes.toBytes("article"), Bytes.toBytes("content"), Bytes.toBytes("HBase is the Hadoop database. Use it when you need random, realtime read/write access to your Big Data."));
p1.add(Bytes.toBytes("article"), Bytes.toBytes("tags"), Bytes.toBytes("Hadoop,HBase,NoSQL"));
p1.add(Bytes.toBytes("article"), Bytes.toBytes("title"), Bytes.toBytes("Head First HBase"));
p1.add(Bytes.toBytes("author"), Bytes.toBytes("name"), Bytes.toBytes("hujinjun"));
//p1.add(Bytes.toBytes("author"), Bytes.toBytes("nickname"), Bytes.toBytes("yedu"));
//todo 若同一个列存放多个cell,如何自动带上timestamp?如下的参数1或者2用于设置时间戳版本号,但是这样比较山寨
p1.add(Bytes.toBytes("author"), Bytes.toBytes("nickname"), 1, Bytes.toBytes("yedu"));
p1.add(Bytes.toBytes("author"), Bytes.toBytes("nickname"), 2, Bytes.toBytes("一叶渡江")); //带时间参数
Put p2 = new Put(Bytes.toBytes("10"));
p2.add(Bytes.toBytes("article"), Bytes.toBytes("tags"), Bytes.toBytes("Hadoop"));
p2.add(Bytes.toBytes("author"), Bytes.toBytes("nickname"), Bytes.toBytes("heyun"));
Put p3 = new Put(Bytes.toBytes("100"));
p3.add(Bytes.toBytes("article"), Bytes.toBytes("tags"), Bytes.toBytes("hbase,nosql"));
p3.add(Bytes.toBytes("author"), Bytes.toBytes("nickname"), Bytes.toBytes("shenxiu"));
puts.add(p1);
puts.add(p2);
puts.add(p3);
blogTable.put(puts);
blogTable.flushCommits();
showtableinfo(blogTable);
}catch (IOException e) {
System.out.println(e.toString());
}
}
public static void create_outtable(Configuration conf) {
try {
HBaseAdmin admin = new HBaseAdmin(conf);
/*创建一个空表:tag_friend;由于没有定义rowkey,则表在HDFS中实际是没有建立的*/
if(admin.tableExists("tag_friend")) {
admin.disableTable("tag_friend");
admin.deleteTable("tag_friend");
}
HTableDescriptor tdesc = new HTableDescriptor("tag_friend");
HColumnDescriptor cdesc = new HColumnDescriptor("person");
cdesc.setMaxVersions(3);
tdesc.addFamily(cdesc);
admin.createTable(tdesc);
showtableinfo(new HTable(conf, "tag_friend"));
}catch (IOException e) {
System.out.println(e.toString());
}
}
//自定义map任务
//这里只需要定义输出的key/value类型即可;默认的<输入key,value>类型是<ImmutableBytesWritable,Result>已经被TableMapper隐藏了--这和hadoop自己的MR不同
public static class Mymap extends TableMapper<ImmutableBytesWritable, ImmutableBytesWritable> {
//map方法的入参,包括输入的<key1,value1>和输出的上下文对象:Context
public void map(ImmutableBytesWritable row, Result values,
Context context) throws IOException,InterruptedException {
ImmutableBytesWritable value = null;
String[] tags = null;
//这里的values,就是Scan结果中的一行Result,也就是和map方法的入参:ImmutableBytesWritable row相对应的那一行的Scan结果
//这里的KeyValue kv就是此Result中的单一版本的结果值。Result里面的结果值是可以分版本的
for(KeyValue kv : values.raw()){
if("author".equals(Bytes.toString(kv.getFamily()))
&&"nickname".equals(Bytes.toString(kv.getQualifier()))){
value = new ImmutableBytesWritable(kv.getValue());
}
if("article".equals(Bytes.toString(kv.getFamily()))
&&"tags".equals(Bytes.toString(kv.getQualifier()))){
tags = Bytes.toString(kv.getValue()).toLowerCase().split(",");
}
}
for(int i=0;i<tags.length;i++){
ImmutableBytesWritable key = new ImmutableBytesWritable(Bytes.toBytes(tags[i]));
context.write(key, value); //设置map任务的输出
}
}
}
//自定义reduce任务
//这里只有KEYIN, VALUEIN, KEYOUT,没有定义valueOut,因为reduce的ValueOut一般都是Put或Delete(因为只有Put和Delete可以写到一个HTable中),所以ValueOutu也已经被TableMapper隐藏了--这和hadoop自己的MR不同
public static class Myreduce extends TableReducer<ImmutableBytesWritable,ImmutableBytesWritable,ImmutableBytesWritable> {
//reduce方法的入参,包括输入的<key2,value2链>和输出的上下文对象:Context
public void reduce(ImmutableBytesWritable key, Iterable<ImmutableBytesWritable>values,
Context context) throws IOException,InterruptedException {
String friends = "";
for(ImmutableBytesWritable val : values){
friends += (friends.length()>0?",":"") + Bytes.toString(val.get());
}
//定义一个用于写入HTable的Put对象
Put put = new Put(key.get()); //key的值就作为Rowkey了
put.add(Bytes.toBytes("person"),Bytes.toBytes("nicknames"), Bytes.toBytes(friends));
context.write(key, put); //Reduce的任务只要执行到:提供<Rowkey,Put>或者<RowKey,Delete>就可以了;Reduce机制本身会负责将此Put或Delete,按照Rowkey,写到对应的Region中
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Configuration conf = HBaseConfiguration.create();
//先把输入的表,创建出来,并填写内容
create_intable(conf);
//再把输出的表,创建好框架,但是不填写内容
create_outtable(conf);
Job myjob = new Job(conf, "HBaseMR");
myjob.setJarByClass(HBasePracticeMR.class);
//定义scan,用于控制输入给map的内容。Scan在MR中用处很大
Scan s = new Scan();
s.addColumn(Bytes.toBytes("article"), Bytes.toBytes("tags"));
s.addColumn(Bytes.toBytes("author"), Bytes.toBytes("nickname"));
s.setMaxVersions(); //增加扫描条件,获得所有版本
//初始化map任务
//“blog”:table名,用于指定从哪个table读取数据
//s:Scan实例,用于从指定的table中扫描得到map任务的输入数据
//Mymap.class:自定义的map类,这里就负责实际的map任务实现
//第一个ImmutableBytesWritable.class:指定outputkey的类型
//第二个ImmutableBytesWritable.class:指定outputvalue的类型
//myjob:代表此次MR的任务
TableMapReduceUtil.initTableMapperJob("blog", s, Mymap.class,
ImmutableBytesWritable.class, ImmutableBytesWritable.class, myjob);
//初始化Reduce任务
//“tag_friend”:table名,用于指定要往哪个table写入数据
//Myreduce.class:自定义的reduce类,这里就负责实际的reduce任务实现
//myjob:代表此次MR的任务
TableMapReduceUtil.initTableReducerJob("tag_friend", Myreduce.class, myjob);
System.exit(myjob.waitForCompletion(true)?0:1);
}catch (IOException e) {
System.out.println(e.toString());
}catch (ClassNotFoundException e) {
System.out.println(e.toString());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
System.out.println("func over!");
}
}
}
在Eclipse indigo 版本中,将此文件export成jar包后(选择export-JAR File即可):HBasePracticeMR.jar,然后运行:hadoop jar HBasePracticeMR.jar即可。
《HBase in Action》 第三章节的学习总结 ---- 如何编写和运行基于HBase的MapReduce程序的更多相关文章
- 《HBase in Action》 第二章节的学习总结 ---- HBase基本组成
准备工作:采用的HBase版本是:CDH4.5,其中的Hadoop版本是:hadoop-2.0.0-cdh4.5.0:HBase版本是:hbase-0.94.6-cdh4.5.0: Hbase的配置文 ...
- 《HBase in Action》 第一章节的学习总结 ---- HBase是个啥
1.HBase模仿了Google的BigTable,是一种开源的,面向列族的数据库.它基于行键(rowkey),列键(column key)和时间戳(TimeStamp)来建立索引.HBase是建立在 ...
- Hadoop学习历程(四、运行一个真正的MapReduce程序)
上次的程序只是操作文件系统,本次运行一个真正的MapReduce程序. 运行的是官方提供的例子程序wordcount,这个例子类似其他程序的hello world. 1. 首先确认启动的正常:运行 s ...
- 《Lucene in Action 第二版》第三章节的学习总结----IndexSearcher以及Term和QueryParser
本章节告诉我们怎么用搜索.通过这章节的学习,虽然搜索的内部原理不清楚,但是至少应该学会简单的编写搜索程序了本章节,需要掌握如下几个主要API1.IndexSearcher类:搜索索引的门户,发起者. ...
- HBase in Action前三章笔记
近期接触HBase,看了HBase In Action的英文版.開始认为还行,做了些笔记.可是兴许看下去,越来越感觉到实战这本书比較偏使用上的细节,对于HBase的具体设计涉及得很少.把前三章的一些笔 ...
- 《TomCat与Java Web开发技术详解》(第二版) 第三章节的学习总结--利用Context元素来自定义web应用的存储位置
在学习完第三章后(第三章提供的web应用是helloaapp,我将其放到了tomcat/webapps中),对Context元素的作用理解不深:但是当进入第四章后,发现第四章提供的源码包中也有一个叫h ...
- 一种基于HBase韵海量图片存储技术
针对海量图片存储,已有若干个基于Hadoop的方案被设计出来.这些方案在系统层小文件合并.全局名字空间以及通用性方面存在不足.本文基于HBase提出了一种海量图片存储技术,成功解决了上述问题.本文将介 ...
- 《Lucene in Action》(第二版) 第二章节的学习总结 ---- IndexWriter+Document+Field
这一章节的学习,主要是学会如何创建索引,使用索引 一.创建索引 1.从原始文件中提取内容.这里的文件,可以是文本文件,也可以是二进制文件.文本文件(txt),lucene可以直接处理:而二进制文件(w ...
- 《Lucene in Action》(第二版) 第一章节的学习总结 ---- 用最少的代码创建索引和搜索
第一章节是介绍性质,但是通过这一章节的学习,我理解到如下概念: 1.Lucene由两部分组成:索引和搜索.索引是通过对原始数据的解析,形成索引的过程:而搜索则是针对用户输入的查找要求,从索引中找到匹配 ...
随机推荐
- Trapping Rain Water (Bar Height) -- LeetCode
Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...
- Linux下进行Web服务器压力(并发)测试工具http_load、webbench、ab、Siege、autobench简单使用教程(转)
一.http_load 程序非常小,解压后也不到100K http_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工 具,它可以以一个单一的进程运行,一般 ...
- 我学MSMQ(二)
上次我主要学习的是MSMQ的基本的概念.安装消息队列和新建了一个简单的队列. 现在我就继续学习关于消息队列的接收先还是概念 消息的接收又分成同步和异步方式两种,同步接收在 ...
- MySQL索引,如何正确创建MySQL索引?
索引可以提高数据的检索效率,也可以降低数据库的IO成本,并且索引还可以降低数据库的排序成本.排序分组操作主要消耗的就是CPU资源和内存,所以能够在排序分组操作中好好的利用索引将会极大地降低CPU资源的 ...
- [置顶]
docker web-GUI DockerUI和Shipyard对比
DockerUI和Shipyard对比 相似 基于Docker API,提供等同Docker命令行的大部分功能,支持container管理,image管理. web页面查看和管理容器和镜像,均能批量管 ...
- 使用Intent调用内置应用程序
布局代码如下: <?xml version="1.0" encoding="utf-8" ?> <LinearLayout xmlns:and ...
- 遨游maxthon打开页面一片黑色,百度地图等黑屏解决办法
遨游maxthon使用webkit极速核心,打开百度地图等页面一片黑色,黑屏了. 找了好久,不知道什么问题. 版本一样,都是4.4.xxx版本.另外一台机器又正常. 后来上傲游社区,好多人也有这个问题 ...
- 转: android 实现效果特效
一. 各种控件效果 http://www.jcodecraeer.com/plus/list.php?tid=31&TotalResult=990&PageNo=7
- 基于WPF系统框架设计(2)-Fluent Ribbon之HelloWorld
Fluent/Ribbon是微软在其最新桌面操作系统Windows 7中使用的图形用户界面. Windows平台的进化,伴随着系统图形界面的重新设计.从Windows XP到Windows Vista ...
- 《深入理解Android 卷III》第七章 深入理解SystemUI
<深入理解Android 卷III>即将公布,作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白,即Android Framework中和UI相关的部分. ...