(超详细)快速上手分布式数据库——HBase

HBase的安装、命令操作和基础编程

 JunLeon——go big or go home


目录

HBase的安装、命令操作和基础编程

一、HBase的概述

1.什么是HBase?

2.HBase的特点

3.HBase组成部分及数据模型

(1)HBase架构的组件及其作用

(2)HBase的数据模型

(3)表和Region

4.HBase的读写流程

5.HBase的Compaction过程

二、基于Hadoop HA集群的HBase环境安装配置

1.下载HBase

2.解压安装配置

(1)上传到虚拟机中指定的opt目录下

(2)解压HBase

(3)配置环境及其相关属性

3.启动HBase集群

4.查看进程及HBase集群信息

三、HBase的Shell命令

1.基本Shell命令

2.DDL操作命令

3.DML操作命令

4.运行HBase Shell脚本

四、HBase基础编程

1.HBase API

2.HBase API编程代码演示


前言:

        学习HBase这个组件,可能很多人都有这个这个疑惑:HDFS和MySQL等都可做数据的持久化存储,那为什么还要学习这个HBase呢?而HBase的最终数据还是存储在HDFS中,那为什么还要使用HBase呢?HBase和HDFS又有什么关系呢?

        HBase作为Hadoop的分布式数据库,基于Google发行的三篇论文之一——《BigData》研发的Hadoop生态组件之一。那我们为啥要用HBase呢?HBase在HDFS之上提供了高并发的随机写支持实时查询,这是HDFS不具备的。

        HDFS是分布式文件存储系统,HBase是分布式数据库,两者其实没有什么可比性。可能很多人对MySQL比较熟悉,MySQL的数据持久化就是将数据落地磁盘存储。简单理解就是可以把HBase当做是MySQL,把HDFS当做是硬盘。HBase只是一个NoSQL数据库,把数据存在HDFS上。

一、HBase的概述

1.什么是HBase?

        HBase是高可靠性、高性能、面向列、可伸缩的分布式存储系统,是基于HDFS的分布式数据库,也是一种非关系型数据库。分布式数据库HBase是Hadoop生态系统的组件之一。HBase的运行依赖于Hadoop HDFS文件系统提供数据的持久化,依赖于Zookeeper提供集群的的同步与协调。HBase使用Zookeeper服务来进行节点管理以及表数据的定位。

2.HBase的特点

        (1)大:一个表可以有上亿行,上百万列。
        (2)面向列:面向列表(簇)的存储和权限控制,列(簇)独立检索。
        (3)稀疏:对于为空(NULL)的列,并不占用存储空间,因此,表可以设计的非常稀疏。
        (4)无模式:每一行都有一个可以排序的主键和任意多的列,列可以根据需要动态增加,同一张表中不同的行可以有截然不同的列。
        (5)数据多版本:每个单元中的数据可以有多个版本,默认情况下,版本号自动分配,版本号就是单元格插入时的时间戳。
        (6)数据类型单一:HBase中的数据都是字符串,没有类型。

3.HBase组成部分及数据模型

(1)HBase架构的组件及其作用

        HBase采用Master/slaves的主从服务器架构,由一个HMaster服务器和多个HRegionServer服务器组成。HBase采用Master/Slave架构,主要角色包括Master服务器(HMaster,管理节点)、Region服务器(HRegionServer,数据节点)、ZooKeeper服务器以及客户端。

 1.HMaster HMaster

        HMaster HMaster是主节点,它主要负责HRegionServer的管理以及元数据的更改,包括以下内容:新HRegionServer的注册、表的增删改查、HRegionServer的负载均衡,Region(表的分区,存储在Region服务器上)的分布调整、Region分裂以及分裂后的Region分配,HRegionServer失效后的Region迁移等。

        HMaster采用主备模式部署,集群启动时,通过竞争获得主HMaster角色。主HMaster只能有一个,备HMaster进程在集群运行期间处于休眠状态,不干涉任何集群事务。当主用Master故障时,备用Master将取代主用Master对外提供服务。

2.HRegionServer

        HRegionServer是HBase的从节点,它负责提供表数据读写等服务,是数据存储和计算单元。HRegionServer一般与HDFS集群的DataNode部署在一起,实现数据的存储功能。一台HRegionServer管理多个Region对象和一个HLog文件。

        一个Region由一个或多个Store组成。每个Store存储该Region一个列族的数据。一个Store包含一个MemStore缓存以及若干StoreFile文件,MemStore缓存客户端向Region插入的数据,当HRegionServer中的MemStore大小达到配置的容量上限时,RegionServer会将MemStore中的数据刷新(Flush)到HDFS中。MemStore的数据刷新到HDFS后成为HFile,HFile定义了StoreFile在文件系统中的存储格式,它是当前HBase系统中StoreFile的具体实现。随着数据的插入,一个Store会产生多个StoreFile,当StoreFile的个数达到配置的最大值时,RegionServer会将多个StoreFile合并为一个大的StoreFile。

        HLog日志是一种预写式日志(Write Ahead Log),用户更新数据时需要先写入HLog再写入MemStore,MemStore中的数据被刷新到StoreFile之后才会在HLog中清除对应的记录,这样的设计保证了当HRegionServer故障时,用户写入的数据不丢失,一台HRegionServer的所有Region共享同一个HLog。

3.ZooKeeper

        ZooKeeper为HBase集群各进程提供分布式协作服务。各HRegionServer将自己的信息注册到ZooKeeper中,HMaster据此感知各个HRegionServer的健康状态。

        HBase还通过ZooKeeper实现HMaster的高可用。ZooKeeper存储HBase的如下信息:HBase元数据、HMaster地址。当HMaster主节点出现故障时,HMaster备用节点会通过ZooKeeper获取主HMaster存储的整个HBase集群状态信息,接管HMaster主节点的工作。

4.Client

        客户端通过HBase的元数据找到所需数据所在的HRegionServer进行访问(HBase的元数据存储在ZooKeeper中,因此客户端在做读取操作时不需要与HMaster进行通信,这样的设计减少了HMaster的负担),客户端会在缓存中维护访问过的Region位置信息,下次访问时就可以跳过向ZooKeeper寻址的过程。如果缓存中位置信息所指向的HRegionServer失效或Region已被迁移到其他服务器,客户端在查找不到该Region的情况下,会重新查询元数据以获取该Region的新地址。除了读取HRegionServer的信息外,客户端还可以与HMaster通信做表的修改。

(2)HBase的数据模型

        HBase中,数据存储在由行和列组成的表中,HBase的表是稀疏的,多维映射的。HBase用键值对的方式存储数据。每个值都是未经解释的字符串,通过行键、列族、列限定符、时间戳等信息进行定位。

1.表(Table)

        HBase采取表的形式存储数据,表由行和列组成。

2.行(Row)

        HBase中的行由行键(RowKey)和若干列组成。行是通过行键按字典顺序进行排序的,因此行键的设计非常重要,好的行键设计可以将内容相关的行排列到相邻位置,方便查找和读取。以存储网页内容为例,将URL作为行键,如org.apache.www、org.apache.mail,可以将相邻子网页存储在相邻的位置。

3.列族(Column Family)

        一个表在水平方向上由一个或多个列族组成。一个列族可以由任意多个列组成,列族在表创建时就需要预先设定好。

        列族是Region的物理存储单元。同一个Region下面的多个列族,位于不同的Store下面。

        列族信息是表级别的配置。同一个表的多个Region,都拥有相同的列族信息(例如,都有两个列族,且不同Region的同一个列族配置信息相同)。不是每一行下的列族或列中都存储了信息,因此说HBase的表是稀疏的。

4.列限定符(Column Qualifier)

        列族中添加不同的列限定符可以对数据进行划分定位,列限定符以列族名作为前缀,用“:”连接后缀。例如以“content”为列族,那么列限定符则可以是“content:xxxx”。列限定符是列族下的一个标签,可以在写入数据时任意添加,支持动态扩展,无需预先定义列的数量和类型。

5.单元格(Cell)

        一个单元格保存了一个值的多个版本,单元格通过行键、列族和列限定符进行定位,每个版本对应一个时间戳。

6.时间戳(TimeStamp)

        HBase每个值都会带一个时间戳,时间戳标识了这个值的版本。默认情况下,在一个值发生变化(写入、更新、删除)时,所在的HRegionServer会自动为其创建一个时间戳。用户也可以在值发生变化时自定义时间戳。如果一个值有多个版本,在用户查询时默认返回最新的版本。HBase保存的版本数可以自定义,当超过设置的版本数时,新的版本会替换掉最早的版本。

(3)表和Region

        一个HBase集群中维护着多张表,每张表可能包含非常多的行,在单台机器上无法全部存储,HBase会将一张数据表按行键的值范围横向划分为多个子表,实现分布式存储,如图5-1所示。这些子表,在HBase中被称作“Region”,Region是HBase分布式存储的基本单元。每一个Region都关联一个行键值的范围,即一个使用StartKey和EndKey描述的区间。事实上,每一个Region仅仅记录StartKey就可以了,因为它的EndKey就是下一个Region的StartKey。

        每张表最开始值包含一个Region,随着表中数据的不断增大,Region中的行数超过一定阈值时就会分裂为两个新的Region。

        Region分为元数据Region以及用户Region(User Region)两类。用户Region用于存储普通数据,元数据Region包括.META.表和-ROOT-表,用于存储Region的位置信息。.META.表记录了每一个用户Region的路由信息,用户可以通过.META.表查询到要访问的Region所在的HRegionServer,从而与其建立通信进行数据操作。.META.表的路由信息存储在-ROOT-表中,-ROOT-表不可被分割,只有一个Region。用户可以通过访问ZooKeeper服务器来获得-ROOT-表的位置。Region的划分如下图:

        从HBase0.96.0开始,-ROOT-表的设置已被移除,.META.表改名为hbase:meta,hbase:meta的位置信息直接保存在ZooKeeper中。

4.HBase的读写流程

1.HBase的读流程

        HBase的读流程如下: ·

        客户端发起请求,与ZooKeeper服务器通信获取hbase:meta所在的HRegion Server,记为HRegionServer A;

        访问HRegionServer A中的hbase:meta,hbase:meta中记载着各个User Region信息(行键范围,所在RegionServer等),通过行键查找hbase:meta获取所要读取的Region所在HRegionServer,记为HRegionServer B;

        请求发送到HRegionServer B,HRegionServer B先查询MemStore,如果未查询到目标数据,则在HFile中查找; ·

        查询到数据后返回到客户端。

2.HBase的写流程

        HBase的写流程如下: ·

        客户端发起请求,与ZooKeeper服务器通信获取hbase:meta所在HRegionServer,记为HRegionServer A;

        客户端访问HRegionServer A中的hbase:meta,hbase:meta中记载着每个User Region信息(行键范围,所在RegionServer),通过行键查找hbase:meta获取本次写入操作所涉及的HRegionServer(HBase写入操作可能会涉及多个HRegionServer,在写入前HBase会对数据进行分组,分组共两步:首先将所有的记录按RegionServer划分,然后将同一RegionServer所有的记录按Region划分。每个RegionServer上的数据会一起发送,这样发送的数据中,都是已经按照Region分好组了);

        客户端按RegionServer和Region将数据打包发送到对应的HRegionServer,RegionServer将数据写入对应的Region; ·客户端发送完待写数据后,会自动等待请求处理结果,如果客户端没有捕获到任何的异常,则认为所有数据写入成功。如果全部写入失败,或者部分写入失败,客户端能够获知详细的失败Key值列表。

        如下图所示,HRegionServer在写入数据时,会先将数据写入HLog中,再将需要写入的数据暂时保存在对应Region的缓存MemStore中。这样一来可以减少数据直接写入磁盘带来的写入延迟,提高写入效率;另外数据先写入HLog可以避免HRegionServer故障时造成缓存数据的丢失。

      

        达到一定预设条件时,HBase会将MemStore中的数据写入磁盘生成HFlie文件,并清空MemStore及HLog中的对应记录,这个过程称为刷盘(Flush)。

5.HBase的Compaction过程

        当随着时间的增长,业务数据不断写入到HBase集群中,HFile的数目会越来越多,那么针对同样的查询,需要同时打开的文件也就可能越来越多,从而增加了查询延时,降低查询效率。

        当HFile文件过多时,HBase就会启动一个Compation的操作。Compaction的主要目的,是为了减少同一个Region同一个列族下面的小文件数目,从而提升读取的性能。

        如下图所示,Compaction分为Minor、Major两类。

        Minor:小范围的Compaction。Minor Compation有最少和最大文件数目限制,默认最少选择3个HFile,最多10个,通常会选择一些连续时间范围的小文件进行合并。Minor Compaction选取文件时,遵循一定的算法。 

        Major:Major Compaction会将一个Region中的某个ColumnFamily下面所有的HFile合并成一个HFile。HBase默认一天进行一次Major Compaction。Major Compaction过程中,会清理被删除的数据。

二、基于Hadoop HA集群的HBase环境安装配置

1.下载HBase

官网下载:Index of /dist/hbase

版本:hbase-1.4.13-bin.tar.gz

 hadoop版本对应的HBase版本可以参考下表,自行选择下载:

 补充:我使用的是hadoop-2.7.3版本,故下载hbase-1.4.13的版本。

2.解压安装配置

 说明:该HBase环境是在基于Zookeeper的Hadoop HA的基础上搭建的。

基于Zookeeper的Hadoop HA搭建请查看:(超详细)基于Zookeeper的Hadoop HA集群的搭建_JunLeon的博客-CSDN博客

(1)上传到虚拟机中指定的opt目录下

        可通过XShell或者其他远程连接工具上传,上传过程略

(2)解压HBase

tar -zxvf /opt/hbase-1.4.13-bin.tar.gz -C /opt/   

(3)配置环境及其相关属性

1.配置HBase的环境变量

vi  /etc/profile

在该文件的最后添加HBase的安装路径

 使配置文件生效:

source /etc/profile

2.配置${HBASE_HOME}/conf/hbase-env.sh文件

vi ${HBASE_HOME}/conf/hbase-env.sh

在27行,配置jdk路径:

 注释46、47行,如果使用jdk1.8,则需要注释掉

 128行,设置是否启动HBase自带的zookeeper

 3.配置${HBASE_HOME}/conf/hbase-site.xml文件

<configuration>
	<property>
		<!-- hbase存放数据目录。mycluster为hdfs-site.xml中dfs.nameservices的值 -->
		<name>hbase.rootdir</name>
		<value>hdfs://mycluster/data/hbase_db</value>
	</property>
	<property>
		<!-- 是否分布式部署HBase -->
		<name>hbase.cluster.distributed</name>
		<value>true</value>
	</property>
	<property>
		<name>dfs.support.append</name>
		<value>true</value>
	</property>
	<property>
		<name>hbase.zookeeper.quorum</name>
		<value>BigData01,BigData02,BigData03</value>
	</property>
	<property>
		<!-- Zookooper配置、日志等的存储位置 -->
		<name>hbase.zookeeper.property.datadir</name>
		<value>/opt/zookeeper-3.4.12</value>
	</property>
	<property>
		<name>hbase.zookeeper.property.clientPort</name>
		<value>2181</value>
	</property>
</configuration>

4.配置${HBASE_HOME}/conf/regionservers文件

BigData01
BigData02
BigData03

