08-HBase环境搭建
星期一, 4月 7, 2025 | 7分钟阅读

关于Linux系统大数据环境搭建——08-HBase环境搭建。
08-HBase环境搭建
HBase版本:HBase2.5.3
集群搭建
目标环境
前提:Hadoop 正常运行,ZooKeeper 正常运行,Hive 正常运行,服务器时间同步。
安装
解压
将准备好的安装包上传至 node01,然后解压:
[root@node01 ~]# tar -zxvf hbase-2.5.3-bin.tar.gz -C /opt/yjx/
[root@node01 ~]# rm hbase-2.5.3-bin.tar.gz -rf
修改配置文件
修改环境配置文件 hbase-env.sh
:
[root@node01 ~]# cd /opt/yjx/hbase-2.5.3/conf/
[root@node01 conf]# vim hbase-env.sh
在文件末尾添加以下内容:
export JAVA_HOME=/usr/java/jdk1.8.0_351-amd64
export HADOOP_HOME=/opt/yjx/hadoop-3.3.4/
export HBASE_MANAGES_ZK=false
export HBASE_LOG_DIR=${HBASE_HOME}/logs
# HBase 的 Jar 包和 Hadoop 的 Jar 包会有冲突,会导致服务启动失败。设置以下参数禁止启动时扫描 Hadoop 的 Jar包
export HBASE_DISABLE_HADOOP_CLASSPATH_LOOKUP="true"
修改配置文件 hbase-site.xml
:
[root@node01 conf]# vim hbase-site.xml
首先删除 `configuration` 节点中的所有内容,然后再在 `configuration `节点中添加以下内容:
<!-- 设置 HBase 数据存储的位置(存储在 HDFS 上的位置) -->
<!-- 使用本地文件系统例如:file:///root/hbase/data -->
<property>
<name>hbase.rootdir</name>
<value>hdfs://hdfs-yjx/hbase</value>
</property>
<!-- 是否为分布式模式部署,true 表示分布式部署 -->
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<!-- 设置 HBase 的 ZK 集群地址,以逗号分隔 -->
<property>
<name>hbase.zookeeper.quorum</name>
<value>node01,node02,node03:2181</value>
</property>
<!-- 设置 HBase 在 ZK 上的数据根目录 znode 节点名称 -->
<property>
<name>zookeeper.znode.parent</name>
<value>/hbase</value>
</property>
<!-- 本地文件系统的临时目录,默认在 /tmp,/tmp 会在服务器重启时被清除,一般配置成本地文件模式时才需要设置 -->
<property>
<name>hbase.tmp.dir</name>
<value>/var/yjx/hbase</value>
</property>
<!-- 控制 HBase 是否检查流功能(hflush/hsync),如果要在 HDFS 系统上运行,请禁用此选项 -->
<!-- 简单的理解就是:使用 HDFS 存储将其设置为 false,使用本地文件系统将其设置为 true -->
<property>
<name>hbase.unsafe.stream.capability.enforce</name>
<value>false</value>
</property>
修改 regionservers
:
[root@node01 conf]# vim regionservers
用以下内容替换文件内容:
node01
node02
node03
添加备用主机 backup-masters
:
[root@node01 conf]# vim backup-masters
用以下内容替换文件内容:
node02
拷贝 Hadoop 配置文件至 HBase。
[root@node01 conf]# cp /opt/yjx/hadoop-3.3.4/etc/hadoop/core-site.xml /opt/yjx/hbase-2.5.3/conf/
[root@node01 conf]# cp /opt/yjx/hadoop-3.3.4/etc/hadoop/hdfs-site.xml /opt/yjx/hbase-2.5.3/conf/
拷贝至其他节点
将 node01 已配置好的 HBase 拷贝至 node02 和 node03。
[root@node02 ~]# scp -r root@node01:/opt/yjx/hbase-2.5.3 /opt/yjx/
[root@node03 ~]# scp -r root@node01:/opt/yjx/hbase-2.5.3 /opt/yjx/
# 或者使用分发脚本
[root@node01 ~]# yjxrsync /opt/yjx/hbase-2.5.3
修改环境变量
三个节点修改环境变量 vim /etc/profile
,在文件末尾添加以下内容:
export HBASE_HOME=/opt/yjx/hbase-2.5.3
export PATH=$HBASE_HOME/bin:$PATH
修改完成后 source /etc/profile
重新加载环境变量。
启动
启动 ZooKeeper(三台机器都需要执行)。
zkServer.sh start
zkServer.sh status
启动 HDFS。
[root@node01 \~]# start-all.sh
启动 HBase。
[root@node01 \~]# start-hbase.sh
访问
先使用jps
命令查看各节点服务运行情况。
Web 访问:http://node01:16010 结果如下。
Web 访问:http://node02:16010 结果如下。
关闭
先关闭 HBase。
[root@node01 ~]# stop-hbase.sh
再关闭 HDFS。
[root@node01 ~]# stop-all.sh
再关闭 ZooKeeper(三台机器都需要执行)。
zkServer.sh stop
环境搭建成功后删除安装包, shutdown -h now
关机拍摄快照。
框架整合
HBase 和 MapReduce
添加依赖
在之前的 hbase-demo
项目中添加hbase-mapreduce
依赖。
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-mapreduce</artifactId>
<version>${hbase.version}</version>
</dependency>
完整 pom.xml 文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yjxxt</groupId>
<artifactId>hbase-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<!-- Hadoop 版本控制 -->
<hadoop.version>3.3.4</hadoop.version>
<!-- HBase 版本控制 -->
<hbase.version>2.5.3</hbase.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-auth</artifactId>
<version>${hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>${hbase.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-server</artifactId>
<version>${hbase.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-mapreduce</artifactId>
<version>${hbase.version}</version>
</dependency>
<!-- JUnit 单元测试 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
创建数据库
将 harry potter.txt
文件上传至 HDFS 的 /yjx/harry potter.txt
。
在 HBase 中创建 t_wordcount
表并添加 word
列族。
hbase> create 't_wordcount', 'word'
Hdfs2HBase
编写 Job、Mapper、Reducer。
Hdfs2HBaseWordCountJob.java
package com.yjxxt.hbase.mapred.hdfs2hbase;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import java.io.IOException;
public class Hdfs2HBaseWordCountJob {
public static void main(String[] args) throws IOException,
InterruptedException, ClassNotFoundException {
// 加载配置文件
Configuration configuration = HBaseConfiguration.create();
// 本地模式运行
configuration.set("mapreduce.framework.name", "local");
// 创建作业并设置作业名称
Job job = Job.getInstance(configuration, "yjx-hdfs2hbase-" + System.currentTimeMillis());
// 设置作业主类
job.setJarByClass(Hdfs2HBaseWordCountJob.class);
// 设置 Reduce 的数量
job.setNumReduceTasks(2);
// 设置数据的输入路径(需要计算的数据从哪里读)
FileInputFormat.setInputPaths(job, new Path("/yjx/harry potter.txt"));
// 设置 Map 的输出的 Key 和 Value 的类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 设置 Map 的处理类
job.setMapperClass(Hdfs2HBaseWordCountMapper.class);
// 设置 Reduce 写出到 HBase 的数据库
TableMapReduceUtil.initTableReducerJob("t_wordcount",
Hdfs2HBaseWordCountReducer.class, job, null, null, null, null, false);
job.waitForCompletion(true);
}
}
Hdfs2HBaseWordCountMapper.java
package com.yjxxt.hbase.mapred.hdfs2hbase;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class Hdfs2HBaseWordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
private IntWritable one = new IntWritable(1);
/**
* @param key 前行的偏移量
* @param value 当前行的数据
* @param context 可以理解为环形数据缓冲区
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// 替换特殊字符
String line = value.toString().replaceAll("[^\\w'-]+", " ");
// 切分字符串
String[] words = line.split("\\s+");
// 写出数据
for (String word : words) {
context.write(new Text(word), one);
}
}
}
Hdfs2HBaseWordCountReducer.java
package com.yjxxt.hbase.mapred.hdfs2hbase;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import java.io.IOException;
public class Hdfs2HBaseWordCountReducer extends TableReducer<Text, IntWritable, ImmutableBytesWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
// 声明计数器
int count = 0;
// 循环处理
for (IntWritable value : values) {
count += value.get();
}
// 创建插入数据对象 Put
// 初始化 RowKey
Put put = new Put(Bytes.toBytes("harry_potter_" + key.toString()));
// 列族和列
put.addColumn(Bytes.toBytes("word"), Bytes.toBytes(key.toString()), Bytes.toBytes(String.valueOf(count)));
// 写出数据
context.write(null, put);
}
}
HBase2Hdfs
Mock 数据
使用以下程序生成一批随机的手机通话记录。
package com.yjxxt.phone;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@DisplayName("手机通话记录生成测试类")
public class PhoneRecordTest {
/**
* HBase 的管理对象
*/
private Admin admin;
/**
* 数据库连接
*/
private Connection connection;
/**
* 表对象
*/
private Table table;
/**
* 表名
*/
private final static String TABLE_NAME = "t_phone";
/**
* 列族
*/
private final static String COLUMN_FAMILY_NAME = "info";
@DisplayName("创建数据库连接并初始化管理类和数据库表")
@BeforeEach
public void init() throws IOException {
// 初始化 HBase 配置类
Configuration configuration = HBaseConfiguration.create();
// 创建数据库连接
connection = ConnectionFactory.createConnection(configuration);
// 初始化 HBase 管理类
admin = connection.getAdmin();
// 获取数据库表
table = connection.getTable(TableName.valueOf(TABLE_NAME));
}
@DisplayName("释放 HBase 资源")
@AfterEach
public void destory() throws IOException {
if (table != null) {
table.close();
}
if (admin != null) {
admin.close();
}
if (connection != null) {
connection.close();
}
}
@DisplayName("创建含有预分区的表")
@Test
public void createTable() throws IOException {
// 获取表
TableDescriptorBuilder table = TableDescriptorBuilder.newBuilder(TableName.valueOf(TABLE_NAME));
// 创建列族
ColumnFamilyDescriptorBuilder columnBuilder = ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(COLUMN_FAMILY_NAME));
ColumnFamilyDescriptor familyDescriptor = columnBuilder.build();
// 将列族添加到表对象
table.setColumnFamily(familyDescriptor);
// 获取预分区
byte[][] phoneRange = createPhoneSplits();
// 创建表对象
admin.createTable(table.build(), phoneRange);
}
@DisplayName("批量插入手机通话记录")
@Test
public void putPhoneRecords() throws IOException {
// 创建一个容器
List<Put> puts = new ArrayList<>();
// 批量插入数据
for (int i = 0; i < 100; i++) {
// 随机生成一个手机号码
String phone = getRandomPhone();
// 开始随机生成通话记录
for (int j = 0; j < 100; j++) {
// 随机生成数据
String otherphone = getRandomPhone();
Date date = getRandomDate();
// 创建插入对象
Put put = new Put(Bytes.toBytes(phone + "_" + date.getTime()));
put.addColumn(Bytes.toBytes(COLUMN_FAMILY_NAME), Bytes.toBytes("otherphone"), Bytes.toBytes(otherphone));
put.addColumn(Bytes.toBytes(COLUMN_FAMILY_NAME), Bytes.toBytes("time"), Bytes.toBytes(getRandomNum(1, 3600 * 3)));
put.addColumn(Bytes.toBytes(COLUMN_FAMILY_NAME), Bytes.toBytes("date"), Bytes.toBytes(date.getTime()));
put.addColumn(Bytes.toBytes(COLUMN_FAMILY_NAME), Bytes.toBytes("type"), Bytes.toBytes(String.valueOf(getRandomNum(0, 1))));
// 添加至容器
puts.add(put);
}
}
// 将数据插入到数据库
table.put(puts);
}
@DisplayName("扫描数据")
@Test
public void scanPhoneRecords() throws Exception {
// 创建扫描对象
Scan scan = new Scan();
// 本次查询开始的 RowKey 和结束的 RowKey
String startRow = "138";
String endRow = "139";
scan.withStartRow(Bytes.toBytes(startRow));
scan.withStopRow(Bytes.toBytes(endRow));
// 创建结果扫描器
ResultScanner resultScanner = table.getScanner(scan);
// 获取所有的结果
for (Result result : resultScanner) {
// 获取 Cell
List<Cell> cells = result.listCells();
for (Cell cell : cells) {
String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
if (qualifier.equals("date")) {
System.out.println(Bytes.toString(CellUtil.cloneRow(cell)) + ":" + Bytes.toString(CellUtil.cloneFamily(cell)) + ":" + Bytes.toString(CellUtil.cloneQualifier(cell)) + ":" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(Bytes.toLong(CellUtil.cloneValue(cell)))));
} else if (qualifier.equals("time")) {
System.out.println(Bytes.toString(CellUtil.cloneRow(cell)) + ":" + Bytes.toString(CellUtil.cloneFamily(cell)) + ":" + Bytes.toString(CellUtil.cloneQualifier(cell)) + ":" + Bytes.toInt(CellUtil.cloneValue(cell)));
} else {
System.out.println(Bytes.toString(CellUtil.cloneRow(cell)) + ":" + Bytes.toString(CellUtil.cloneFamily(cell)) + ":" + Bytes.toString(CellUtil.cloneQualifier(cell)) + ":" + Bytes.toString(CellUtil.cloneValue(cell)));
}
}
}
resultScanner.close();
}
/**
* 创建手机号码通讯记录表的预分区
*
* @return
*/
private byte[][] createPhoneSplits() {
String[] telArrays = "134,135,136,137,138,139,150,151,152,157,158,159,130,131,132,155,156,133,153".split(",");
// 对数组进行排序
Arrays.sort(telArrays);
// 创建分区
byte[][] phoneSplits = new byte[telArrays.length][];
for (int i = 0; i < telArrays.length; i++) {
phoneSplits[i] = Bytes.toBytes(telArrays[i]);
}
return phoneSplits;
}
/**
* 随机生成手机号码
*
* @return
*/
private static String getRandomPhone() {
String[] telArrays = "134,135,136,137,138,139,150,151,152,157,158,159,130,131,132,155,156,133,153".split(",");
int index = getRandomNum(0, telArrays.length - 1);
String first = telArrays[index];
String second = String.valueOf(getRandomNum(1, 888) + 10000).substring(1);
String third = String.valueOf(getRandomNum(1, 9100) + 10000).substring(1);
return first + second + third;
}
/**
* 生成随机数字
*
* @param start
* @param end
* @return
*/
public static int getRandomNum(int start, int end) {
return (int) (Math.random() * (end - start + 1) + start);
}
/**
* 随机获取日期
*
* @return
*/
private static Date getRandomDate() {
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date start = format.parse("2021-01-01");
Date end = format.parse("2022-01-01");
if (start.getTime() >= end.getTime()) {
return null;
}
long date = random(start.getTime(), end.getTime());
return new Date(date);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 随机生成数据
*
* @param begin
* @param end
* @return
*/
private static long random(long begin, long end) {
long rtn = begin + (long) (Math.random() * (end - begin));
if (rtn == begin || rtn == end) {
return random(begin, end);
}
return rtn;
}
}
编码
编写 Job、Mapper、Reducer。
HBase2HdfsPhoneJob.java
package com.yjxxt.hbase.mapred.hbase2hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class HBase2HdfsPhoneJob {
public static void main(String[] args) throws IOException,
ClassNotFoundException, InterruptedException {
// 加载配置文件
Configuration configuration = HBaseConfiguration.create();
// 本地模式运行
configuration.set("mapreduce.framework.name", "local");
// 创建作业并设置作业名称
Job job = Job.getInstance(configuration, "yjx-hbase2hdfs-" + System.currentTimeMillis());
// 设置当前任务的主类
job.setJarByClass(HBase2HdfsPhoneJob.class);
// 设置 Reduce 的数量
job.setNumReduceTasks(2);
// 设置数据的输出路径(计算后的数据输出到哪里)
FileOutputFormat.setOutputPath(job, new Path("/yjx/result/" + job.getJobName()));
// 设置扫描器
Scan scan = new Scan();
scan.withStartRow("138".getBytes());
scan.withStopRow("139".getBytes());
// 设置 Map 从 HBase 读取数据至 HDFS
TableMapReduceUtil.initTableMapperJob("t_phone", scan,
HBase2HdfsPhoneMapper.class, Text.class, IntWritable.class, job, false);
// 设置 Reduce 的处理类
job.setReducerClass(HBase2HdfsPhoneReducer.class);
// 将作业提交到集群并等待完成
job.waitForCompletion(true);
}
}
HBase2HdfsPhoneMapper.java
package com.yjxxt.hbase.mapred.hbase2hdfs;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import java.io.IOException;
public class HBase2HdfsPhoneMapper extends TableMapper<Text, IntWritable> {
@Override
protected void map(ImmutableBytesWritable key, Result value, Context context) throws IOException, InterruptedException {
// 获取 RowKey 并分割处理得到手机号
String rowkey = new String(value.getRow());
String phoneNum = rowkey.split("_")[0];
context.write(new Text(phoneNum), new IntWritable(1));
}
}
HBase2HdfsPhoneReducer.java
package com.yjxxt.hbase.mapred.hbase2hdfs;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
public class HBase2HdfsPhoneReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int count = 0;
for (IntWritable value : values) {
count += value.get();
}
context.write(key, new IntWritable(count));
}
}
HBase 和 Hive
Hive 提供了与 HBase 的集成,使得能够在 HBase 表上使用 HQL 语句进行查询、插入以及 JOIN、UNION 等复杂查询,同时也可以将 Hive 表中的数据映射到 HBase 中。
拷贝 Jar
三台机器分别执行以下命令,将 hive-hbase-handler-3.1.2.jar
拷贝至 HBase。
cp /opt/yjx/apache-hive-3.1.2-bin/lib/hive-hbase-handler-3.1.2.jar /opt/yjx/hbase-2.5.3/lib/
检查 Jar 包是否已经拷贝。
ls /opt/yjx/hbase-2.5.3/lib/hive-hbase-handler-3.1.2.jar
修改配置文件
修改 Hive(MetaStore 机器) 的配置文件vim /opt/yjx/apache-hive-3.1.2-bin/conf/hive-site.xml
,配置HBase 的 ZooKeeper 集群。
<property>
<name>hbase.zookeeper.quorum</name>
<value>node01:2181,node02:2181,node03:2181</value>
</property>
测试
HBase 创建 hbase_user 表并添加 info 列族。
# 创建 test 命令空间
create_namespace 'test'
# 创建 hbase_user 表并添加 info 列族
create 'test:hbase_user', 'info'
# 插入数据
put 'test:hbase_user', '1', 'info:name', 'zhangsan'
put 'test:hbase_user', '1', 'info:age', '18'
put 'test:hbase_user', '1', 'info:gender', 'male'
put 'test:hbase_user', '2', 'info:name', 'lisi'
put 'test:hbase_user', '2', 'info:age', '19'
put 'test:hbase_user', '2', 'info:gender', 'female'
put 'test:hbase_user', '3', 'info:name', 'wangwu'
put 'test:hbase_user', '3', 'info:age', '20'
put 'test:hbase_user', '3', 'info:gender', 'male'
Hive 创建 hive_user 外部表并使用 HBase 序列化器。
-- 创建 test 数据库
CREATE DATABASE IF NOT EXISTS test;
-- 创建 hive_user 外部表
CREATE EXTERNAL TABLE IF NOT EXISTS test.hive_user (
id string,
name string,
age string,
gender string
)
ROW FORMAT SERDE 'org.apache.hadoop.hive.hbase.HBaseSerDe'
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES('hbase.columns.mapping'=':key,info:name,info:age,info:gender')
TBLPROPERTIES('hbase.table.name'='test:hbase_user');
-- 通过查询测试是否整合成功
SELECT * FROM test.hive_user;