一、HBase定义
1.1 HBase定义
HBase 是一种分布式、可扩展、支持海量数据存储的 NoSQL 数据库非结构化数据存储的数据库,基于列的模式存储。利用Hadoop HDFS作为其文件存储系统,写入性能很强,读取性能较差。利用Hadoop MapReduce来处理HBase中的海量数据,利用Zookeeper作为协同服务。
关系型数据库存储数据是以表格的形式存储,非关系型数据库是以<k,v>进行存储。通过<k,v>进行存储,当在用key读取value的时候,效率更高,速度更快,使用起来更灵活。
划重点:
HBase是基于列存储的,主要用来存储非结构化和半结构化的松散数据,适合大数据的实时查询;
利用 HDFS作为其文件存储系统;
利用 MapReduce来处理 HBase中的海量数据;
利用 Zookeeper作为其分布式协同服务;
HDFS只支持追加写,不支持随机写,不太适合做大量的随机读应用
HBASE却特别适合随机的读写。
1.2 HBase数据模型
用户将数据行存储在带标签的表中,数据行具有可排序的键和任意数量的列,该表存储稀疏。
HBase关于数据的关键在于:稀疏、分布式、多维、排序的映射map。其中映射map指代非关系型数据库的key-value结构。
释义:
稀疏:对比关系型数据库,关系型数据库是一个表格,表格在底层存储的时候要求比较高,每一行每一列都需要预留对应的存储空间。当数据量比较大、列比较多时,存在大量的空值,使用关系型数据库就会造成存储空间的浪费。
使用非关系型数据库就会节省对应的空间。如果某一行某一列为空,可以不存数据,在空间的使用上就会比较节省。
分布式:海量数据保存在多台机器上。
持久化:将内存中的对象存储在数据库中,或者存储在磁盘文件中。
排序:无序的数据当想要查找时,需要遍历整张表。排序的数据可以按照特定算法进行读取。如二分法查找。
映射:由行键、列键、时间戳作为key,映射中的每个值都是一个未解释(经过序列化,无法用UTF-8编码)的字节数组。
1.2.1 基础模型
![](https://i-blog.csdnimg.cn/blog_migrate/c56f88fc66f4eec9d9c8b14dade6eb6a.png)
Name Space
命名空间,类似于关系型数据库的 DatabBase 概念,每个命名空间下有多个表。HBase 有两个自带的命名空间,分别是 hbase 和 default,hbase 中存放的是 HBase 内置的表, default 表是用户默认使用的命名空间。
Table
类似于关系型数据库的表概念。不同的是,HBase 定义表时只需要声明列族即可,不需要声明具体的列。这意味着,往 HBase 写入数据时,字段可以动态、按需指定。因此,和关系型数据库相比,HBase 能够轻松应对字段变更的场景。
Row
HBase 表中的每行数据都由一个 RowKey 和多个 Column(列)组成,数据是按照 RowKey 的字典顺序存储的,并且查询数据时只能根据 RowKey 进行检索,所以 RowKey 的设计十分重要。
HBase框架不能写SQL,只能根据RowKey去读取数据。
Column
HBase 中的每个列都由 Column Family(列族)和 Column Qualifier(列限定符)进行限定,例如 info:name,info:age。建表时,只需指明列族,而列限定符无需预先定义 。
Time Stamp
用于标识数据的不同版本(version),每条数据写入时,如果不指定时间戳,系统会 自动为其加上该字段,其值为写入 HBase 的时间。
Cell
由{rowkey, column Family:column Qualifier, time Stamp} 唯一确定的单元。cell 中的数据是没有类型的,全部是字节码形式存贮。
1.2.2 模型结构拆解
HBase数十亿行、数百万列的数据需要进行拆分,才能够进行相应的存储。在对其进行拆分的时候,首先按照行,横向进行切分,切分完的结构就是Region(区域)。Region在拆分完之后,会有对应RowKey的范围,每个Region的RowKey范围不一样,相互之间不交叉。
Region用于实现分布式结构。单独的一张表只能存在一个地方,拆分成Region之后可以放到不同的节点上去。
竖向进行切分,切分出来的单位就是store。竖向的切分以列族为单位纵向切分。纵向切分为store用于底层存储到不同的文件夹中,便于文件存储。
1.2.3 物理存储结构
![](https://i-blog.csdnimg.cn/blog_migrate/a7c624b84ea798fbc46fbe68974fabfb.png)
先切分Region(为了划分不同的节点),再切分store(为了拆分文件夹)。一个文件底层是以KV进行编写。key的信息包括行号RowKey、列(列族Colume Family、列名/列限定符)、时间戳、type。
HBase是以HDFS作为存储基础的数据库,而HDFS上的数据是无法进行修改的,只能删除、重写或追加写。那么HBase如何在不能修改数据的基础上实现改数据的功能呢?于是有了时间戳。读取数据的时候有两个时间版本,新的版本会覆盖旧的版本,就会被认为数据已经修改。
1.3 HBase 架构
![](https://i-blog.csdnimg.cn/blog_migrate/c2d7b708de3730ed7ab1048322f8b6dd.png)
Master
主要进程,Master 是所有 Region Server 的管理者,其实现类为 HMaster(服务器上有个HMaster进程)。
功能:负责通过ZK监控RegionServer进程状态,同时是所有元数据变化的接口。内部启动监控执行region的故障转移和拆分的线程。
RegionServer
主要进程,具体实现类为HRegionServer,部署在datanode上。
功能:主要负责数据cell的处理。同时在执行区域的拆分和合并的时候由RegionServer来实际执行。
Zookeeper
HBase 通过 Zookeeper 来做 Master 的高可用、RegionServer 的监控、元数据的入口以及集群配置的维护等工作。
HDFS
HDFS 为 HBase 提供最终的底层数据存储服务,同时为 HBase 提供高可用的支持。
StoreFile/HFile
一个表对应一个文件夹,在一张表中,会切分成多个Region(可以在定义表的时候进行切分),再根据列族进行切分成一个个的store。
![](https://i-blog.csdnimg.cn/blog_migrate/8972166a393bb9d9295588810d8a9c9d.png)
二、HBase基本Shell操作
-- 启动关闭相关
-- 1.启动hbase
bin/start-hbase.sh
-- 2.查看启动情况,
-- 单机版只会有 HMaster 进程
jps
-- 3.关闭hbase
bin/stop-hbase.sh
基础命令:
-- 基础命令
-- 1.进入 HBase 客户端命令行
bin/hbase shell
-- 2.查看帮助命令
help
-- 3.查看当前数据库中有哪些表
list
表空间namespace相关操作:
-- 表空间
-- 1.创建namespace
create_namespace 'nametest'
-- 2.删除namespace
drop_namespace 'nametest'
-- 3.查看namespace
describe_namespace 'nametest'
-- 4.列出所有namespace
list_namespace
-- 5.在namespace下创建表
create 'nametest:testtable', 'fm1'
-- 6.查看namespace下的表
list_namespace_tables 'nametest'
表table相关操作:
增删改查
创建表,表中有两个列族 baseinfo, schoolinfo
create 'bigdata:student','baseinfo','schoolinfo'
查看指定表全名空间中的表
list_namespace_tables 'bigdata'
查看表描述
desc/describe 'bigdata:student'
禁用/启用
disable 'bigdata:student'
enable 'bigdata:student'
查看是否启用/禁用
is_disabled 'bigdata:student'
true
is_enabled 'bigdata:student'
false
删除表 注意,首先要将删除的表设置为禁用状态才可以删除,否则会报错
drop 'bigdata:student'
新增列族
alter 'bigdata:student','teacherinfo'
删除列族
alter 'bigdata:student',{NAME=>'teacherinfo',METHOD=>'delete'}
删除指定列族下的指定列
delete 'bigdata:student','rowkey3','baseinfo:age'
删除指定行
deleteall 'bigdata:student','rowkey3'
增加数据
put 'bigdata:student','rowkey1','baseinfo:name','tom'
put 'bigdata:student','rowkey1','baseinfo:birthday','1999-01-01'
put 'bigdata:student','rowkey1','baseinfo:age','24'
put 'bigdata:student','rowkey1','schoolinfo:name','bdqn'
put 'bigdata:student','rowkey1','schoolinfo:address','jsxueyuan'
put 'bigdata:student','rowkey2','baseinfo:name','jerry'
put 'bigdata:student','rowkey2','baseinfo:birthday','2003-07-02'
put 'bigdata:student','rowkey2','baseinfo:age','20'
put 'bigdata:student','rowkey2','schoolinfo:name','njzb'
put 'bigdata:student','rowkey2','schoolinfo:address','wending'
put 'bigdata:student','rowkey3','baseinfo:name','mands'
put 'bigdata:student','rowkey3','baseinfo:birthday','2022-05-21'
put 'bigdata:student','rowkey3','baseinfo:age','1'
put 'bigdata:student','rowkey3','schoolinfo:name','yey'
put 'bigdata:student','rowkey3','schoolinfo:address','bj'
put 'bigdata:student','rowkey4','baseinfo:name','roboot'
put 'bigdata:student','rowkey4','baseinfo:birthday','2018-12-31'
put 'bigdata:student','rowkey4','baseinfo:age','5'
put 'bigdata:student','rowkey4','schoolinfo:name','xiaoxue'
put 'bigdata:student','rowkey4','schoolinfo:address','shanghai'
版本号设置/查看历史版本号
查看指定列中不同版本的数据
get 'bigdata:student','rowkey2',{COLUMN=>'baseinfo:name','VERSIONS'=>3}
更改列族存储版本的限制
alter 'bigdata:student',{NAME=>'baseinfo',VERSIONS=>3}
条件查询
根据条件查询
get 'bigdata:student','rowkey1'
get 'bigdata:student','rowkey2','baseinfo'
get 'bigdata:student','rowkey2','schoolinfo'
get 'bigdata:student','rowkey2','baseinfo:name'
get 'bigdata:student','rowkey3',{COLUMN=>'baseinfo:name'}
全表扫描
全表扫描
scan 'bigdata:student'
全表扫描指定列族
scan 'bigdata:student', COLUMN=>'baseinfo'
全表扫描指定列族指定列
scan 'bigdata:student', COLUMN=>'baseinfo:birthday'
扫描指定起始行至结束行(不包含)
scan 'bigdata:student',{COLUMNS=>'baseinfo:name', STARTROW=>'rowkey1', STOPROW=>'rowkey4'}
scan 'bigdata:student',{COLUMNS=>'baseinfo:name', STARTROW=>'rowkey1', STOPROW=>'rowkey4', LIMIT=>3}
scan 'bigdata:student',{COLUMNS=>'baseinfo:name', STARTROW=>'rowkey1', STOPROW=>'rowkey4', LIMIT=>3,VERSIONS=>3}
值包含nt
scan 'bigdata:student',FILTER=>"ValueFilter(=,'substring:bdqn')"
值=24
scan 'bigdata:student',FILTER=>"ValueFilter(=,'binary:24')"
列以birth开头的
scan 'bigdata:student',FILTER=>"ColumnPrefixFilter('birth')"
以birth开头,且 值中包含2022
scan 'bigdata:student', FILTER=>"ColumnPrefixFilter('birth') AND ValueFilter(=,'substring:2022')"
以birth开头,且 值中包含2022 或者 1999
三、HBase API
3.1 环境准备
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.3.5</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>2.3.5</version>
</dependency>
3.2 创建连接
根据官方 API 介绍,HBase 的客户端连接由 ConnectionFactory 类来创建,用户使用完成之后需要手动关闭连接。同时连接是一个重量级的,推荐一个进程使用一个连接,对 HBase的命令通过连接中的两个属性 Admin 和 Table 来实现。
3.2.1 单线程创建连接
// 1. 创建配置对象
Configuration conf = new Configuration();
// 2. 添加配置参数
conf.set("hbase.zookeeper.quorum","hadoop102,hadoop103,hadoop104");
// 3. 创建 hbase 的连接
// 默认使用 同步连接
Connection connection = ConnectionFactory.createConnection(conf);
// 可以使用异步连接(不推荐使用)
// 主要影响后续的 DML 操作
CompletableFuture<AsyncConnection> asyncConnection = ConnectionFactory.createAsyncConnection(conf);
// 4. 使用连接
System.out.println(connection);
// 5. 关闭连接
connection.close();
3.2.2 多线程创建连接
// 声明一个静态属性
public static Connection connection = null;
static{
// 1. 创建连接
// 默认使用 同步连接
try {
// 使用读取本地文件的形式添加参数
connection = ConnectionFactory.createConnection();
} catch (IOException e){
e.printStackTrace();
}
}
public static void closeConnection() throws IOException {
// 判断连接是否为null
if (connection != null){
connection.close();
}
}
在 resources 文件夹中创建配置文件 hbase-site.xml,添加以下内容:
<configuration>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hadoop102,hadoop103,hadoop104</value>
</property>
</configuration>
3.3 DDL
创建HBaseDDL类,添加静态方法即可作为工具类。
public class HBaseDDL {
// 添加静态属性 connection 指向单例连接
public static Connection connection = HBaseConnection.connection;
}
3.3.1 创建命名空间
// 创建命名空间
public static void createNamespace(String namespace) throws IOException{
// 1. 获取admin
Admin admin = connection.getAdmin();
// 2. 调用方法创建命名空间
// 代码相对shell更加底层,所以shell能够实现的功能,代码一定能够实现
// 所以需要填写完整的命名空间描述
// 2.1 创建命名空间描述建造者
NamespaceDescription.Builder builder = NamespaceDescription.create(namespace);
// 2.2 给命名空间添加需求
builder.addConfiguration("user","xsqone");
// 2.3 使用builder构造出对应 的添加完参数的对象,完成创建
// 创建命名空间出现的问题都属于方法本身的问题,不应该抛出
try {
admin.createNamespace(builder.build());
} catch (IOException e) {
System.out.println("命令空间已经存在");
e.printStackTrace();
}
// 3. 关闭admin
admin.close();
}
3.3.2 判断表格是否存在
/**
* 创建命名空间
* @param namespace 命名空间名称
*/
public static boolean isTableExists(String namespace,String tableName) throws IOException {
// 1. 获取 admin
Admin admin = connection.getAdmin();
// 2. 使用方法判断表格是否存在
boolean b = false;
try {
b = admin.tableExists(TableName.valueOf(namespace, tableName));
} catch (IOException e) {
e.printStackTrace();
}
// 3. 关闭 admin
admin.close();
// 3. 返回结果
return b;
}
3.3.3 创建表
/**
* 创建表格
* @param namespace 命名空间名称
* @param tableName 表格名称
* @param columnFamilies 列族名称 可以有多个
*/
public static void createTable(String namespace, String tableName, String... columnFamilies){
// 判断是否有至少一个列族
if (columnFamilies.length == 0 ){
System.out.println("创建表格至少有一个列族");
return;
}
// 1. 获取admin
Admin admin = connection.getAdmin();
// 2. 调用方法创建表格
// 2.1 创建表格描述的建造者
TableDescriptorBuilder tableDescriptorBuilder =
TableDescriptorBuilder.newBuilder(TableName.valueOf(namespace, tableName));
// 2.2 添加参数
for (String columnFamily : columnFamilies) {
// 2.3 创建列族描述的建造者
ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder =
ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(columnFamily));
// 2.4 对应当前的列族添加参数
// 添加版本参数
columnFamilyDescriptorBuilder.setMaxVersions(3);
// 2.5 创建添加完参数的列族描述
tableDescriptorBuilder.setColumnFamily(columnFamilyDescriptorBuilder.build());
}
// 2.3 创建对应的表格描述
try {
admin.createTable(tableDescriptorBuilder.build());
} catch (IOException e) {
System.out.println("表格已经存在");
e.printStackTrace();
}
// 3. 关闭admin
admin.close();
}
3.3.4 修改表
/**
* 修改表格中一个列族的版本
* @param namespace 命名空间名称
* @param tableName 表格名称
* @param columnFamily 列族名称
* @param version 版本
*/
public static void modifyTable(String namespace ,String tableName,String columnFamily,int version) throws IOException {
// 判断表格是否存在
if (!isTableExists(namespace,tableName)){
System.out.println("表格不存在无法修改");
return;
}
// 1. 获取admin
Admin admin = connection.getAdmin();
// 2. 调用方法修改表格
// 2.0 获取之前的表格描述
TableDescriptor descriptor = admin.getDescriptor(TableName.valueOf(namespace, tableName));
// 2.1 创建一个表格描述建造者
// 如果使用填写 tableName 的方法 相当于创建了一个新的表格描述建造者 没有之前的信息
// 如果想要修改之前的信息 必须调用方法填写一个旧的表格描述
TableDescriptorBuilder tableDescriptorBuilder = TableDescriptorBuilder.newBuilder(descriptor);
// 2.2 对应建造者进行表格数据的修改
// 创建列族描述建造者
ColumnFamilyDescriptor columnFamily1 = descriptor.getColumnFamily(Bytes.toBytes(columnFamily));
// 创建列族描述建造者
// 需要填写旧的列族描述
ColumnFamilyDescriptorBuilder columnFamilyDescriptorBuilder = ColumnFamilyDescriptorBuilder.newBuilder(columnFamily1);
// 修改对应的版本
columnFamilyDescriptorBuilder.setMaxVersions(version);
// 此处修改的时候 如果填写的新创建 那么别的参数会初始化
tableDescriptorBuilder.modifyColumnFamily(columnFamilyDescriptorBuilder.build());
try {
admin.modifyTable(tableDescriptorBuilder.build());
} catch (IOException e) {
e.printStackTrace();
}
// 3. 关闭 admin
admin.close();
}
3.3.5 删除表
/**
* 删除表格
* @param namespace 命名空间名称
* @param tableName 表格名称
* @return true 表示删除成功
*/
public static boolean deleteTable(String namespace ,String tableName) throws IOException {
// 1. 判断表格是否存在
if (!isTableExists(namespace,tableName)){
System.out.println("表格不存在,无法删除");
return false;
}
// 2. 获取 admin
Admin admin = connection.getAdmin();
// 3. 调用相关的方法删除表格
try {
// HBase 删除表格之前 一定要先标记表格为不可以
TableName tableName1 = TableName.valueOf(namespace, tableName);
admin.disableTable(tableName1);
admin.deleteTable(tableName1);
} catch (IOException e) {
e.printStackTrace();
}
// 4. 关闭 admin
admin.close();
return true;
}
3.4 DML
public class HBaseMDL {
// 静态属性
public static Connection connection = HBaseConnection.connection;
}
3.4.1 插入数据
/**
* 插入数据
* @param namespace 命名空间名称
* @param tableName 表格名称
* @param rowKey 主键
* @param columnFamily 列族名称
* @param columnName 列名
* @param value 值
*/
public static void putCell(String namespace,String tableName,String rowKey, String columnFamily,String columnName,String value) throws IOException {
// 1. 获取 table
Table table = connection.getTable(TableName.valueOf(namespace, tableName));
// 2. 调用相关方法插入数据
// 2.1 创建 put 对象
Put put = new Put(Bytes.toBytes(rowKey));
// 2.2. 给 put 对象添加数据
put.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName),Bytes.toBytes(value));
// 2.3 将对象写入对应的方法
try {
table.put(put);
} catch (IOException e) {
e.printStackTrace();
}
// 3. 关闭 table
table.close();
}
3.4.2 读取数据
/**
* 读取数据 读取对应的一行中的某一列
*
* @param namespace 命名空间名称
* @param tableName 表格名称
* @param rowKey 主键
* @param columnFamily 列族名称
* @param columnName 列名
*/
public static void getCells(String namespace, String tableName, String rowKey, String columnFamily, String columnName) throws IOException {
// 1. 获取 table
Table table = connection.getTable(TableName.valueOf(namespace, tableName));
// 2. 创建 get 对象
Get get = new Get(Bytes.toBytes(rowKey));
// 如果直接调用 get 方法读取数据 此时读一整行数据
// 如果想读取某一列的数据 需要添加对应的参数
get.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columnName));
// 设置读取数据的版本
get.readAllVersions();
try {
// 读取数据,得到 result 对象
Result result = table.get(get);
// 处理数据
Cell[] cells = result.rawCells();
// 测试方法: 直接把读取的数据打印到控制台
// 如果是实际开发 需要再额外写方法 对应处理数据
for (Cell cell : cells) {
// cell 存储数据比较底层
String value = new String(CellUtil.cloneValue(cell));
System.out.println(value);
}
} catch (IOException e) {
e.printStackTrace();
}
// 关闭 table
table.close();
}
3.4.3 扫描数据
/**
* 扫描数据
*
* @param namespace 命名空间
* @param tableName 表格名称
* @param startRow 开始的 row 包含的
* @param stopRow 结束的 row 不包含
*/
public static void scanRows(String namespace, String tableName, String startRow, String stopRow) throws IOException {
// 1. 获取 table
Table table = connection.getTable(TableName.valueOf(namespace, tableName));
// 2. 创建 scan 对象
Scan scan = new Scan();
// 如果此时直接调用 会直接扫描整张表
// 添加参数 来控制扫描的数据
// 默认包含
scan.withStartRow(Bytes.toBytes(startRow));
// 默认不包含
scan.withStopRow(Bytes.toBytes(stopRow));
try {
// 读取多行数据 获得 scanner
ResultScanner scanner = table.getScanner(scan);
// result 来记录一行数据 cell 数组
// ResultScanner 来记录多行数据 result 的数组
for (Result result : scanner) {
Cell[] cells = result.rawCells();
for (Cell cell : cells) {
System.out.print (new
String(CellUtil.cloneRow(cell)) + "-" + new
String(CellUtil.cloneFamily(cell)) + "-" + new
String(CellUtil.cloneQualifier(cell)) + "-" + new
String(CellUtil.cloneValue(cell)) + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
// 3. 关闭 table
table.close();
}
3.4.4 带过滤扫描
/**
* 带过滤的扫描
*
* @param namespace 命名空间
* @param tableName 表格名称
* @param startRow 开始 row
* @param stopRow 结束 row
* @param columnFamily 列族名称
* @param columnName 列名
* @param value value 值
* @throws IOException
*/
public static void filterScan(String namespace, String tableName, String startRow, String stopRow, String columnFamily, String columnName, String value) throws IOException {
// 1. 获取 table
Table table = connection.getTable(TableName.valueOf(namespace, tableName));
// 2. 创建 scan 对象
Scan scan = new Scan();
// 如果此时直接调用 会直接扫描整张表
// 添加参数 来控制扫描的数据
// 默认包含
scan.withStartRow(Bytes.toBytes(startRow));
// 默认不包含
scan.withStopRow(Bytes.toBytes(stopRow));
// 可以添加多个过滤
FilterList filterList = new FilterList();
// 创建过滤器
// (1) 结果只保留当前列的数据
ColumnValueFilter columnValueFilter = new ColumnValueFilter(
// 列族名称
Bytes.toBytes(columnFamily),
// 列名
Bytes.toBytes(columnName),
// 比较关系
CompareOperator.EQUAL,
// 值
Bytes.toBytes(value)
);
// (2) 结果保留整行数据
// 结果同时会保留没有当前列的数据
SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(
// 列族名称
Bytes.toBytes(columnFamily),
// 列名
Bytes.toBytes(columnName),
// 比较关系
CompareOperator.EQUAL,
// 值
Bytes.toBytes(value)
);
// 本身可以添加多个过滤器
filterList.addFilter(singleColumnValueFilter);
// 添加过滤
scan.setFilter(filterList);
try {
// 读取多行数据 获得 scanner
ResultScanner scanner = table.getScanner(scan);
// result 来记录一行数据 cell 数组
// ResultScanner 来记录多行数据 result 的数组
for (Result result : scanner) {
Cell[] cells = result.rawCells();
for (Cell cell : cells) {
System.out.print(new
String(CellUtil.cloneRow(cell)) + "-" + new
String(CellUtil.cloneFamily(cell)) + "-" + new
String(CellUtil.cloneQualifier(cell)) + "-" + new
String(CellUtil.cloneValue(cell)) + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
// 3. 关闭 table
table.close();
}
3.4.5 删除数据
/**
* 删除 column 数据
*
* @param nameSpace
* @param tableName
* @param rowKey
* @param family
* @param column
* @throws IOException
*/
public static void deleteColumn(String nameSpace, String tableName, String rowKey, String family, String column) throws IOException {
// 1.获取 table
Table table = connection.getTable(TableName.valueOf(nameSpace, tableName));
// 2.创建 Delete 对象
Delete delete = new Delete(Bytes.toBytes(rowKey));
// 3.添加删除信息
// 3.1 addColumn 删除单个版本
delete.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes(columnName));
// 3.2 addColumns 删除所有版本
delete.addColumns(Bytes.toBytes(columnFamily), Bytes.toBytes(columnName));
// 3.3 删除列族
delete.addFamily(Bytes.toBytes(family));
// 3.删除数据
try {
table.delete(delete);
} catch (IOException e) {
e.printStackTrace();
}
// 5.关闭资源
table.close();
}