`

Hbase相关

阅读更多

博主最近onsite在华为那边,写的是Hbase及Spark

 

发些相关文章

 

1、搭建环境

部署节点操作系统为CentOS,防火墙和SElinux禁用,创建了一个shiyanlou用户并在系统根目录下创建/app目录,用于存放Hadoop等组件运行包。因为该目录用于安装hadoop等组件程序,用户对shiyanlou必须赋予rwx权限(一般做法是root用户在根目录下创建/app目录,并修改该目录拥有者为shiyanlou(chown –R shiyanlou:shiyanlou /app)。

Hadoop搭建环境:

l 虚拟机操作系统: CentOS6.6 64位,单核,1G内存

l JDK:1.7.0_55 64位

l Hadoop:1.1.2

2、HBase介绍

HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。

HBase是Google Bigtable的开源实现,类似Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MapReduce来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用 Chubby作为协同服务,HBase利用Zookeeper作为对应来源:北京oracle培训

 

<iframe id="iframe_0.9898827413666083" style="border-width: initial; border-style: none; width: 394px; height: 284px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300215713.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.9898827413666083',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

上图描述了Hadoop EcoSystem中的各层系统,其中HBase位于结构化存储层,Hadoop HDFS为HBase提供了高可靠性的底层存储支持,Hadoop MapReduce为HBase提供了高性能的计算能力,Zookeeper为HBase提供了稳定服务和failover机制。

此外,Pig和Hive还为HBase提供了高层语言支持,使得在HBase上进行数据统计处理变的非常简单。 Sqoop则为HBase提供了方便的RDBMS数据导入功能,使得传统数据库数据向HBase中迁移变的非常方便。

2.1 HBase访问接口

1. Native Java API,最常规和高效的访问方式,适合Hadoop MapReduce Job并行批处理HBase表数据

2. HBase Shell,HBase的命令行工具,最简单的接口,适合HBase管理使用

3. Thrift Gateway,利用Thrift序列化技术,支持C++,PHP,Python等多种语言,适合其他异构系统在线访问HBase表数据

4. REST Gateway,支持REST 风格的Http API访问HBase, 解除了语言限制

5. Pig,可以使用Pig Latin流式编程语言来操作HBase中的数据,和Hive类似,本质最终也是编译成MapReduce Job来处理HBase表数据,适合做数据统计

6. Hive,当前Hive的Release版本尚没有加入对HBase的支持,但在下一个版本Hive 0.7.0中将会支持HBase,可以使用类似SQL语言来访问HBase

2.2 HBase数据模型

2.2.1 Table & Column Family

 

<iframe id="iframe_0.38094912719234" style="border-width: initial; border-style: none; width: 650px; height: 268px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300216649.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.38094912719234',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

l Row Key: 行键,Table的主键,Table中的记录按照Row Key排序

l Timestamp: 时间戳,每次数据操作对应的时间戳,可以看作是数据的version number

l Column Family:列簇,Table在水平方向有一个或者多个Column Family组成,一个Column Family中可以由任意多个Column组成,即Column Family支持动态扩展,无需预先定义Column的数量以及类型,所有Column均以二进制格式存储,用户需要自行进行类型转换。

2.2.2 Table & Region

当Table随着记录数不断增加而变大后,会逐渐分裂成多份splits,成为regions,一个region由[startkey,endkey)表示,不同的region会被Master分配给相应的RegionServer进行管理:

 

<iframe id="iframe_0.6313588330323459" style="border-width: initial; border-style: none; width: 324px; height: 285px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300217491.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.6313588330323459',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

-ROOT- && .META. Table

HBase中有两张特殊的Table,-ROOT-和.META.

l .META.:记录了用户表的Region信息,.META.可以有多个regoin

l -ROOT-:记录了.META.表的Region信息,-ROOT-只有一个region

l Zookeeper中记录了-ROOT-表的location

Client访问用户数据之前需要首先访问zookeeper,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,中间需要多次网络操作,不过client端会做cache缓存。

2.2.3 MapReduce on HBase

在HBase系统上运行批处理运算,最方便和实用的模型依然是MapReduce,如下图:

 

<iframe id="iframe_0.7565154202671747" style="border-width: initial; border-style: none; width: 554px; height: 277px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300218262.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.7565154202671747',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

HBase Table和Region的关系,比较类似HDFS File和Block的关系,HBase提供了配套的TableInputFormat和TableOutputFormat API,可以方便的将HBase Table作为Hadoop MapReduce的Source和Sink,对于MapReduce Job应用开发人员来说,基本不需要关注HBase系统自身的细节。

2.3 HBase系统架构

 

<iframe id="iframe_0.2866335160998794" style="border-width: initial; border-style: none; width: 603px; height: 389px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300219246.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.2866335160998794',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

2.3.1 Client

HBase Client使用HBase的RPC机制与HMaster和HRegionServer进行通信,对于管理类操作,Client与HMaster进行RPC;对于数据读写类操作,Client与HRegionServer进行RPC

2.3.2 Zookeeper

Zookeeper Quorum中除了存储了-ROOT-表的地址和HMaster的地址,HRegionServer也会把自己以Ephemeral方式注册到 Zookeeper中,使得HMaster可以随时感知到各个HRegionServer的健康状态。此外,Zookeeper也避免了HMaster的 单点问题,见下文描述

2.3.3 HMaster

HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行,HMaster在功能上主要负责Table和Region的管理工作:

1. 管理用户对Table的增、删、改、查操作

2. 管理HRegionServer的负载均衡,调整Region分布

3. 在Region Split后,负责新Region的分配

4. 在HRegionServer停机后,负责失效HRegionServer 上的Regions迁移

2.3.4 HRegionServer

HRegionServer主要负责响应用户I/O请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。

 

<iframe id="iframe_0.4490337319015001" style="border-width: initial; border-style: none; width: 553px; height: 347px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300220047.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.4490337319015001',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个 Region,HRegion中由多个HStore组成。每个HStore对应了Table中的一个Column Family的存储,可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。

HStore存储是HBase存储的核心了,其中由两部分组成,一部分是MemStore,一部分是StoreFiles。 MemStore是Sorted Memory Buffer,用户写入的数据首先会放入MemStore,当MemStore满了以后会Flush成一个StoreFile(底层实现是HFile), 当StoreFile文件数量增长到一定阈值,会触发Compact合并操作,将多个StoreFiles合并成一个StoreFile,合并过程中会进 行版本合并和数据删除,因此可以看出HBase其实只有增加数据,所有的更新和删除操作都是在后续的compact过程中进行的,这使得用户的写操作只要 进入内存中就可以立即返回,保证了HBase I/O的高性能。当StoreFiles Compact后,会逐步形成越来越大的StoreFile,当单个StoreFile大小超过一定阈值后,会触发Split操作,同时把当前 Region Split成2个Region,父Region会下线,新Split出的2个孩子Region会被HMaster分配到相应的HRegionServer 上,使得原先1个Region的压力得以分流到2个Region上。下图描述了Compaction和Split的过程:

 

<iframe id="iframe_0.38444134244702166" style="border-width: initial; border-style: none; width: 554px; height: 119px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300221053.gif?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.38444134244702166',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

在理解了上述HStore的基本原理后,还必须了解一下HLog的功能,因为上述的HStore在系统正常工作的前提下是没有问 题的,但是在分布式系统环境中,无法避免系统出错或者宕机,因此一旦HRegionServer意外退出,MemStore中的内存数据将会丢失,这就需要引入HLog了。每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中(HLog文件格式见后续),HLog文件定期会滚动出新的,并 删除旧的文件(已持久化到StoreFile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper感知 到,HMaster首先会处理遗留的 HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应region的目录下,然后再将失效的region重新分配,领取 到这些region的HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。

2.4 HBase存储格式

HBase中的所有数据文件都存储在Hadoop HDFS文件系统上,主要包括上述提出的两种文件类型:

1.HFile, HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile

2.HLog File,HBase中WAL(Write Ahead Log) 的存储格式,物理上是Hadoop的Sequence File

2.4.1 HFile

下图是HFile的存储格式:

 

<iframe id="iframe_0.38704544564846" style="border-width: initial; border-style: none; width: 554px; height: 160px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300222138.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.38704544564846',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

首先HFile文件是不定长的,长度固定的只有其中的两块:Trailer和FileInfo。正如图中所示的,Trailer 中有指针指向其他数据块的起始点。File Info中记录了文件的一些Meta信息,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。Data Index和Meta Index块记录了每个Data块和Meta块的起始点。

Data Block是HBase I/O的基本单元,为了提高效率,HRegionServer中有基于LRU的Block Cache机制。每个Data块的大小可以在创建一个Table的时候通过参数指定,大号的Block有利于顺序Scan,小号Block利于随机查询。 每个Data块除了开头的Magic以外就是一个个KeyValue对拼接而成, Magic内容就是一些随机数字,目的是防止数据损坏。后面会详细介绍每个KeyValue对的内部构造。

HFile里面的每个KeyValue对就是一个简单的byte数组。但是这个byte数组里面包含了很多项,并且有固定的结构。我们来看看里面的具体结构:

 

<iframe id="iframe_0.9915630809212412" style="border-width: initial; border-style: none; width: 553px; height: 93px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300223068.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.9915630809212412',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

开始是两个固定长度的数值,分别表示Key的长度和Value的长度。紧接着是Key,开始是固定长度的数值,表示RowKey 的长度,紧接着是RowKey,然后是固定长度的数值,表示Family的长度,然后是Family,接着是Qualifier,然后是两个固定长度的数 值,表示Time Stamp和Key Type(Put/Delete)。Value部分没有这么复杂的结构,就是纯粹的二进制数据了。

2.4.2 HLogFile

 

<iframe id="iframe_0.1692523284900096" style="border-width: initial; border-style: none; width: 553px; height: 350px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300223880.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.1692523284900096',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

上图中示意了HLog文件的结构,其实HLog文件就是一个普通的Hadoop Sequence File,Sequence File 的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括 sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。

HLog Sequece File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue,可参见上文描述。

3、安装部署HBase

3.1 安装过程

3.1.1 下载HBase安装包

从Apache网站上(hbase.apache.org)下载HBase稳定发布包:

http://mirrors.cnnic.cn/apache/hbase/hbase-0.96.2/

 

<iframe id="iframe_0.17599606656193556" style="border-width: initial; border-style: none; width: 665px; height: 309px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300224604.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.17599606656193556',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

也可以在/home/shiyanlou/install-pack目录中找到该安装包,解压该安装包并把该安装包复制到/app目录中

cd /home/shiyanlou/install-pack

tar -zxf hbase-0.96.2-hadoop1-bin.tar.gz

mv hbase-0.96.2-hadoop1 /app/hbase-0.96.2

 

<iframe id="iframe_0.7286737321366736" style="border-width: initial; border-style: none; width: 663px; height: 167px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300225421.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.7286737321366736',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

3.1.2 设置环境变量

1. 使用sudo vi /etc/profile命令修改系统环境变量

export HBASE_HOME=/app/hbase-0.96.2

export PATH=$PATH:$HBASE_HOME/bin

 

<iframe id="iframe_0.987317928401529" style="border-width: initial; border-style: none; width: 663px; height: 85px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300226489.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.987317928401529',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

2. 使环境变量生效并验证环境变量生效

source /etc/profile

hbase version

 

<iframe id="iframe_0.9241358372263595" style="border-width: initial; border-style: none; width: 663px; height: 101px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300227235.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.9241358372263595',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

3.1.3 编辑hbase-env.sh

1. 打开hbase-env.sh文件

cd /app/hbase-0.96.2/conf

sudo vi hbase-env.sh

2. 修改该文件配置

#Java环境

export JAVA_HOME=/app/lib/jdk1.7.0_55

#通过hadoop的配置文件找到hadoop集群

export HBASE_CLASSPATH=/app/hadoop-1.1.2/conf

#使用HBASE自带的zookeeper管理集群

export HBASE_MANAGES_ZK=true

 

<iframe id="iframe_0.9101723378292395" style="border-width: initial; border-style: none; width: 663px; height: 99px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300229489.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.9101723378292395',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

 

<iframe id="iframe_0.40181545965225807" style="border-width: initial; border-style: none; width: 663px; height: 88px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300230382.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.40181545965225807',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

3.1.4 编辑hbase-site.xml

1. 打开hbase-site.xml配置文件

cd /app/hbase-0.96.2/conf

sudo vi hbase-site.xml

2. 配置hbase-site.xml文件

hbase.rootdir

hdfs://hadoop:9000/hbase

hbase.cluster.distributed

true

hbase.zookeeper.quorum

b393a04554e1

 

<iframe id="iframe_0.0933640692262927" style="border-width: initial; border-style: none; width: 663px; height: 164px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300231112.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.0933640692262927',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

3.2 启动并验证

3.2.1 启动HBase

通过如下命令启动Hbase

cd /app/hbase-0.96.2/bin

./start-hbase.sh

 

<iframe id="iframe_0.4786900479075886" style="border-width: initial; border-style: none; width: 663px; height: 96px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300231909.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.4786900479075886',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

3.2.2 验证启动

1. 在hadoop节点使用jps查看节点状态

 

<iframe id="iframe_0.2073254804510405" style="border-width: initial; border-style: none; width: 663px; height: 128px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300232795.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.2073254804510405',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

2. 进入hbase的shell命令行,创建表member并进行查看

hbase shell

hbase>create 'member', 'm_id', 'address', 'info'

 

<iframe id="iframe_0.2868974878086705" style="border-width: initial; border-style: none; width: 663px; height: 365px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.cuug.com.cn/uploadfile/2016-06/12300233549.jpg?_=5665780%22%20style=%22border:none;max-width:1571px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.2868974878086705',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

 

***********************************************************分割**********************************************************

 

概述

 

对于建表,和RDBMS类似,HBase也有namespace的概念,可以指定表空间创建表,也可以直接创建表,进入default表空间。

 

对于数据操作,HBase支持四类主要的数据操作,分别是:

 

  • Put :增加一行,修改一行;

  • Delete :删除一行,删除指定列族,删除指定column的多个版本,删除指定column的制定版本等;

  • Get :获取指定行的所有信息,获取指定行和指定列族的所有colunm,获取指定column,获取指定column的几个版本, 获取指定column的指定版本等;
  • Scan :获取所有行,获取指定行键范围的行,获取从某行开始的几行,获取满足过滤条件的行等。

 

这四个类都是 org.apache.hadoop.hbase.client的子类,可以到官网API去查看详细信息,本文仅总结常用方法,力争让读者用20%的时间掌握80%的常用功能。

 


目录

 

1.命名空间Namespace

 

2.创建表

 

3.删除表

 

4.修改表

 

5.新增、更新数据Put

 

6.删除数据Delete

 

7.获取单行Get

 

8.获取多行Scan

 


 

1. 命名空间Namespace

在关系数据库系统中,命名空间

namespace指的是一个 表的逻辑分组 ,同一组中的表有类似的用途。命名空间的概念为 即将到来 的多租户特性打下基础:

  • 配额管理( Quota Management (HBASE-8410)):限制一个namespace可以使用的资源,资源包括region和table等;
  • 命名空间安全管理( Namespace Security Administration (HBASE-9206)):提供了另一个层面的多租户安全管理;
  • Region服务器组(Region server groups (HBASE-6721)):一个命名空间或一张表,可以被固定到一组regionservers上,从而保证了数据隔离性。

1.1.命名空间管理

命名空间可以被创建、移除、修改。

表和命名空间的隶属关系 在在创建表时决定,通过以下格式指定:

<namespace>:<table>

Example:hbase shell中创建命名空间、创建命名空间中的表、移除命名空间、修改命名空间

#Create a namespace
create_namespace 'my_ns'
            
#create my_table in my_ns namespace
create 'my_ns:my_table', 'fam'
          
#drop namespace
drop_namespace 'my_ns'
          
#alter namespace
alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
        

1.2. 预定义的命名空间

有两个系统内置的预定义命名空间:

  • hbase :系统命名空间,用于包含hbase的内部表
  • default : 所有未指定命名空间的表都自动进入该命名空间

Example:指定命名空间和默认命名空间

#namespace=foo and table qualifier=bar
create 'foo:bar', 'fam'

#namespace=default and table qualifier=bar
create 'bar', 'fam'

2.创建表

 

废话不多说,直接上样板代码,代码后再说明注意事项和知识点:

 

        Configuration conf = HBaseConfiguration. create ();

        HBaseAdmin admin =  new  HBaseAdmin(conf);

         //create  namespace  named "my_ns"

        admin.createNamespace(NamespaceDescriptor. create ( "my_ns" ).build());

        

         //create tableDesc, with  namespace  name "my_ns" and table name " mytable "

        HTableDescriptor tableDesc =  new  HTableDescriptor(TableName. valueOf ( "my_ns:mytable" ));

         tableDesc.setDurability(Durability. SYNC_WAL );

         //add a column family " mycf "

        HColumnDescriptor hcd =  new  HColumnDescriptor( "mycf" );

        tableDesc.addFamily(hcd);

        admin.createTable(tableDesc);

 

        admin.close();

  

 

关键知识点:

 

  1. 必须将HBase集群的hbase-site.xml文件添加进工程的classpath中,否则Configuration conf = HBaseConfiguration. create () 代码获取不到需要的集群相关信息,也就无法找到集群,运行程序时会报错;
  2. HTableDescriptor tableDesc =  new  HTableDescriptor(TableName. valueOf ( "my_ns:mytable" )) 代码是描述表mytable,并将mytable放到了my_ns命名空间中,前提是该命名空间已存在,如果指定的是不存在命名空间,则会报 错 org.apache.hadoop.hbase.NamespaceNotFoundException;
  3. 命名空间一般在建模阶段通过命令行创建,在java代码中通过 admin.createNamespace(NamespaceDescriptor. create ( "my_ns" ).build()) 创建的机会不多;
  4. 创建 HBaseAdmin 对象时就已经建立了客户端程序与HBase集群的connection ,所以在程序执行完成后,务必通过 admin.close() 关闭connection;
  5. 可以通过 HTableDescriptor 对象设置 表的特性 ,比如: 通过 tableDesc.setMaxFileSize(512) 设置一个region中的store文件的最大size,当一个region中的最大store文件达到这个size时,region就开始分裂; 通过tableDesc.setMemStoreFlushSize(512) 设置region内存中的memstore的最大值,当memstore达到这个值时,开始往磁盘中刷数据。 更多特性请自行查阅官网API;
  6. 可以通过 HColumnDescriptor 对象设置 列族的特性 ,比如:通过 hcd.setTimeToLive(5184000) 设置数据保存的最长时间;通过 hcd.setInMemory( true ) 设置数据保存在内存中以提高响应速度;通过   hcd .setMaxVersions(10) 设置数据保存的最大版本数;通过 hcd.setMinVersions(5) 设置数据保存的最小版本数(配合TimeToLive使用)。更多特性请自行查阅官网API;
  7. 数据的版本数只能通过 HColumnDescriptor 对象设置,不能通过 HTableDescriptor 对象设置;
  8. 由于HBase的数据是先写入内存,数据累计达到内存阀值时才往磁盘中flush数据,所以,如果在数据还没有flush进硬盘 时,regionserver down掉了,内存中的数据将丢失。要想解决这个场景的问题就需要用到WAL(Write-Ahead-Log), tableDesc.setDurability(Durability. SYNC_WAL ) 就是设置写WAL日志的级别,示例中设置的是同步写WAL,该方式安全性较高,但无疑会一定程度影响性能,请根据具体场景选择使用;
  9. setDurability (Durability d)方法可以在相关的三个对象中使用,分别是: HTableDescriptor, Delete,Put(其中Delete和Put的该方法都是继承自父类 org.apache.hadoop.hbase.client.Mutation) 。分别针对表、插入操作、删除操作设定WAL日志写入级别。需要注意的是, Delete和Put并不会继承Table的Durability级别(已实测验证) 。Durability是一个枚举变量,可选值参见4.2节。如果不通过该方法指定WAL日志级别,则为 默认 USE_DEFAULT 级别。

3.删除表

删除表没创建表那么多学问,直接上代码:

        Configuration conf = HBaseConfiguration. create ();

        HBaseAdmin admin =  new  HBaseAdmin(conf);

        String tablename =  "my_ns:mytable" ;

         if (admin.tableExists(tablename)) {

             try  {

                admin.disableTable(tablename);

                admin.deleteTable(tablename);

            }  catch  (Exception e) {

                 //  TODO : handle exception

                e.printStackTrace();

            }

        }

 

        admin.close();

  

说明 :删除表前必须先disable表。


4.修改表

4.1.实例代码

(1)删除列族、新增列族

修改之前,四个列族:

hbase(main):014:0> describe 'rd_ns:itable'

DESCRIPTION                                                                                                        ENABLED

'rd_ns:itable', {NAME => ' info ', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', V true

ERSIONS => '10', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false',

BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => ' newcf ', DATA_BLOCK_ENCODING => 'NONE

', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647',

MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'tr

ue'}, {NAME => ' note ', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS =>

'10', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE

=> '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => ' sysinfo ', DATA_BLOCK_ENCODING => 'NONE', BLOOM

FILTER => 'ROW', REPLICATION_SCOPE => '0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647', MIN_VERS

IONS => '0', KEEP_DELETED_CELLS => 'true', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}

1 row(s) in 0.0450 seconds

修改表,删除三个列族,新增一个列族,代码如下:

        Configuration conf = HBaseConfiguration. create ();

        HBaseAdmin admin =  new  HBaseAdmin(conf);

        String tablename =  "rd_ns:itable" ;

         if (admin.tableExists(tablename)) {

             try  {

                admin.disableTable(tablename);

                 //get the TableDescriptor of target table

                HTableDescriptor newtd =  admin.getTableDescriptor (Bytes. toBytes ( "rd_ns:itable" ));

                

                 //remove 3 useless column families

                newtd.removeFamily(Bytes. toBytes ( "note" ));

                newtd.removeFamily(Bytes. toBytes ( "newcf" ));

                newtd.removeFamily(Bytes. toBytes ( "sysinfo" ));

                

                 //create HColumnDescriptor for new column family

                HColumnDescriptor newhcd =  new  HColumnDescriptor( "action_log" );

                newhcd.setMaxVersions(10);

                newhcd.setKeepDeletedCells( true );

                

                 //add the new column family(HColumnDescriptor) to HTableDescriptor

                newtd.addFamily(newhcd);

                

                 //modify target table  struture

                admin. modifyTable (Bytes. toBytes ( "rd_ns:itable" ),newtd);

                

                admin.enableTable(tablename);

            }  catch  (Exception e) {

                 //  TODO : handle exception

                e.printStackTrace();

            }

        }

 

        admin.close();

  

修改之后:

hbase(main):015:0> describe 'rd_ns:itable'

DESCRIPTION                                                                                                        ENABLED

'rd_ns:itable', {NAME => ' action_log ', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE =>  true

'0', COMPRESSION => 'NONE', VERSIONS => '10', TTL => '2147483647', MIN_VERSIONS => '0', KEEP_DELETED_CELLS => 'tr

ue', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'}, {NAME => ' info ', DATA_BLOCK_ENCODING => '

NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '10', COMPRESSION => 'NONE', MIN_VERSIONS => '

0', TTL => '2147483647', KEEP_DELETED_CELLS => 'false', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE =>

'true'}

1 row(s) in 0.0400 seconds

逻辑很简单:

  1. 通过 admin.getTableDescriptor (Bytes. toBytes ( "rd_ns:itable" )) 取得目标表的描述对象,应该就是取得指向该对象的指针了;
  2. 修改目标表描述对象;
  3. 通过 admin. modifyTable (Bytes. toBytes ( "rd_ns:itable" ),newtd) 将修改后的描述对象应用到目标表。

(2)修改现有列族的属性(setMaxVersions)

 

        Configuration conf = HBaseConfiguration. create ();

        HBaseAdmin admin =  new  HBaseAdmin(conf);

        String tablename =  "rd_ns:itable" ;

         if (admin.tableExists(tablename)) {

             try  {

                admin.disableTable(tablename);

                 //get the TableDescriptor of target table

                HTableDescriptor htd = admin.getTableDescriptor(Bytes. toBytes ( "rd_ns:itable" ));

                HColumnDescriptor infocf = htd.getFamily(Bytes. toBytes ( "info" ));

                infocf.setMaxVersions(100);

                 //modify target table  struture

                admin.modifyTable(Bytes. toBytes ( "rd_ns:itable" ),htd);

                admin.enableTable(tablename);

            }  catch  (Exception e) {

                 //  TODO : handle exception

                e.printStackTrace();

            }

        }

 

        admin.close();

  

 


 

5.新增、更新数据Put

5.1.常用构造函数:

(1)指定行键

public Put(byte[] row)

参数: row 行键

(2)指定行键和时间戳

public Put(byte[] row, long ts)

参数: row 行键, ts 时间戳

(3)从目标字符串中提取子串,作为行键

Put(byte[] rowArray, int rowOffset, int rowLength)

(4)从目标字符串中提取子串,作为行键,并加上时间戳

Put(byte[] rowArray, int rowOffset, int rowLength, long ts)

5.2.常用方法:

(1)指定 列族、限定符 ,添加值

add(byte[] family, byte[] qualifier, byte[] value)

(2)指定 列族、限定符、时间戳 ,添加值

add(byte[] family, byte[] qualifier, long ts, byte[] value)

(3) 设置写WAL (Write-Ahead-Log)的级别

public void setDurability(Durability d)

参数是一个枚举值,可以有以下几种选择:

  • ASYNC_WAL : 当数据变动时,异步写WAL日志

  • SYNC_WAL : 当数据变动时,同步写WAL日志

  • FSYNC_WAL : 当数据变动时,同步写WAL日志,并且,强制将数据写入磁盘

  • SKIP_WAL : 不写WAL日志

  • USE_DEFAULT : 使用HBase全局默认的WAL写入级别,即 SYNC_WAL

5.3.实例代码

(1)插入行

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        Put put =  new  Put(Bytes. toBytes ( "100001" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ), Bytes. toBytes ( "lion" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ), Bytes. toBytes ( "shangdi" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "age" ), Bytes. toBytes ( "30" ));

 

        put.setDurability(Durability. SYNC_WAL );

  

        table.put(put);

 

        table.close();

  

(2)更新行

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        

        Put put =  new  Put(Bytes. toBytes ( "100001" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ), Bytes. toBytes ( "lee" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ), Bytes. toBytes ( "longze" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "age" ), Bytes. toBytes ( "31" ));

 

        put.setDurability(Durability. SYNC_WAL );

  

        table.put(put);         

 

        table.close();

  
注意:
  1. Put的构造函数都需要指定行键,如果是全新的行键,则新增一行;如果是已有的行键,则更新现有行。

  2. 创建Put对象及put.add过程都是在构建一行的数据,创建Put对象时相当于创建了行对象,add的过程就是往目标行里添加cell,直到table.put才将数据插入表格;
  3. 以上代码创建Put对象用的是构造函数1,也可用构造函数2,第二个参数是时间戳;
  4. Put还有别的构造函数,请查阅官网API。

(3) 从目标字符串中提取子串,作为行键,构建Put

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        

        Put put =  new  Put(Bytes. toBytes ( "100001_100002" ),7,6);

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ), Bytes. toBytes ( "show" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ), Bytes. toBytes ( "caofang" ));

        put.add(Bytes. toBytes ( "info" ), Bytes. toBytes ( "age" ), Bytes. toBytes ( "30" ));

        

        table.put(put);

 

        table.close();

  

注意,关于: Put put =  new  Put(Bytes. toBytes ( "100001_100002" ),7,6)

  1. 第二个参数是偏移量,也就是行键从第一个参数的第几个字符开始截取;
  2. 第三个参数是截取长度;
  3. 这个代码实际是从 100001_100002 中截取了100002子串作为目标行的行键。

6.删除数据Delete

Delete类用于删除表中的一行数据,通过HTable.delete来执行该动作。

在执行Delete操作时,HBase并不会立即删除数据,而是对需要删除的数据打上一个“墓碑”标记,直到当Storefile合并时,再清除这些被标记上“墓碑”的数据。

如果希望删除整行,用行键来初始化一个Delete对象即可。如果希望进一步定义删除的具体内容,可以使用以下这些Delete对象的方法:

  • 为了删除指定的列族,可以使用 deleteFamily
  • 为了删除指定列的多个版本,可以使用 deleteColumns
  • 为了删除指定列的 指定版本 ,可以使用 deleteColumn,这样的话就只会删除版本号(时间戳)与指定版本相同的列。如果不指定时间戳,默认只删除最新的版本

下面详细说明构造函数和常用方法:

6.1.构造函数

(1)指定要删除的行键

Delete(byte[] row)

删除行键指定行的数据。

如果没有进一步的操作,使用该构造函数将删除行键指定的行中 所有列族中所有列的所有版本 !

(2)指定要删除的行键和时间戳

Delete(byte[] row, long timestamp)

删除行键和时间戳共同确定行的数据。

如果没有进一步的操作,使用该构造函数将删除行键指定的行中,所有列族中所有列的 时间戳 小于等于 指定时间戳的数据版本 

注意 :该时间戳仅仅和删除行有关,如果需要进一步指定列族或者列,你必须分别为它们指定时间戳。

(3)给定一个字符串,目标行键的偏移,截取的长度

Delete(byte[] rowArray, int rowOffset, int rowLength)

(4)给定一个字符串,目标行键的偏移,截取的长度,时间戳

Delete(byte[] rowArray, int rowOffset, int rowLength, long ts)

6.2.常用方法

  • Delete   deleteColumn (byte[] family, byte[] qualifier)     删除指定列的 最新版本 的数据。
  • Delete   deleteColumn s (byte[] family, byte[] qualifier)     删除指定列的 所有版本 的数据。
  • Delete   deleteColumn (byte[] family, byte[] qualifier, long  timestamp )     删除指定列的 指定版本 的数据。
  • Delete   deleteColumn s (byte[] family, byte[] qualifier, long  timestamp )     删除指定列的,时间戳 小于等于给定时间戳 的 所有 版本的数据。
  • Delete   deleteFamily (byte[] family)     删除指定列族的所有列的 所有 版本数据。
  • Delete   deleteFamily (byte[] family, long timestamp)     删除指定列族的所有列中 时间戳 小于等于 指定时间戳 的所有数据。
  • Delete   deleteFamilyVersion (byte[] family, long timestamp)     删除指定列族中所有 列的时间戳 等于 指定时间戳 的版本数据。
  • void setTimestamp (long timestamp)     为Delete对象设置时间戳。

6.3.实例代码

(1)删除整行的所有列族、所有行、所有版本

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        

        Delete delete =  new  Delete(Bytes. toBytes ( "000" ));

        table.delete(delete);

 

        table.close();

  

(2)删除 指定列的最新版本

以下是删除之前的数据,注意看100003行的info:address,这是该列最新版本的数据,值是caofang1,在这之前的版本值是caofang:

hbase(main):007:0> scan 'rd_ns:leetable'

ROW                       COLUMN+CELL

100001                   column=info:address, timestamp=1405304843114, value=longze

100001                   column=info:age, timestamp=1405304843114, value=31

100001                   column=info:name, timestamp=1405304843114, value=leon

100002                   column=info:address, timestamp=1405305471343, value=caofang

100002                   column=info:age, timestamp=1405305471343, value=30

100002                   column=info:name, timestamp=1405305471343, value=show

 100003                   column=info:address, timestamp=1405390959464, value=caofang1

100003                   column=info:age, timestamp=1405390959464, value=301

100003                   column=info:name, timestamp=1405390959464, value=show1

3 row(s) in 0.0270 seconds

执行以下代码:

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        Delete delete =  new  Delete(Bytes. toBytes ( "100003" ));

        delete.deleteColumn(Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ));

        

        table.delete(delete);

 

        table.close();

  

然后查看数据,发现100003列的info:address列的值显示为前一个版本的caofang了!其余值均不变:

hbase(main):008:0> scan 'rd_ns:leetable'

ROW                       COLUMN+CELL

100001                   column=info:address, timestamp=1405304843114, value=longze

100001                   column=info:age, timestamp=1405304843114, value=31

100001                   column=info:name, timestamp=1405304843114, value=leon

100002                   column=info:address, timestamp=1405305471343, value=caofang

100002                   column=info:age, timestamp=1405305471343, value=30

100002                   column=info:name, timestamp=1405305471343, value=show

 100003                   column=info:address, timestamp=1405390728175, value=caofang

100003                   column=info:age, timestamp=1405390959464, value=301

100003                   column=info:name, timestamp=1405390959464, value=show1

3 row(s) in 0.0560 seconds

(3)删除 指定列的所有版本

接以上场景,执行以下代码:

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        Delete delete =  new  Delete(Bytes. toBytes ( "100003" ));

        delete. deleteColumns (Bytes. toBytes ( "info" ), Bytes. toBytes ( "address" ));

        

        table.delete(delete);

 

        table.close();

  

然后我们会发现,100003行的整个info:address列都没了:

hbase(main):009:0> scan 'rd_ns:leetable'

ROW                       COLUMN+CELL

100001                   column=info:address, timestamp=1405304843114, value=longze

100001                   column=info:age, timestamp=1405304843114, value=31

100001                   column=info:name, timestamp=1405304843114, value=leon

100002                   column=info:address, timestamp=1405305471343, value=caofang

100002                   column=info:age, timestamp=1405305471343, value=30

100002                   column=info:name, timestamp=1405305471343, value=show

 100003                   column=info:age, timestamp=1405390959464, value=301

 100003                   column=info:name, timestamp=1405390959464, value=show1

3 row(s) in 0.0240 seconds

(4) 删除指定列族中所有 列的时间戳 等于 指定时间戳 的版本数据

为了演示效果,我已经向100003行的info:address列新插入一条数据

hbase(main):010:0> scan 'rd_ns:leetable'

ROW                       COLUMN+CELL

100001                   column=info:address, timestamp=1405304843114, value=longze

100001                   column=info:age, timestamp=1405304843114, value=31

100001                   column=info:name, timestamp=1405304843114, value=leon

100002                   column=info:address, timestamp=1405305471343, value=caofang

100002                   column=info:age, timestamp=1405305471343, value=30

100002                   column=info:name, timestamp=1405305471343, value=show

100003                   column=info:address, timestamp= 1405391883886 , value=shangdi

100003                   column=info:age, timestamp= 1405390959464 , value=301

100003                   column=info:name, timestamp= 1405390959464 , value=show1

3 row(s) in 0.0250 seconds

现在,我们的目的是删除info列族中,时间戳为1405390959464的所有列数据:

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        

        Delete delete =  new  Delete(Bytes. toBytes ( "100003" ));

        delete. deleteFamilyVersion (Bytes. toBytes ( "info" ), 1405390959464L);

        

        table.delete(delete);

 

        table.close();

  

hbase(main):011:0> scan 'rd_ns:leetable'

ROW                       COLUMN+CELL

100001                   column=info:address, timestamp=1405304843114, value=longze

100001                   column=info:age, timestamp=1405304843114, value=31

100001                   column=info:name, timestamp=1405304843114, value=leon

100002                   column=info:address, timestamp=1405305471343, value=caofang

100002                   column=info:age, timestamp=1405305471343, value=30

100002                   column=info:name, timestamp=1405305471343, value=show

100003                   column=info:address, timestamp= 1405391883886 , value=shangdi

100003                   column=info:age, timestamp= 1405390728175 , value=30

100003                   column=info:name, timestamp= 1405390728175 , value=show

3 row(s) in 0.0250 seconds

可以看到,100003行的info列族,已经不存在时间戳为 1405390959464的数据,比它更早版本的数据被查询出来,而info列族中时间戳不等于 1405390959464的address列,不受该delete的影响 。


7.获取单行Get

如果希望获取整行数据,用行键初始化一个Get对象就可以,如果希望进一步缩小获取的数据范围,可以使用Get对象的以下方法:

  • 如果希望取得指定列族的所有列数据,使用 addFamily 添加所有的目标列族即可;
  • 如果希望取得指定列的数据,使用 addColumn 添加所有的目标列即可;
  • 如果希望取得目标列的指定时间戳范围的数据版本,使用 setTimeRange ;
  • 如果仅希望获取目标列的指定时间戳版本,则使用 setTimestamp ;
  • 如果希望限制每个列返回的版本数,使用 setMaxVersions ;
  • 如果希望添加过滤器,使用 setFilter

下面详细描述构造函数及常用方法:

7.1.构造函数

Get的构造函数很简单,只有一个构造函数: Get(byte[] row) 参数是行键。

7.2.常用方法

  • Get addFamily(byte[] family)  指定希望获取的列族
  • Get addColumn(byte[] family, byte[] qualifier)  指定希望获取的列
  • Get setTimeRange(long minStamp, long maxStamp)  设置获取数据的 时间戳范围
  • Get setTimeStamp(long timestamp)  设置获取数据的时间戳
  • Get setMaxVersions(int maxVersions) 设定获取数据的版本数
  • Get setMaxVersions()  设定获取数据的 所有版本
  • Get setFilter(Filter filter)  为Get对象添加过滤器,过滤器详解请参见:http://blog.csdn.net/u010967382/article/details/37653177
  • void setCacheBlocks(boolean cacheBlocks)  设置该Get获取的数据是否缓存在内存中

7.3.实测代码

测试表的所有数据:

hbase(main):016:0> scan 'rd_ns:leetable'

ROW                       COLUMN+CELL

100001                   column=info:address, timestamp=1405304843114, value=longze

100001                   column=info:age, timestamp=1405304843114, value=31

100001                   column=info:name, timestamp=1405304843114, value=leon

100002                   column=info:address, timestamp=1405305471343, value=caofang

100002                   column=info:age, timestamp=1405305471343, value=30

100002                   column=info:name, timestamp=1405305471343, value=show

100003                   column=info:address, timestamp=1405407883218, value=qinghe

100003                   column=info:age, timestamp=1405407883218, value=28

100003                   column=info:name, timestamp=1405407883218, value=shichao

3 row(s) in 0.0250 seconds

(1)获取行键指定行的 所有列族、所有列 的 最新版本 数据

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        Get get =  new  Get(Bytes. toBytes ( "100003" ));

        Result r = table.get(get);

         for  (Cell cell : r.rawCells()) {

            System. out .println(

                     "Rowkey : " +Bytes. toString (r.getRow())+

                     "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                     "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))

                    );

        }

 

        table.close();

  

代码输出:

Rowkey : 100003   Familiy:Quilifier : address   Value : qinghe

Rowkey : 100003   Familiy:Quilifier : age   Value : 28

 

Rowkey : 100003   Familiy:Quilifier : name   Value : shichao

  

(2)获取行键指定行中, 指定列 的最新版本数据

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        Get get =  new  Get(Bytes. toBytes ( "100003" ));

         get.addColumn(Bytes. toBytes ( "info" ), Bytes. toBytes ( "name" ));

        Result r = table.get(get);

         for  (Cell cell : r.rawCells()) {

            System. out .println(

                     "Rowkey : " +Bytes. toString (r.getRow())+

                     "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                     "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))

                    );

        }

 

        table.close();

  

代码输出:

 

Rowkey : 100003   Familiy:Quilifier : name   Value : shichao

  

(3)获取行键指定的行中, 指定时间戳 的数据

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:leetable" );

        Get get =  new  Get(Bytes. toBytes ( "100003" ));

         get.setTimeStamp(1405407854374L);

        Result r = table.get(get);

         for  (Cell cell : r.rawCells()) {

            System. out .println(

                     "Rowkey : " +Bytes. toString (r.getRow())+

                     "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                     "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))

                    );

        }

 

        table.close(); 

  

代码输出了上面scan命令输出中没有展示的历史数据:

Rowkey : 100003   Familiy:Quilifier : address   Value : huangzhuang

Rowkey : 100003   Familiy:Quilifier : age   Value : 32

 

Rowkey : 100003   Familiy:Quilifier : name   Value : lily

  

(4)获取行键指定的行中, 所有版本 的数据

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:itable" );

        Get get =  new  Get(Bytes. toBytes ( "100003" ));

        get.setMaxVersions();

        Result r = table.get(get);

         for  (Cell cell : r.rawCells()) {

            System. out .println(

                     "Rowkey : " +Bytes. toString (r.getRow())+

                     "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                     "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+

                     "   Time : " +cell.getTimestamp()

                    );

        }

        table.close();        

  

代码输出:

Rowkey : 100003   Familiy:Quilifier : address   Value : xierqi   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : address   Value : shangdi   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : address   Value : longze   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 30   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : age   Value : 31   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : name   Value : leon   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : name   Value : lee   Time : 1405417477465

 

Rowkey : 100003   Familiy:Quilifier : name   Value : lion   Time : 1405417448414

  

注意:

能输出多版本数据的前提是当前列族能保存多版本数据,列族可以保存的数据版本数通过HColumnDescriptor的setMaxVersions(Int)方法设置。


8.获取多行Scan

Scan对象可以返回满足给定条件的多行数据。 如果希望获取所有的行,直接初始化一个Scan对象即可。 如果希望限制扫描的行范围,可以使用以下方法:

  • 如果希望获取指定列族的所有列,可使用 addFamily 方法来添加所有希望获取的列族
  • 如果希望获取指定列,使用 addColumn 方法来添加所有列
  • 通过 setTimeRange 方法设定获取列的时间范围
  • 通过 setTimestamp 方法指定具体的时间戳,只返回该时间戳的数据
  • 通过 setMaxVersions 方法设定最大返回的版本数
  • 通过 setBatch 方法设定返回数据的最大行数
  • 通过 setFilter 方法为Scan对象添加过滤器,过滤器详解请参见: http://blog.csdn.net/u010967382/article/details/37653177
  • Scan的结果数据是可以缓存在内存中的,可以通过 getCaching ()方法来查看当前设定的缓存条数,也可以通过 setCaching (int caching)来设定缓存在内存中的行数,缓存得越多,以后查询结果越快,同时也消耗更多内存。此外, 通过 setCacheBlocks 方法设置是否缓存Scan的结果数据块,默认为true
  • 我们可以通过 setMaxResultSize(long)方法来设定Scan返回的结果行数。

下面是官网文档中的一个入门示例:假设表有几行键值为 "row1", "row2", "row3",还有一些行有键值 "abc1", "abc2", 和 "abc3",目标是返回"row"打头的行:

 

 

HTable htable = ...      // instantiate HTable

 

Scan scan = new Scan();

 

scan.addColumn(Bytes.toBytes("cf"),Bytes.toBytes("attr"));

 

scan.setStartRow( Bytes.toBytes("row"));                   // start key is inclusive

 

scan.setStopRow( Bytes.toBytes("row" +  (char)0));  // stop key is exclusive

 

ResultScanner rs = htable.getScanner(scan);

 

try {

 

for (Result r = rs.next(); r != null; r = rs.next()) {

 

// process result...

 

} finally {

 

rs.close(); // always close the ResultScanner!

 

}

 

8.1.常用构造函数

 

(1)创建扫描所有行的Scan

Scan()

(2)创建Scan,从指定行开始扫描 ,

Scan(byte[] startRow)

参数: startRow 行键

注意 :如果指定行不存在,从下一个最近的行开始

(3)创建Scan,指定起止行

Scan(byte[] startRow, byte[] stopRow)

参数: startRow起始行, stopRow终止行

注意 : startRow <= 结果集 <  stopRow

(4)创建Scan,指定起始行和过滤器

Scan(byte[] startRow, Filter filter)

参数: startRow 起始行, filter 过滤器

注意:过滤器的功能和构造参见 http://blog.csdn.net/u010967382/article/details/37653177

 

8.2.常用方法

 

  • Scan   setStartRow (byte[] startRow)   设置Scan的开始行, 默认 结果集 包含 该行。 如果希望结果集不包含该行,可以在行键末尾加上0。
  • Scan   setStopRow (byte[] stopRow)    设置Scan的结束行, 默认 结果集 不包含 该行。 如果希望结果集包含该行,可以在行键末尾加上0。
  • Scan   setTimeRange (long minStamp, long maxStamp)    扫描指定 时间范围 的数据
  • Scan   setTimeStamp (long timestamp)  扫描指定 时间 的数据
  • Scan   addColumn (byte[] family, byte[] qualifier)   指定扫描的列
  • Scan   addFamily (byte[] family) 指定扫描的列族
  • Scan   setFilter (Filter filter)   为Scan设置过滤器
  • Scan   setReversed (boolean reversed)  设置Scan的扫描顺序,默认是正向扫描(false),可以设置为逆向扫描(true)。注意:该方法0.98版本以后才可用!!
  • Scan   setMaxVersions ()  获取所有版本的数据
  • Scan   setMaxVersions (int maxVersions)  设置获取的最大版本数
  • void   setCaching (int caching)   设定缓存在内存中的行数,缓存得越多,以后查询结果越快,同时也消耗更多内存
  • void setRaw (boolean raw)  激活或者禁用raw模式。如果raw模式被激活,Scan将返回 所有已经被打上删除标记但尚未被真正删除 的数据。该功能仅用于激活了 KEEP_DELETED_ROWS的列族,即列族开启了hcd.setKeepDeletedCells(true)

    。Scan激活raw模式后,就不能指定任意的列,否则会报错

Enable/disable "raw" mode for this scan. If "raw" is enabled the scan will return all delete marker and deleted rows that have not been collected, yet. This is mostly useful for Scan on column families  that have KEEP_DELETED_ROWS enabled. It is an error to specify any column when "raw" is set.

hcd.setKeepDeletedCells(true);

 

8.3.实测代码

 

(1)扫描表中的 所有行 的最新版本数据

 

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:itable" );

        

        Scan s =  new  Scan();

        ResultScanner rs = table.getScanner(s);

         for  (Result r : rs) {

             for  (Cell cell : r.rawCells()) {

                System. out .println(

                         "Rowkey : " +Bytes. toString (r.getRow())+

                         "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                         "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+

                         "   Time : " +cell.getTimestamp()

                        );

            }

        }

 

        table.close();

  

 

代码输出:

 

Rowkey : 100001   Familiy:Quilifier : address   Value : anywhere   Time : 1405417403438

Rowkey : 100001   Familiy:Quilifier : age   Value : 24   Time : 1405417403438

Rowkey : 100001   Familiy:Quilifier : name   Value : zhangtao   Time : 1405417403438

Rowkey : 100002   Familiy:Quilifier : address   Value : shangdi   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : age   Value : 28   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : name   Value : shichao   Time : 1405417426693

Rowkey : 100003   Familiy:Quilifier : address   Value : xierqi   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405417500485

 

Rowkey : 100003   Familiy:Quilifier : name   Value : leon   Time : 1405417500485

  

 

(2) 扫描指定行键范围,通过末尾加0,使得结果集包含StopRow

 

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:itable" );

        Scan s =  new  Scan();

        s. setStartRow (Bytes. toBytes ( "100001" ));

        s. setStopRow (Bytes. toBytes ( " 1000020 " ));

        

        ResultScanner rs = table.getScanner(s);

         for  (Result r : rs) {

             for  (Cell cell : r.rawCells()) {

                System. out .println(

                         "Rowkey : " +Bytes. toString (r.getRow())+

                         "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                         "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+

                         "   Time : " +cell.getTimestamp()

                        );

            }

        }

 

        table.close();

  

 

代码输出:

 

Rowkey : 100001   Familiy:Quilifier : address   Value : anywhere   Time : 1405417403438

Rowkey : 100001   Familiy:Quilifier : age   Value : 24   Time : 1405417403438

Rowkey : 100001   Familiy:Quilifier : name   Value : zhangtao   Time : 1405417403438

Rowkey : 100002   Familiy:Quilifier : address   Value : shangdi   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : age   Value : 28   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : name   Value : shichao   Time : 1405417426693   

 

(3) 返回 所有已经被打上删除标记但尚未被真正删除 的数据

 

本测试针对rd_ns:itable表的100003行。

 

如果使用get结合 setMaxVersions() 方法能返回所有未删除的数据,输出如下:

 

Rowkey : 100003   Familiy:Quilifier : address   Value : huilongguan   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : address   Value : shangdi   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : age   Value : new29   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : name   Value : liyang   Time : 1405494141522

  

 

然而,使用Scan强大的 s.setRaw( true ) 方法,可以获得所有 已经被打上删除标记但尚未被真正删除 的数据。

 

代码如下:

 

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:itable" );

        Scan s =  new  Scan();

        s.setStartRow(Bytes. toBytes ( "100003" ));

        s.setRaw( true );

        s.setMaxVersions();

        

        ResultScanner rs = table.getScanner(s);

         for  (Result r : rs) {

             for  (Cell cell : r.rawCells()) {

                System. out .println(

                         "Rowkey : " +Bytes. toString (r.getRow())+

                         "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                         "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+

                         "   Time : " +cell.getTimestamp()

                        );

            }

        }

        table.close();

  

 

输出结果如下:

 

Rowkey : 100003   Familiy:Quilifier : address   Value : huilongguan   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : address   Value :    Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : address   Value : xierqi   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : address   Value : shangdi   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : address   Value :    Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : address   Value : longze   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : age   Value : new29   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : age   Value :    Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value :    Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 29   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : age   Value : 30   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : age   Value : 31   Time : 1405417448414

Rowkey : 100003   Familiy:Quilifier : name   Value : liyang   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : name   Value :    Time : 1405493879419

Rowkey : 100003   Familiy:Quilifier : name   Value : leon   Time : 1405417500485

Rowkey : 100003   Familiy:Quilifier : name   Value : lee   Time : 1405417477465

Rowkey : 100003   Familiy:Quilifier : name   Value : lion   Time : 1405417448414

 

(4) 结合过滤器,获取所有age在25到30之间的行

 

目前的数据:

 

hbase(main):049:0> scan 'rd_ns:itable'

ROW                                           COLUMN+CELL

100001                                       column=info:address, timestamp=1405417403438, value=anywhere

100001                                       column=info:age, timestamp=1405417403438, value=24

100001                                       column=info:name, timestamp=1405417403438, value=zhangtao

100002                                       column=info:address, timestamp=1405417426693, value=shangdi

100002                                       column=info:age, timestamp=1405417426693, value=28

100002                                       column=info:name, timestamp=1405417426693, value=shichao

100003                                       column=info:address, timestamp=1405494141522, value=huilongguan

100003                                       column=info:age, timestamp=1405494999631, value=29

100003                                       column=info:name, timestamp=1405494141522, value=liyang

3 row(s) in 0.0240 seconds

 

代码:

 

        Configuration conf = HBaseConfiguration. create ();

        HTable table =  new  HTable(conf,  "rd_ns:itable" );

        FilterList filterList =  new  FilterList(FilterList.Operator. MUST_PASS_ALL );  

        SingleColumnValueFilter filter1 =  new  SingleColumnValueFilter(

                Bytes. toBytes ( "info" ),

                Bytes. toBytes ( "age" ),

                CompareOp. GREATER_OR_EQUAL ,

                Bytes. toBytes ( "25" )

                );

        SingleColumnValueFilter filter2 =  new  SingleColumnValueFilter(

                Bytes. toBytes ( "info" ),

                Bytes. toBytes ( "age" ),

                CompareOp. LESS_OR_EQUAL ,

                Bytes. toBytes ( "30" )

                );

        filterList.addFilter(filter1);

        filterList.addFilter(filter2);

        

        Scan scan =  new  Scan();

        scan.setFilter(filterList);

        

        ResultScanner rs = table.getScanner(scan);

         for  (Result r : rs) {

             for  (Cell cell : r.rawCells()) {

                System. out .println(

                         "Rowkey : " +Bytes. toString (r.getRow())+

                         "   Familiy:Quilifier : " +Bytes. toString (CellUtil. cloneQualifier (cell))+

                         "   Value : " +Bytes. toString (CellUtil. cloneValue (cell))+

                         "   Time : " +cell.getTimestamp()

                        );

            }

        }

 

        table.close();

  

 

代码输出:

 

Rowkey : 100002   Familiy:Quilifier : address   Value : shangdi   Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : age   Value :  28    Time : 1405417426693

Rowkey : 100002   Familiy:Quilifier : name   Value : shichao   Time : 1405417426693

Rowkey : 100003   Familiy:Quilifier : address   Value : huilongguan   Time : 1405494141522

Rowkey : 100003   Familiy:Quilifier : age   Value :  29    Time : 1405494999631

Rowkey : 100003   Familiy:Quilifier : name   Value : liyang   Time : 1405494141522

 

注意:

HBase对列族、列名大小写敏感

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics