目录
- HBaseUtil工具类
- API介绍
- 获取表
- 存储数据
- 获取数据
- 批量存储数据
- 批量获取数据
- 删除数据
- 最终代码
HBaseUtil工具类
前面我们实现了Flink整合Kafka,可以从Kafka中获取数据进行分析,分析之后我们要把结果存入HBase中,为了方便操作,我们先提前编写一个操作HBase的工具类。HBase作为一个数据库,我们肯定要进行数据的增删改查,那么我们就围绕这几个操作进行开发。
API介绍
先来看下我们要编写的工具类的所有方法,我们先明确了目标,再进行开发。
方法名 | 用途 | 参数说明 | 返回值 |
getTable | 创建/获取表 | tableNameStr:表名 columnFamily:列族名 | HBase Table对象 |
putData | 插入/更新一列数据 | tableNameStr: 表名 rowkey:String rowkey columnFamily:列族名 column:String 列名 data:String 列值 | 空 |
putMapData | 插入/更新多个列数据 | tableNameStr: 表名 rowkey:String rowkey columnFamily:列族名 mapData:列名/列值 | 空 |
getData | 根据rowkey,列族+列名 获取单列数据 | tableNameStr: 表名 rowkey:String rowkey columnFamily:列族名 column:列名 | 列对应的数据 String类型 |
getMapData | 根据rowkey,列族+列名集合 获取多列数据 | tableNameStr: 表名 rowkey:String rowkey columnFamily:列族名 column:列名集合 | 列对应的数据 Map[列名, 列值] |
deleteData | 根据rowkey删除一条数据 | tableNameStr: 表名 rowkey:rowkey columnFamily: 列族名 | 空 |
HBase操作基本类 | |||
类名 | 用途 | 获取方式 | |
– | – | – | |
Configuration | HBase的配置类 | HBaseConfiguration.create | |
Connection | 连接 | ConnectionFactory.createConnection(conf) | |
Admin | HBase的操作API | Connection.getAdmin | |
Table | 用来链接HBase的单表 | Connection.getTable() | |
Get | 用来查询HBase的单行数据 | new Get(rowkey.getBytes()) | |
Put | 保存单行数据 | new Put(rowkey.getBytes()) | |
Delete | 删除单行数据 | new Delete(rowkey.getBytes()) |
获取表
开发步骤:
- 将导入
hbase-site.xml
配
置文件到resources
目录 - 在
util
包中添加HBaseUtil
- 使用
HBaseConfiguration.create
获取配置对象Configuration
,该配置对象会自动加载hbase-site.xml - 使用
ConnectionFactory.createConnection
获取hbase连接 - 使用
Connection.getAdmin
获取与master的连接
- 创建
getTable
方法
- 构建
TableName
- 构建
TableDescriptorBuilder
- 构建
ColumnFamilyDescriptor
- 添加列族
- 检查表是否存在,若不存在,则创建表
源码解析:
我们可以围绕Admin来展开源码的查看,请观察下图,通过源码的注释,我们可以很简单的找到该编写的代码。
示例代码:
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client._
object HBaseUtil {
// 读取配置文件
val conf: Configuration = HBaseConfiguration.create
// 创建连接
val conn: Connection = ConnectionFactory.createConnection(conf)
// 创建HBase管理类
val admin: Admin = conn.getAdmin
/**
* 获得表,如果表不存在则创建
*
* @param tableNameStr 表名
* @param columnFamilyName 列族名
* @return
*/
def getTable(tableNameStr: String, columnFamilyName: String): Table = {
// 获取 TableName
val tableName: TableName = TableName.valueOf(tableNameStr)
//判断表是否可用
if (!admin.tableExists(tableName)) {
// 构建TableDescriptorBuilder
val tableDescriptor: TableDescriptorBuilder = TableDescriptorBuilder.newBuilder(tableName)
// 构建列族 ColumnFamilyDescriptor
val columnFamily: ColumnFamilyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(columnFamilyName.getBytes).build()
tableDescriptor.setColumnFamily(columnFamily)
// 创建表
admin.createTable(tableDescriptor.build())
}
// 返回表
conn.getTable(tableName)
}
存储数据
创建putData
方法
- 调用getTable获取表
- 构建
Put
对象 - 添加列、列值
- 对table执行put操作
- 启动编写main进行测试
/**
* 保存数据
*
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamilyName 列族名
* @param columnName 列名
* @param columnValue 列值
*/
def putData(tableNameStr: String,
rowkey: String,
columnFamilyName: String,
columnName: String,
columnValue: String
) = {
val table = getTable(tableNameStr, columnFamilyName)
try {
// Put
val put = new Put(rowkey.getBytes())
// 参数1: 列族 参数2: 列名 参数3: 列值
put.addColumn(columnFamilyName.getBytes, columnName.getBytes, columnValue.getBytes)
// 保存数据
table.put(put)
} catch {
case ex: Exception => {
ex.printStackTrace()
}
} finally {
// 关闭table
table.close()
}
}
获取数据
- 使用
Connection
获取表 - 创建
getData
方法
- 调用getTable获取表
- 构建
Get
对象 - 对table执行get操作,获取result
- 使用Result.getValue获取列族列对应的值
- 捕获异常
- 关闭表
- 启动
hhbase
- 启动编写main进行测试
/**
* 查询数据
*
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamilyName 列族名
* @param columnName 列名
*/
def getData(tableNameStr: String,
rowkey: String,
columnFamilyName: String,
columnName: String) = {
val table: Table = getTable(tableNameStr, columnFamilyName)
try {
// Get对象
val get: Get = new Get(rowkey.getBytes)
// 查询结果
val result = table.get(get)
// 结果不为空, 并且结果包含我们要查询的列
if (result != null && result.containsColumn(columnFamilyName.getBytes, columnName.getBytes)) {
// - 使用Result.getValue获取列族列对应的值
val colValueBytes: Array[Byte] = result.getValue(columnFamilyName.getBytes, columnName.getBytes)
Bytes.toString(colValueBytes)
}else {
""
}
} catch {
case ex: Exception =>
ex.printStackTrace()
""
} finally {
// - 关闭表
table.close()
}
}
批量存储数据
创建putMapData
方法
- 调用
getTable
获取表 - 构建
Put
对象 - 添加Map中的列、列值
- 对table执行put操作
- 捕获异常
- 关闭表
- 启动编写main进行测试
/**
* 批量存储数据
*
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamilyName 列族名
* @param map key/value集合
*/
def putMapData(tableNameStr: String,
rowkey: String,
columnFamilyName: String,
map: Map[String, Any]
) = {
val table = getTable(tableNameStr, columnFamilyName)
try {
//- 添加Map中的列、列值
for ((columnName, columnValue) <- map) {
// Put
val put = new Put(rowkey.getBytes())
put.addColumn(columnFamilyName.getBytes, columnName.getBytes, columnValue.toString.getBytes)
table.put(put)
}
} catch {
case ex: Exception => {
ex.printStackTrace()
}
} finally {
table.close()
}
}
批量获取数据
创建putMapData
方法
- 调用
getTable
获取表 - 构建
Get
对象 - 根据Get对象查询表
- 构建可变Map
- 遍历查询各个列的列值
- 过滤掉不符合的结果
- 把结果转换为Map返回
- 捕获异常
- 关闭表
- 启动编写main进行测试
/**
* 批量获取列的数据
*
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamily 列族
* @param columnList 列的名字列表
* @return
*/
def getMapData(tableNameStr: String, rowkey: String, columnFamily: String, columnList: List[String]): Map[String, String] = {
// 根据表名和列族名获取表
val table: Table = getTable(tableNameStr, columnFamily)
try {
// 创建Get对象
val get: Get = new Get(rowkey.getBytes)
// 根据Get对象查询表
val result: Result = table.get(get)
// 构建可变Map
val valueMap = collection.mutable.Map[String, String]()
// 遍历要查询的列集合
columnList.map {
col =>
// 从表查询结果中,根据列族,列名提取出列值
val values: Array[Byte] = result.getValue(columnFamily.getBytes, col.getBytes)
// 列值不为空 , 则设置 k-> v
if (values != null && values.size > 0) {
col -> Bytes.toString(values)
}
else {
"" -> ""
}
}.filter(_._1 != "").toMap // 过滤掉key为""的内容,并转换为Map类型
} catch {
case e: Exception =>
e.printStackTrace()
Map[String, String]()
} finally {
table.close()
}
}
删除数据
创建deleteData
方法
- 调用
getTable
获取表 - 构建
Delete
对象 - 对table执行delete操作
- 捕获异常
- 关闭表
- 启动编写main进行测试
/**
* 删除数据
*
* @param tableNameStr 表名
* @param columnFamilyName 列族名
* @param rowkey rowkey
*/
def deleteData(tableNameStr: String,
rowkey: String,
columnFamilyName: String
) = {
// 获取表
val table = getTable(tableNameStr, columnFamilyName)
try {
// 创建Delete对象
val delete = new Delete(rowkey.getBytes)
table.delete(delete)
} catch {
case ex: Exception =>
ex.printStackTrace()
} finally {
table.close()
}
}
main方法测试代码
object HBaseUtil {
def main(args: Array[String]): Unit = {
// 测试存入单列数据
putData("test", "123", "info", "t1", "hello world")
// 测试存入多列数据
val map = Map(
"t2" -> "scala",
"t3" -> "hive",
"t4" -> "sqoop"
)
putMapData("test", "123", "info", map)
println(getData("test", "123", "info", "t1"))
println(getData("test", "123", "info", "t2"))
println(getData("test", "123", "info", "t3"))
println(getData("test", "123", "info", "t4"))
println(getMapData("test", "123", "info", List("t1", "t2","t3","t4")))
deleteData("test", "123", "info")
}
}
最终代码
import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.{HBaseConfiguration, TableName}
import org.apache.hadoop.hbase.client.{Admin, ColumnFamilyDescriptorBuilder, Connection, ConnectionFactory, Delete, Get, Put, Result, Table, TableDescriptor, TableDescriptorBuilder}
import org.apache.hadoop.hbase.util.Bytes
/**
* HBase工具类
*
* 获取Table
* 保存单列数据
* 查询单列数据
* 保存多列数据
* 查询多列数据
* 删除数据
*/
object HBaseUtil {
//HBase的配置类,不需要指定配置文件名,文件名要求是hbase-site.xml
val conf:Configuration = HBaseConfiguration.create()
//hbase的连接
val conn:Connection = ConnectionFactory.createConnection()
//hbase的api
val admin:Admin = conn.getAdmin
/**
* 返回table,如果不存在,则创建表
* @param tableNameStr
* @param columnFamilyName
* @return
*/
def getTable(tableNameStr:String,columnFamilyName:String):Table={
//获取TableName
val tableName = TableName.valueOf(tableNameStr)
//如果表不存在,则创建表
if (!admin.tableExists(tableName)){
//构建出 表的描述的建造者
val descBuilder = TableDescriptorBuilder.newBuilder(tableName)
val familyDescriptor = ColumnFamilyDescriptorBuilder.newBuilder(columnFamilyName.getBytes).build()
//给表去添加列族
descBuilder.setColumnFamily(familyDescriptor)
//创建表
admin.createTable(descBuilder.build())
}
conn.getTable(tableName)
}
/**
*存储单列数据
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamilyName 列族名
* @param columnName 列名
* @param columnValue 列值
*/
def putData(tableNameStr:String,rowkey:String,columnFamilyName:String,columnName:String,columnValue:String): Unit ={
//获取表
val table = getTable(tableNameStr, columnFamilyName)
try{
//Put
val put = new Put(rowkey.getBytes())
put.addColumn(columnFamilyName.getBytes(),columnName.getBytes(),columnValue.getBytes())
//保存数据
table.put(put)
}catch {
case ex:Exception=>{
ex.printStackTrace()
}
}finally {
table.close()
}
}
/**
* 通过单列获取列值
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamilyName 列族名
* @param columnName 列明
* @return 列值
*/
def getData(tableNameStr: String,
rowkey: String,
columnFamilyName: String,
columnName: String) = {
val table: Table = getTable(tableNameStr, columnFamilyName)
try {
// Get对象
val get: Get = new Get(rowkey.getBytes)
// 查询结果
val result = table.get(get)
// 结果不为空, 并且结果包含我们要查询的列
if (result != null && result.containsColumn(columnFamilyName.getBytes, columnName.getBytes)) {
// - 使用Result.getValue获取列族列对应的值
val colValueBytes: Array[Byte] = result.getValue(columnFamilyName.getBytes, columnName.getBytes)
Bytes.toString(colValueBytes)
}else {
""
}
} catch {
case ex: Exception =>
ex.printStackTrace()
""
} finally {
// - 关闭表
table.close()
}
}
/**
* 批量存储数据
*
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamilyName 列族名
* @param map key/value集合
*/
def putMapData(tableNameStr: String,
rowkey: String,
columnFamilyName: String,
map: Map[String, Any]
) = {
val table = getTable(tableNameStr, columnFamilyName)
try {
//- 添加Map中的列、列值
for ((columnName, columnValue) <- map) {
// Put
val put = new Put(rowkey.getBytes())
put.addColumn(columnFamilyName.getBytes, columnName.getBytes, columnValue.toString.getBytes)
table.put(put)
}
} catch {
case ex: Exception => {
ex.printStackTrace()
}
} finally {
table.close()
}
}
/**
* 删除数据
*
* @param tableNameStr 表名
* @param columnFamilyName 列族名
* @param rowkey rowkey
*/
def deleteData(tableNameStr: String,
rowkey: String,
columnFamilyName: String
) = {
// 获取表
val table = getTable(tableNameStr, columnFamilyName)
try {
// 创建Delete对象
val delete = new Delete(rowkey.getBytes)
table.delete(delete)
} catch {
case ex: Exception =>
ex.printStackTrace()
} finally {
table.close()
}
}
/**
* 批量获取列的数据
*
* @param tableNameStr 表名
* @param rowkey rowkey
* @param columnFamily 列族
* @param columnList 列的名字列表
* @return
*/
def getMapData(tableNameStr: String, rowkey: String, columnFamily: String, columnList: List[String]): Map[String, String] = {
// 根据表名和列族名获取表
val table: Table = getTable(tableNameStr, columnFamily)
try {
// 创建Get对象
val get: Get = new Get(rowkey.getBytes)
// 根据Get对象查询表
val result: Result = table.get(get)
// 构建可变Map
val valueMap = collection.mutable.Map[String, String]()
// 遍历要查询的列集合
columnList.map {
col =>
// 从表查询结果中,根据列族,列名提取出列值
val values: Array[Byte] = result.getValue(columnFamily.getBytes, col.getBytes)
// 列值不为空 , 则设置 k-> v
if (values != null && values.size > 0) {
col -> Bytes.toString(values)
}
else {
"" -> ""
}
}.filter(_._1 != "").toMap // 过滤掉key为""的内容,并转换为Map类型
} catch {
case e: Exception =>
e.printStackTrace()
Map[String, String]()
} finally {
table.close()
}
}
def main(args: Array[String]): Unit = {
// println(getTable("test", "info"))
// putData("test","1","info","t1","hello")
// println(getData("test", "1", "info", "t1"))
/* val map = Map(
"t2" -> "scala",
"t3" -> "hive",
"t4" -> "sqoop"
)
putMapData("test", "123", "info", map)*/
deleteData("test", "123", "info")
println(getMapData("test", "123", "info", List("t1", "t2","t3","t4")))
}
}