3.启动HBase集群

在开启HBase集群之前应先将HDFS和YARN节点开启

start-all.sh    # 在主节点上执行

再启动HBase集群节点

start-hbase.sh    # 在主节点上执行

4.查看进程及HBase集群信息

jps    # 查看开启的守护进程

 Web端访问:(在主机Master上执行)

IP:16010        例如:192.168.182.10:16010

三、HBase的Shell命令

1.基本Shell命令

(1)启动shell命令(进入HBase命令环境)

[root@BigData01 ~]# hbase shell

 如下图所示即进入HBase命令环境中:

(2)查看HBase状态

hbase(main):001:0> status

(3)查看版本

hbase(main):002:0> version

(4)获得帮助

hbase(main):003:0> help

(5)退出shell命令

hbase(main):004:0> exit

2.DDL操作命令

DDL即数据定义语言:

(1)创建表

create  '表名','列族1','列族2'
# 例如:	create  ‘student’,’address’,’info’

(2)以列表的形式显示所有表

list

(3)查看表的结构

desc  '表名'
# 例如: desc  'student'

(4)修改表的结构

disable  '表名'     # 设置表为不可用的状态
alter  '表名',NAME=>'列族名'    # 添加列族
alter  '表名',NAME=>'cf3',METHOD=>'delete'   # 删除列族

# 例如:    
# disable  'student'   —— 设置student为不可用状态      
# alter  'student',NAME=>'cf3'  ——  添加列族cf3
# alter  'student',NAME=>'cf3',METHOD=>'delete'  ——  删除列族cf3

(5)查询表是否存在

exists  '表名'
# 例如:    exists   'student'

(6)判断表是否可用或者不可用

is_eabled  '表名'    # 判断表是否可用
is_disabled  '表名'    # 判断表是否不可用

(7)删除表

disable  '表名'     # 设置表为不可用的状态
drop  '表名'    # 删除指定表

3.DML操作命令

DML即数据操作语言:

首先, 假设student 表的列族为address { province、city}、info { height、weight、birthday、telephone}、'row key' 为姓名(也可根据需要设学号为row key)

(1)插入记录数据

格式:put  '表名','row key','列族:列','列的值'    

put  'student','zhangsan','address:province','guizhou'
put  'student','zhangsan','address:city','guiyang'
put  'student','zhangsan','info:height','180'
put  'student','zhangsan','info:birthday','2000-01-01'
put  'student','zhangsan','info:telephone','18888888888'

(2)获取一条数据

格式:get  '表名','row key'

get  'student','zhangsan'

(3)获取一个ID(row key)的一个列族所有数据

格式:get  '表名','row key','列族'

get  'student','zhangsan','info'

(4)更新一条记录

格式:get  '表名','row key','列族:列'

get  'student','zhangsan','info:height'

(5)更新一条数据

格式:put  '表名','row key','列族:列','列新的值'

put  'student','zhangsan','info:height','190'

(6)读出表数据

scan  '表名'

scan  'student'

(7)查询表有多少行

count  '表名'

count  'student'

(8)将表清空

truncate  '表名'

truncate  'student'

(9)删除某ID(row key)的某列的值

格式:delete  '表名','row key','列族:列' 

delete  'student','zhangsan','info:height'

4.运行HBase Shell脚本

可以将操作命令写入文件中,当成HBase Shell脚本,再在Linux shell命令下执行该脚本。

比如:在Linux文件系统中创建一个脚本testHBaseData.sh,再在Linux Shell命令下执行:

vi  testHBaseData.sh,在脚本文件中添加如下内容:

put  'student','lisi','address:province','guizhou'
put  'student','lisi','address:city','guiyang'
put  'student','lisi','info:height','185'
put  'student','lisi','info:birthday','1995-01-01'
put  'student','lisi','info:telephone','18899999999'

执行脚本文件:

hbase shell testHbaseData.sh

四、HBase基础编程

1.HBase API

(1)HBaseConfiguration类

该类在hbase-common-1.4.13.jar 里,包名为org.apach.hadoop.hbase,该类是客户端必须使用的。 它从hbase-default.xml和hbase-site.xml文件中获取配置信息,编程时使用如下语句进行初始化配置文件:
Configuration  config  =  HBaseConfiguration.create();

(2)ConnectionFactory类和Connection接口

该类和接口在hbase-common-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client,用来通过配置连接HBase 集群,即建立连接,提高连接接口。 编程时使用如下语句:
Connection  connection  =  ConnectionFactory.createConnection(config)

(3)HBaseAdmin类和Admin接口

该类和接口在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client,封装了对数据表结构的操作的接口,提供的方法有:创建表、删除表、列出表项、使表有效或者无效、添加或者删除表列族成员。

(4)HTableDescriptor类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase。HTableDescriptor类封装了表的相关属性及操作接口。

(5)HColumnDescriptor类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase。HColumnDescriptor类维护列族的相关信息。

(6)HTable类和Table接口

该类和接口在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client,HTable类与HBase表直接通信,编程时不推荐使用HTable 类, 建议直接使用Table 接口, 使用如下语句获得Table 接口变量:
TableName  tableName  =  TableName.valueOf("表名");
Table  table  =  connection.getTable(tableName);

(7)Put类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client,Put类用来对单行数据的添加操作。

(8)Get类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client,Get类用于获取单行数据的相关信息。

(9)Scan类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client,用于对表进行检索

(10)ResultScanner类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client,该类提供了客户端获取值得接口。

(11)Result类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client

(12)Delete类

该类在hbase-client-1.4.13.jar 里,包名为org.apach.hadoop.hbase.client

(13)TableName类

该类在hbase-common-1.4.13.jar 里,包名为org.apach.hadoop.hbase

(14)Cell类和CellUtil类

该类在hbase-common-1.4.13.jar 里,包名为org.apach.hadoop.hbase

2.HBase API编程代码演示

下面通过示例介绍使用Java 语言编程来操作HBase 中的表及数据,编程时必需的最少
jar 包为hadoop-common-2.x.x.jar、hbase-common-1.4.13.jar、hbase-client-1.4.13.jar
①打开Eclipse 编程工具,并建立Java工程MyHBaseUtil;


②新建lib 目录, 将Hbase 编程所需的jar 包拷贝到lib 目录下, 并加入buildpath;


③新建Class文件, 比如: HBASEUtil 类, 并在该类中编写针对HBase 操作的方法, 为
了测试在本类中添加入口主方法main(), 使用HBASEUtil 操作数据;


④将本工程导出生成jar 包文件(指定主类), 导出生成jar 包文件的方法:
选择Eclipse的菜单File→Export, 接着选Java 下的Jar File,点击“Next”, 勾选当前工程(比如:MyHBaseUtil), 此时默认选中当前工程下的src和lib 目录,接下来勾选“Export all output folders for checked projects”,导出所有输出文件夹, 在选项Options中勾选“Compress the contents of the of JAR file” “ add directory entries”, 在“ Select the export destination:”中输入JAR file 存储位置及文件名(比如: MyHBaseUtil.jar),最后点击“Finish”即可!

⑤ 将导出的jar 文件上传到服务器BigData01中,再使用命令:

hadoop jar MyHBaseUtil.jar hadoop.hbase.HBaseUtil

运行程序(需要保证已经启动运行了HBase集群), 假设出现Zookeeper连接错误, 则将程序代码中注释下面几行:

        //conf.set("hbase.zookeeper.quorum", "BigData01:2181, BigData02:2181, BigData03:2181");
        //conf.set("hbase.zookeeper.quorum", "BigData01, BigData02, BigData03");
        //conf.set("hbase.zookeeper.property.clientPort", "2181");

参考代码如下:

package hadoop.hbase;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Append;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Increment;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.util.Bytes;

public class HBaseUtil {
	private static Configuration conf = null;
	static {
		conf = HBaseConfiguration.create();
		//conf.set("hbase.zookeeper.quorum", "BigData01:2181, BigData02:2181, BigData03:2181");
		//conf.set("hbase.zookeeper.quorum", "BigData01, BigData02, BigData03");
		//conf.set("hbase.zookeeper.property.clientPort", "2181");
		System.out.println("---Static Code Loaded. Configuration: " + conf.toString());
	}
	
	public static void main(String[] args) {
		String tableName = "goods"; 
		String[] familys = {"baseinfo", "otherinfo"};
		try {
			System.out.println("===Test Beginning: Creat table " + tableName);
			HBaseUtil.deleteTable(tableName);
			HBaseUtil.createTable(tableName, familys);
			HBaseUtil.addData(tableName, "000001", familys[0], "name", "创维电视机");
			HBaseUtil.getOneRow(tableName, "000001");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 创建表
	 * @param tableName
	 * @param familys
	 * @throws MasterNotRunningException
	 * @throws ZooKeeperConnectionException
	 * @throws IOException
	 */
	public static void createTable(String tableName, String[] familys) throws MasterNotRunningException, ZooKeeperConnectionException, IOException{
		HBaseAdmin admin = new HBaseAdmin(conf);
		if(admin.tableExists(tableName)){
			System.out.println("---CreateTable: table " + tableName + " already exists!");
		}else{
			HTableDescriptor tableDesc = new HTableDescriptor(tableName);
			for(int i=0; i<familys.length; i++){
				tableDesc.addFamily(new HColumnDescriptor(familys[i]));
			}
			admin.createTable(tableDesc);
			System.out.println("---CreateTable: create table " + tableName + " success!");
		}
	}
	
	// 删除表
	public static void deleteTable(String tableName)
			throws MasterNotRunningException, ZooKeeperConnectionException, IOException {
		HBaseAdmin admin = new HBaseAdmin(conf);
		if (admin.tableExists(tableName)) {
			admin.disableTable(tableName);
			admin.deleteTable(tableName);
			System.out.println("---DeleteTable: delete table " + tableName + " success!");
		} else {
			System.out.println("---DeleteTable: " + tableName + " not exists!");
		}
	}

	/**
	 * 插入数据
	 * @param tableName
	 * @param rowKey
	 * @param family
	 * @param qualifier
	 * @param value
	 */
	public static void addData(String tableName, String rowKey, String family, String qualifier, String value){
		try {
			HTable table = new HTable(conf, tableName);
			Put put = new Put(Bytes.toBytes(rowKey));
			put.add(Bytes.toBytes(family), Bytes.toBytes(qualifier), Bytes.toBytes(value));
			table.put(put);
			System.out.println("insert record success!");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * 删除数据
	 * @param tableName
	 * @param rowKey
	 * @throws IOException 
	 */
	public static void deleteRow(String tableName, String rowKey) throws IOException{
		HTable table = new HTable(conf, tableName);
		Delete deleteRow = new Delete(rowKey.getBytes());
		table.delete(deleteRow);
		System.out.println("delete row " + rowKey + " success!");
	}
	
	/**
	 * 删除一行中某列
	 * @param tableName
	 * @param rowKey
	 * @param familyName
	 * @param columnName
	 * @throws IOException 
	 */
	public static void deleteColumn(String tableName, String rowKey, String familyName, String columnName) throws IOException{
		HTable table = new HTable(conf, tableName);
		Delete deleteColumn = new Delete(Bytes.toBytes(rowKey));
		deleteColumn.deleteColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName));
		table.delete(deleteColumn);
		System.out.println("delete " + rowKey + ":" + familyName + ":" + columnName + " success!");
	}
	
	/**
	 * 添加数据
	 * @param tableName
	 * @param rowKey
	 * @param family
	 * @param qualifier
	 * @param value
	 * @throws IOException 
	 */
	public static void appendData(String tableName, String rowKey, String family, String qualifier, String value) throws IOException {
		HTable table = new HTable(conf, tableName);
		Append append = new Append(Bytes.toBytes(rowKey));
		append.add(Bytes.toBytes(family), Bytes.toBytes(qualifier), Bytes.toBytes(value));
		table.append(append);
		System.out.println("append data success!");
	}
	
	/**
	 * 增长数据
	 * @param tableName
	 * @param rowKey
	 * @param family
	 * @param qualifier
	 * @param amount
	 * @throws IOException 
	 */
	public static void incrementData(String tableName, String rowKey, String family, String qualifier, long amount) throws IOException {
		HTable table = new HTable(conf, tableName);
		Increment increment = new Increment(Bytes.toBytes(rowKey));
		increment.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier), amount);
		table.increment(increment);
		System.out.println("increment data success!");
	}
	
	/**
	 * 读取数据
	 * @param tableName
	 * @param rowKey
	 * @throws IOException
	 */
	public static void getOneRow(String tableName, String rowKey) throws IOException{
		HTable table = new HTable(conf, tableName);
		Get get = new Get(rowKey.getBytes());	//设置rowKey
		Result result = table.get(get);
		//打印结果
		for(KeyValue kv : result.raw()){
			System.out.println("\trow: " + new String(kv.getRow()) + " ");
			System.out.println("\tfamily: " + new String(kv.getFamily()) + " ");
			System.out.println("\tqualifier: " + new String(kv.getQualifier()) + " ");
			System.out.println("\ttimestamp: " + kv.getTimestamp() + " ");
			System.out.println("\tvalue: " + new String(kv.getValue()) + " ");
		}
	}
	
	/**
	 * 扫描数据
	 * @param tableName
	 * @param startRow
	 * @param stopRow
	 * @throws IOException
	 */
	public static void scanRows(String tableName, String startRow, String stopRow) throws IOException{
		HTable table = new HTable(conf, tableName);
		//在scan中指定startRow和stopRow
		Scan scan = new Scan(startRow.getBytes(), stopRow.getBytes());
		ResultScanner resultS = table.getScanner(scan);
		//打印扫描结果
		for(Result result : resultS){
			for(KeyValue kv : result.raw()){
				System.out.println("\trow: " + new String(kv.getRow()) + " ");
				System.out.println("\tfamily: " + new String(kv.getFamily()) + " ");
				System.out.println("\tqualifier: " + new String(kv.getQualifier()) + " ");
				System.out.println("\ttimestamp: " + kv.getTimestamp() + " ");
				System.out.println("\tvalue: " + new String(kv.getValue()) + " ");
			}
		}
	}
	
	public static void scanByFilter(String tableName, String family, String qualifier, String value) throws IOException{
		HTable table = new HTable(conf, tableName);
		Scan scan = new Scan();
		scan.addColumn(Bytes.toBytes(family), Bytes.toBytes(qualifier));
		Filter filter = new SingleColumnValueFilter(Bytes.toBytes(family), Bytes.toBytes(qualifier), CompareOp.EQUAL, Bytes.toBytes(value));
		//在scan中设置filter
		scan.setFilter(filter);
		ResultScanner resultS = table.getScanner(scan);
		//打印扫描结果
		for(Result result : resultS){
			System.out.println("row: " + new String(result.getRow()));
			for(KeyValue kv : result.raw()){
				System.out.println("\tfamily: " + new String(kv.getFamily()));
				System.out.println("\tqualifier: " + new String(kv.getQualifier()));
				System.out.println("\ttimestamp: " + kv.getTimestamp() + " ");
				System.out.println("\tvalue: " + new String(kv.getValue()));
			}
		}
	}

}

下一篇:数据仓库Hive的实战(超详细)

如果你喜欢、对你有帮助,点赞+收藏,跟着军哥学知识……

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT路上的军哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值