06数据仓库Hive03

127 阅读11分钟

数据仓库Hive

Hive参数

hive参数介绍

hive命令是hive --service cli的简写,可以通过hive --service cli --help查看帮助

选项说明
-d,--define <key=value>用于Hive命令的变量替换,例如-d A=B--define A=B
--database <databasename>指定要使用的库,默认是default
-e <quoted-query-string>执行-e指定的sql
-f <filename>执行-f指定的sql脚本
-H,--help打印帮助信息
--hiveconf <property=value>覆盖hive-site.xml配置文件中指定属性的值
--hivevar <key=value>用于Hive命令的变量替换,例如--hivevar A=B
-i <filename>初始化SQL文件,在进入hive cli之前执行一些初始化操作,例如设置多个变量
-S,--silent交互式shell中的静默模式
-v,--verbose详细模式(将已执行的SQL回显到控制台)

hive当中的参数、变量都是以命名空间开头的,详情如下表所示

命名空间读写权限含义
hiveconf可读写hive-site.xml中配置的变量,启动hive cli时可以覆盖,例如hive --hiveconf hive.cli.print.header=true
system可读写系统变量,包含JVM运行参数等,例如system:user.name=bigdata
env只读环境变量,例如env:JAVA_HOME=/usr/local/jdk8
hivevar可读写例如hive -d val=key

hive的变量可以通过${}方式进行引用,其中hiveconf、system、env下的变量必须以前缀(命名空间加上冒号)开头,hivevar变量可以加前缀也可以不加前缀。通过set方式查看时,system、env下的变量必须以前缀开头,hiveconf、hivevar变量可以加前缀也可以不加前缀。参考"hive参数的设置方式"中的案例

hive参数的设置方式

  1. 修改配置文件${HIVE_HOME}/conf/hive-site.xml,永久生效,所有的hive会话都会加载对应的配置
  2. 启动hive cli时,通过--hiveconf key=value的方式进行设置,例如hive --hiveconf hive.cli.print.header=true
  3. 在进入到cli之后,通过set命令设置,例如set hive.cli.print.header=true;

注意:2和3两种方式设置的参数只在当前会话有效,退出会话之后参数失效

在hive cli控制台可以通过set对hive中的参数进行查询、设置

-- 设置参数
set hive.cli.print.header=true;
-- 查看该参数的值
set hive.cli.print.header;
-- 查看hive的所有参数
set;

-- 用set设置自定义变量时,必须加hivevar:前缀,否则${}取不到
set abc=1;
-- 取不到值
select "${abc}";
${abc}

set hivevar:abc=1;
-- 可以取到abc
select "${abc}";
1
-- 带上hivevar:前缀也可以
select "${hivevar:abc}";
1

-- 实际abc和hivevar:abc都是有值的,但是通过${abc}获取时,实际获取的是hivevar:abc

-- 有值
set abc;
abc=1

-- 有值
set hivevar:abc;
hivevar:abc=1

-- `hive -d abc=1`这种方式进入hive cli时,相当于执行了`set hivevar:abc=1;`

-- hiveconf、system、env下的变量${}取值必须以前缀开头,否则取不到;system、env下的变量,set查看值必须以前缀开头

-- hive.cli.print.header实际也是有前缀的(hiveconf:)

-- 有值
set hiveconf:hive.cli.print.header;
hiveconf:hive.cli.print.header=false

-- 有值
set hive.cli.print.header;
hive.cli.print.header=false

-- 取不到值
select "${hive.cli.print.header}";
${hive.cli.print.header}

-- 可以取到
select "${hiveconf:hive.cli.print.header}";
false

-- system:user.name=bigdata

-- 有值
set system:user.name;
system:user.name=bigdata

-- 没有值
set user.name;
user.name is undefined

-- 可以取到
select "${system:user.name}";
bigdata

-- 取不到值
select "${user.name}";
${user.name}

-- env:JAVA_HOME=/usr/local/jdk8

-- 有值
set env:JAVA_HOME;
env:JAVA_HOME=/usr/local/jdk8

-- 没有值
set JAVA_HOME;
JAVA_HOME is undefined

-- 可以取到
select "${env:JAVA_HOME}";
/usr/local/jdk8

-- 取不到
select "${JAVA_HOME}";
${JAVA_HOME}
  1. hive参数初始化设置

当前用户家目录下的.hiverc文件,如果没有,可直接创建该文件,将需要设置的参数和变量写到该文件中(set命令设置),hive启动运行时,会加载该文件,执行文件中的命令

在当前用户的家目录下还会存在~/.hivehistory文件,该文件保存了hive历史操作命令

Hive运行方式

我们在使用Hive时,有四种使用方式

  • 命令行方式
  • 脚本运行方式
  • JDBC运行方式
  • Web GUI方式

命令行方式

我们可以直接在安装Hive的节点输入"hive"进入hive命令行交互式窗口,上面都是基于这种方式操作hive的

进入交互式窗口后,除了可以执行sql,也可以输入"dfs"命令与HDFS交互,也可以输入"!"开头的命令来与Linux交互

-- 在hive cli中操作hdfs比在shell中操作快,因为与hdfs的连接已经建立好了
dfs -ls /data;
Found 2 items
drwxr-xr-x   - bigdata supergroup          0 2024-03-12 09:46 /data/test
drwxr-xr-x   - bigdata supergroup          0 2024-03-12 10:12 /data/topn

-- 与linux交互,注意与linux交互的时候必须要加!
!ls /usr/local/hive-3.1.3/bin/;
beeline
ext
hive
hive-config.sh
hiveserver2
hplsql
init-hive-dfs.sh
metatool
schematool

进入hive命令行交互式窗口时,可以设置变量,然后在交互式窗口中使用

# 相当于在hive交互式窗口中执行`set hivevar:abc=1;`
hive -d abc=1
select * from person2 where id = ${abc};
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}

进入hive命令行交互式窗口时,可以执行一个初始化脚本,这样在进入hive cli后会先执行这个初始化脚本,例如设置一些参数和变量

# 创建初始化文件
echo "-- 查询时打印表头
set hive.cli.print.header=true;
-- 自定义变量
set hivevar:abc=1;
-- 展示当前所有表
show tables;
" > my_hive_init.sql;

# 进入hive cli通过-i指定初始化文件,会看到打印了所有表
hive -i /home/bigdata/my_hive_init.sql;
-- 可以看到初始化脚本中设置的参数和变量生效了
select * from person2 where id = ${abc};
person2.id      person2.name    person2.likes   person2.address
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}

在hive的命令行中也可以执行外部文件中的脚本

-- sql脚本执行了,会看到打印了所有表
source /home/bigdata/my_hive_init.sql;

我们也可以执行如下命令不进入Hive 交互式窗口执行命令

# 不进入Hive交互式窗口执行Hql语句
hive -e "select * from person2"
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}

# 不进入Hive交互式窗口并以静默(输出会少一些)模式运行HQL
hive -S -e "select * from person2"
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}

# 可以执行多个sql,sql语句用分号(;)分割,因为这是在shell环境中,可以将执行结果重定向到文件中保存
hive -S -e "show tables;select * from person2;" > tables_and_person2_result

# 将所有参数导到文件中
hive -e 'set' > my_hive_set.txt

脚本方式运行

我们也可以将Hive SQL语句写入到一个sql脚本中,通过以下命令来执行SQL脚本,这在工作中用的非常多

echo "show tables;
select * from person2;" > xx.sql

hive -f xx.sql
...
a
a1
b
b1
bucket_tbl01
...
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}

# 以静默(输出会少一些)方式运行HQL脚本
hive -S -f xx.sql

JDBC方式运行

java

pom.xml如下所示,注意依赖的jar包除了从阿里云public仓库https://maven.aliyun.com/repository/public下载,还有的从阿里云spring仓库https://maven.aliyun.com/repository/spring下载

<?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>org.example</groupId>
    <artifactId>hive-test</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-jdbc</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-metastore</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-service</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>3.2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.thrift</groupId>
            <artifactId>libfb303</artifactId>
            <version>0.9.2</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.10</version>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <finalName>${project.name}</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <!--代码编译指定版本插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <target>${maven.compiler.target}</target>
                    <source>${maven.compiler.source}</source>
                    <encoding>UTF-8</encoding>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
public class HiveJdbcClient {
    public static void main(String[] args) throws Exception {
        Class.forName("org.apache.hive.jdbc.HiveDriver");
        Connection conn = DriverManager.getConnection("jdbc:hive2://node01:10000/default", "bigdata", "");
        Statement stmt = conn.createStatement();
        String sql = "select * from person2";
        ResultSet res = stmt.executeQuery(sql);
        while (res.next()) {
            System.out.println(res.getString(1) + ","
                    + res.getString(2) + ","
                    + res.getString(3) + ","
                    + res.getString(4));
        }
        // 执行结果:1,小明1,["lol","book","movie"],{"beijing":"xisanqi","shanghai":"pudong"}
    }
}
python

我们可以通过python连接Hive,通过python编写Hql语句执行。这里我们通过使用JayDeBeApi通过JDBC的方式连接Hive(需要先在node01节点启动hiveserver2,jdbc连接的是这个服务)

# node03节点root用户,python环境准备

# python软件部署
yum install python3 -y

python3 --version
Python 3.6.8

# pip环境配置
mkdir ~/.pip
cat > ~/.pip/pip.conf << EOF
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = pypi.tuna.tsinghua.edu.cn
EOF

python3 -m pip install --upgrade pip

# python虚拟环境

# 安装虚拟环境软件
yum install python-virtualenv -y
# 准备虚拟环境目录
mkdir /data/virtual -p
cd /data/virtual
# 创建虚拟环境
virtualenv -p /usr/bin/python3.6 venv
# 进入python虚拟环境
source venv/bin/activate
# 更新pip
pip install --upgrade pip

python --version
Python 3.6.8

# 退出虚拟环境
deactivate

脚本文件hive_jdbc_conn.py如下所示,

import jaydebeapi

# hive jdbc连接地址
url = 'jdbc:hive2://node01:10000/default'
user = 'bigdata'
password = ''
driver = 'org.apache.hive.jdbc.HiveDriver'
# 先自己准备好jar包,放到相应的目录
jarFile = [
    '/root/python_conn_hive/hive-jdbc-1.2.1.jar',
    '/root/python_conn_hive/hive-exec-1.2.1.jar',
    '/root/python_conn_hive/hive-metastore-1.2.1.jar',
    '/root/python_conn_hive/hive-service-1.2.1.jar',
    '/root/python_conn_hive/hadoop-common-3.2.4.jar',
    '/root/python_conn_hive/libfb303-0.9.2.jar',
    '/root/python_conn_hive/commons-logging-1.2.jar',
    '/root/python_conn_hive/slf4j-api-1.7.12.jar',
    '/root/python_conn_hive/httpclient-4.5.6.jar',
    '/root/python_conn_hive/httpcore-4.4.10.jar',
    '/root/python_conn_hive/slf4j-simple-1.7.12.jar']

# 准备sql语句
sqlStr = 'select * from person2'

# 创建Hive连接
conn = jaydebeapi.connect(driver, url, [user, password], jarFile)

# 创建执行sql对象
curs = conn.cursor()
# 执行sql
curs.execute(sqlStr)

# 获取结果
result = curs.fetchall()
print(result)

# 关闭对象
curs.close()
conn.close()
# 进入python虚拟环境
source /data/virtual/venv/bin/activate
# 创建上面的hive_jdbc_conn.py脚本文件

# 安装JayDeBeApi
pip install JayDeBeApi

# 执行脚本
python3 hive_jdbc_conn.py
[(1, '小明1', '["lol","book","movie"]', '{"beijing":"xisanqi","shanghai":"pudong"}')]

Web GUI接口

在Hive3版本之前,我们还可以通过Web GUI方式来操作Hive,这种方式虽然是有WebUI,但是在大数据执行任务过程中,我们最常用的还是直接执行sql脚本。此外,大数据中还有工具例如:HUE 可以直接操作Hive,相对原生的Web GUI,非常好用

动态分区

动态分区使用

向Hive分区表中插入数据时,如果要创建的分区非常多,例如:以时间字段为分区的话,每天的数据对应一个分区,如果日期非常多,那么将要执行很多sql才能完成。Hive提供了动态分区的功能,可以根据某一列或几列的列值动态生成分区,在Hive中通过参数: hive.exec.dynamic.partition来设置开启或者关闭动态分区,默认是true

有以下用户数据(person30.txt),id,name,log_dt

1	zs	2023-10-01
2	ls	2023-10-01
3	ww	2023-10-02
4	ml	2023-10-02

person31.txt

1	zs
2	ls

person32.txt

3	ww
4	ml

我们需要创建person30表,将数据加载到表中,同时以log_dt为分区,分区数据是每天日期

比较笨重的是创建分区表,并加载数据

-- 创建分区表
create table person30(id int,name string) partitioned by (log_dt string) row format delimited fields terminated by '\t';
-- 加载数据时,需要将以上四条数据分别放入两个不同的文件,分别执行sql加载,如下
load data local inpath '/home/bigdata/person31.txt' into table person30 partition (log_dt='2023-10-01');
load data local inpath '/home/bigdata/person32.txt' into table person30 partition (log_dt='2023-10-02');

-- 查看数据
select * from person30;
1       zs      2023-10-01
2       ls      2023-10-01
3       ww      2023-10-02
4       ml      2023-10-02

-- 查看分区
show partitions person30;
log_dt=2023-10-01
log_dt=2023-10-02

动态分区创建表,并加载数据

从已有非分区表加载数据到分区表

-- 创建普通表,并加载数据
create table person31_tmp(id int,name string,log_dt string) row format delimited fields terminated by '\t';
load data local inpath '/home/bigdata/person30.txt' into table person31_tmp;

-- 创建分区表
create table person31(id int,name string) partitioned by (log_dt string) row format delimited fields terminated by '\t';

-- 向分区表动态加载数据,可能会报下面的错误
insert overwrite table person31 partition (log_dt) select id,name,log_dt as xx from person31_tmp;
FAILED: SemanticException [Error 10096]: Dynamic partition strict mode requires at least one static partition column. To turn this off set hive.exec.dynamic.partition.mode=nonstrict

-- 使用Hive动态分区必须设置如下参数,此参数默认是strict,必须有静态分区才能使用动态分区,我们设置为nonstrict,可以直接使用动态分区
set hive.exec.dynamic.partition.mode=nonstrict;
-- 再次执行成功,分区列在最后面,名字不重要,这里设置成xx不影响
insert overwrite table person31 partition (log_dt) select id,name,log_dt as xx from person31_tmp;

-- 查看数据
select * from person31;
1       zs      2023-10-01
2       ls      2023-10-01
3       ww      2023-10-02
4       ml      2023-10-02

-- 查看分区
show partitions person31;
log_dt=2023-10-01
log_dt=2023-10-02

-- 双分区演示
create table students31(id int,name string) partitioned by (age int,loc string)row format delimited fields terminated by '\t';
-- partition(loc, age)中列的顺序不重要,但是必须指定所有的分区列,最终是按照建表语句中分区列的顺序取后面select语句中最后两列的值(后面select语句中的列名也不重要)
insert overwrite table students31 partition(loc, age) select id,name,age xx,loc yy from students;
-- 上面只是为了演示,实际使用时,应该把列名对应起来,这样好理解
insert overwrite table students31 partition(age, loc) select id,name,age,loc from students;

show partitions students31;
age=10/loc=shanghai
age=20/loc=beijing

select * from students31;
1       zs      10      shanghai
2       ls      10      shanghai
3       ww      20      beijing
4       ml      20      beijing

-- 下面演示严格模式下,动态分区的使用,必须至少两个分区列(因为需要至少指定一个静态分区)
set hive.exec.dynamic.partition.mode=strict;
create table students32(id int,name string) partitioned by (age int,loc string)row format delimited fields terminated by '\t';
-- 严格模式下,向动态分区表中导入数据,必须至少指定一个静态分区列,且原始数据中静态分区列对应的数据会被忽略(以指定的静态分区列数据为准)
insert overwrite table students32 partition(age=10, loc) select id,name,/*age,*/loc from students;
-- 指定静态分区列之后,不会使用原始数据中对应列的数据,这里原始数据中有age=20的数据全部都变成了age=10
select * from students32;
3       ww      10      beijing
4       ml      10      beijing
1       zs      10      shanghai
2       ls      10      shanghai

直接将含有分区列的文件加载到分区表,前面已经介绍过

-- 创建分区表,并加载数据
create table person32(id int,name string) partitioned by (log_dt string) row format delimited fields terminated by '\t';
load data local inpath '/home/bigdata/person30.txt' into table person32;

-- 查看数据
select * from person32;
1       zs      2023-10-01
2       ls      2023-10-01
3       ww      2023-10-02
4       ml      2023-10-02

-- 查看分区
show partitions person32;
log_dt=2023-10-01
log_dt=2023-10-02

动态分区优化

关于动态分区优化参数如下

-- 此值默认100,代表每个maper或者reducer可以允许创建的最大动态分区个数,默认是100,超出会报错
set hive.exec.max.dynamic.partitions.pernode=100;
-- 此值默认是1000,代表一个动态分区语句可以创建的最大动态分区个数,超出会报错
set hive.exec.max.dynamic.partitions=1000;
-- 此值默认是100000,所有的mr job允许创建的最大文件数量,类似于OS中进程可打开的最大文件数量
set hive.exec.max.created.files=100000;

Hive分桶

分桶表

Hive 分桶是比分区更细粒度的数据划分,可以指定分桶表的某一列,让该列数据按照哈希取模的方式随机、均匀地分发到各个桶文件中。例如:按照表name列分为3个桶,就是对name属性值的hash值对3取摸,按照取模结果对数据分桶。如取模结果为0的数据记录存放到一个文件,取模为1的数据存放到一个文件,取模为2的数据存放到一个文件

分桶可提高查询效率,比如我们要对两张在同一列上进行了分桶操作的表进行JOIN操作的时候,只需要对保存相同列值的桶进行JOIN操作即可。同时分桶也可以提高采样率

分桶表的好处:

*获得更高的查询处理效率:*桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作,对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量

*使取样(sampling)更高效:*在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便

创建分桶表

准备数据(bucket01.txt)

1	a	18
2	b	19
3	c	20
4	d	21
5	e	22
6	f	23
7	g	24
8	h	25
9	i	26
10	j	27
-- 在Hive中使用分桶,首先需要开启分桶,hive 2.X版本之前需要设置,之后的版本不用设置
set hive.enforce.bucketing=true;
-- 创建分桶表,使用clustered by 指定分桶依据的列名,还要指定分多少桶,这里指定分为4个桶
create table bucket_tbl01(id int,name string,age int) clustered by (id) into 4 buckets row format delimited fields terminated by '\t'; 
-- 对于分桶表,mr运行时会根据bucket的数量自动分配reduce task数量(用户也可以通过mapred.reduce.tasks设置reduce task数量,但分桶时不推荐使用)
-- 加载数据,从日志中可以看出reduce的数量等于桶的数量
load data local inpath '/home/bigdata/bucket01.txt' into table bucket_tbl01;
...
Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 4
...

-- 也可以使用insert into table 命令向分桶表中插入数据,例如:
insert into table bucket_tbl01 select columns from tbl;
insert overwrite table bucket_tbl01 select columns from tbl;

-- 查询数据
select * from bucket_tbl01;
8       h       25
4       d       21
9       i       26
...
# 查看hdfs,bucket_tbl01分桶表所在目录,有四个桶文件
hdfs dfs -ls -R /user/hive/warehouse/bucket_tbl01
-rw-r--r--   3 bigdata supergroup         14 2024-03-24 11:53 /user/hive/warehouse/bucket_tbl01/000000_0
-rw-r--r--   3 bigdata supergroup         21 2024-03-24 11:53 /user/hive/warehouse/bucket_tbl01/000001_0
-rw-r--r--   3 bigdata supergroup         22 2024-03-24 11:53 /user/hive/warehouse/bucket_tbl01/000002_0
-rw-r--r--   3 bigdata supergroup         14 2024-03-24 11:53 /user/hive/warehouse/bucket_tbl01/000003_0

采样

分桶表采样

TABLESAMPLE (BUCKET x OUT OF y [ON colname])

TABLESAMPLE 子句允许用户为数据样本而不是整个表编写查询。 TABLESAMPLE子句可以添加到任何表的FROM 子句中。桶编号从1开始。 colname表示对表中每一行进行抽样的列。 colname可以是表中的非分区列之一,也可以是rand()表示对整行而不是单个列进行抽样。表的行按colname列随机“分桶”到 y 个桶中,桶编号为1到 y。属于桶x的行被返回

-- 抽取数据时,将source表数据分成32个桶,抽取第3个桶数据
SELECT * FROM source TABLESAMPLE(BUCKET 3 OUT OF 32 ON rand())

输入修剪:通常,TABLESAMPLE将扫描整个表并抽取样本。但是,这不是很有效。相反,可以使用一个CLUSTERED BY子句创建表(即分桶表),该子句指示表在其多列上进行哈希分区/cluster。如果在TABLESAMPLE子句中指定的列与CLUSTERED BY子句中的列匹配,那么TABLESAMPLE只扫描表中所需的哈希分区(桶)

因此,在上面的例子中,如果表source创建的时候有CLUSTERED BY id INTO 32 BUCKETS子句

TABLESAMPLE(BUCKET 3 OUT OF 16 ON id)表示将选出第3和第19个cluster,因为每个桶将由(32/16)=2个cluster组成

TABLESAMPLE(BUCKET 3 OUT OF 64 ON id)表示将选出第3个cluster的一半,因为每个桶将由(32/64)=1/2个cluster组成

上面是官网的描述,下面再说明一下

TABLESAMPLE (BUCKET x OUT OF y [ON colname])表示抽样查询,即不会查询所有。当表是分桶表且抽样列与查询列一样时(其它情况都是抽样x/y,当分桶表只有一个分桶列时,取样列可以省略),y必须是表桶总数量的倍数或者因子。hive根据y的大小,决定抽样的比例。 例如,table总共分了32个桶,当y=16时,抽取(32/16)=2个桶的数据,当y=64时,抽取(32/64)=1/2个桶的数据。x表示从哪个桶开始抽取,例如,table总共分了32个桶,TABLESAMPLE(BUCKET 3 OUT OF 16 ON id)表示抽取(32/16)=2个桶的数据,分别为第3个桶和第3+16=19个桶的数据;TABLESAMPLE(BUCKET 3 OUT OF 64 ON id)表示从第3个桶抽取(32/64)=1/2个桶的数据。注意实际的取样算法是比较复杂的,当数据量少时,结果不一定和上面公式算的一模一样

块采样

TABLESAMPLE (n PERCENT)

这将允许Hive抽取至少n%的数据大小(注意它不一定意味着行数)作为输入。只支持CombineHiveInputFormat,一些特殊的压缩格式不处理。如果采样失败,MapReduce作业的输入将是整个表/分区。我们在HDFS块级进行采样,因此采样粒度是块大小。例如,如果块大小为256MB,即使输入大小的n%只有100MB,也会得到256MB的数据

-- 采样0.1%的数据
SELECT * FROM source TABLESAMPLE(0.1 PERCENT) s;

如果希望在不同的块中抽取相同大小的数据,可以修改hive.sample.seednumber参数的值(默认是0)

TABLESAMPLE (ByteLengthLiteral),ByteLengthLiteral: (Digit)+ ('b' | 'B' | 'k' | 'K' | 'm' | 'M' | 'g' | 'G')

也可以指定要采样数据的总大小,但它与百分比采样有相同的限制

-- 采样100M的数据
SELECT * FROM source TABLESAMPLE(100M) s;

TABLESAMPLE (n ROWS)

Hive 还支持按行数对输入进行限制(采样),但它与上述两种行为不同。首先,它不需要 CombineHiveInputFormat ,这意味着它可以在non-native表上使用。其次,用户给定的行数应用到每个split上。 因此总行数还随着输入split数量而变化

-- 获取每个输入分片(split)的前10行
SELECT * FROM source TABLESAMPLE(10 ROWS)

分区+分桶表

在Hive创建表时,可以同时指定分区和分桶

准备数据(bucket02.txt)

1	a	18	beijing
2	b	19	beijing
3	c	20	shanghai
4	d	21	shanghai
5	e	22	beijing
6	f	23	beijing
7	g	24	beijing
8	h	25	shanghai
9	i	26	shanghai
10	j	27	beijing
-- 创建表
create table bucket_tbl02(id int,name string,age int) partitioned by (loc string) clustered by (id) into 4 buckets row format delimited fields terminated by '\t'; 
-- 加载数据
load data local inpath '/home/bigdata/bucket02.txt' into table bucket_tbl02;

查看HDFS 中Hive存储数据,我们发现当一张表既有分区又有分桶时,针对每个分区内的数据都会进行分桶操作,每个分区内都有对应的桶个数

# 查看hdfs,bucket_tbl02分区分桶表所在目录,每个分区对应一个目录,且每个分区中有四个桶文件
hdfs dfs -ls -R /user/hive/warehouse/bucket_tbl02
drwxr-xr-x   - bigdata supergroup          0 2024-03-24 12:11 /user/hive/warehouse/bucket_tbl02/loc=beijing
-rw-r--r--   3 bigdata supergroup          0 2024-03-24 12:11 /user/hive/warehouse/bucket_tbl02/loc=beijing/000000_0
-rw-r--r--   3 bigdata supergroup         14 2024-03-24 12:11 /user/hive/warehouse/bucket_tbl02/loc=beijing/000001_0
-rw-r--r--   3 bigdata supergroup         22 2024-03-24 12:11 /user/hive/warehouse/bucket_tbl02/loc=beijing/000002_0
-rw-r--r--   3 bigdata supergroup          7 2024-03-24 12:11 /user/hive/warehouse/bucket_tbl02/loc=beijing/000003_0
...

分区与分桶的区别

分区是分目录存储数据,分桶是将表中的数据分文件存储,可以先分区再分桶

Hive Lateral View 视图与索引

Hive Lateral View

lateralView: LATERAL VIEW udtf(expression) tableAlias AS columnAlias (',' columnAlias)*

fromClause: FROM baseTable (lateralView)*

准备数据(lateral_view.txt),id,name,address,phones

1	zs	shanghai-beijing	111-222
2	ls	tianjin-nanjing	333-444

我们想将以上数据中的"address"和"phones"列拆分得到如下数据

1	zs	shanghai	111
1	zs	beijing	111
1	zs	shanghai	222
1	zs	beijing	222
...

Lateral View用于将普通列与UDTF函数同时查询;首先通过UDTF函数拆分成多行,再将多行结果组合成一个支持别名的虚拟表。主要解决在select使用UDTF做查询过程中,查询只能包含单个UDTF,不能包含其他字段、以及多个UDTF的问题

-- 创建表并加载数据
create table lateral_view_tbl(id int,name string,address string,phones string) row format delimited fields terminated by '\t';
load data local inpath '/home/bigdata/lateral_view.txt' into table lateral_view_tbl;

-- 如果想要得到预期的结果必须使用Hive UDTF函数explode将"address"和"phones"列进行膨胀拆分
select explode(split(address,"-")) as ads from lateral_view_tbl;
shanghai
beijing
tianjin
nanjing

-- 但是如果同时想要查询展示对应的id和name列时会报错,在Hive中不允许普通列与UDTF函数同时查询
select id,name,explode(split(address,"-")) as ads from lateral_view_tbl;
"FAILED: SemanticException [Error 10081]: UDTF's are not supported outside the SELECT clause, nor nested in expressions"

-- 那么"Lateral View"就是解决这种问题的,可以使用"Lateral View"实现同时查询展示对应的列。这里`explode(split(address,"-")) xx`中的xx只是给函数起了个别名没有实际的意义,但是必须有
select id,name,ads from lateral_view_tbl lateral view explode(split(address,"-")) mytbl as ads;
1       zs      shanghai
1       zs      beijing
2       ls      tianjin
2       ls      nanjing

-- 如果一个表中有两列需要进行膨胀,那么使用Lateral view 应该按照如下方式使用
select id,name,ads,pho from lateral_view_tbl 
lateral view explode(split(address,"-")) mytbl1 as ads  
lateral view explode(split(phones,"-")) mytbl2 as pho;
1       zs      shanghai        111
1       zs      shanghai        222
1       zs      beijing 111
1       zs      beijing 222
...

-- lateral view 后面的可以看成一个虚拟表,可以包含多列,上面都是包含一列,下面演示包含两列的情况
-- 原始数据
select * from person2;
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}

select id, name, tbl1.*, tbl2.* from person2 lateral view explode(address) tbl1 lateral view explode(likes) tbl2;
1       小明1   beijing xisanqi lol
1       小明1   beijing xisanqi book
1       小明1   beijing xisanqi movie
1       小明1   shanghai        pudong  lol
1       小明1   shanghai        pudong  book
1       小明1   shanghai        pudong  movie

-- lateral view 后面的as是给虚拟表中的列起别名的,上面的sql,可以改写成下面这个样子
select id, name, my_address1, my_address2, my_like from person2 lateral view explode(address) tbl1 as my_address1, my_address2 lateral view explode(likes) tbl2 as my_like;

-- 也可以直接用*取所有列
select * from person2 lateral view explode(address) tbl1 lateral view explode(likes) tbl2;
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}       beijing xisanqi lol
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}       beijing xisanqi book
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}       beijing xisanqi movie
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}       shanghai        pudong  lol
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}       shanghai        pudong  book
1       小明1   ["lol","book","movie"]  {"beijing":"xisanqi","shanghai":"pudong"}       shanghai        pudong  movie

lateral view相当于生成了一个虚拟表(视图),与前面的表做关联查询,只不过没有关联条件

可以指定可选的OUTER关键字来生成行,即使LATERAL VIEW不会生成行。当使用的UDTF不生成任何行时,就会发生这种情况,当要爆炸(explode)的列为空时,很容易发生这种情况。在这种情况下,源行永远不会出现在结果中。可以使用OUTER来防止这种情况,行中来自UDTF的列将生成NULL值

-- 创建测试表
create table lateral_view_tbl02 as select * from person2;
-- 插入一行数据,address和likes都为null
insert into lateral_view_tbl02(id, name) values (2, '小明2');
-- 查询,不包含null列
select id, name, tbl1.*, tbl2.* from lateral_view_tbl02 lateral view explode(address) tbl1 lateral view explode(likes) tbl2;
1       小明1   beijing xisanqi lol
1       小明1   beijing xisanqi book
1       小明1   beijing xisanqi movie
1       小明1   shanghai        pudong  lol
1       小明1   shanghai        pudong  book
1       小明1   shanghai        pudong  movie

-- 查询,包含null列
select id, name, tbl1.*, tbl2.* from lateral_view_tbl02 lateral view outer explode(address) tbl1 lateral view outer explode(likes) tbl2;
1       小明1   beijing xisanqi lol
1       小明1   beijing xisanqi book
1       小明1   beijing xisanqi movie
1       小明1   shanghai        pudong  lol
1       小明1   shanghai        pudong  book
1       小明1   shanghai        pudong  movie
2       小明2   NULL    NULL    NULL

Hive 视图

在Hive中如果经常使用到一个复杂SQL进行数据查询,我们可以对复杂SQL创建视图,这样就可以在后期使用中直接查询视图,比较方便。Hive中的视图和RDBMS中视图的概念一致,都是一组数据的逻辑表示,本质上就是一条SELECT语句的结果集。视图是纯粹的逻辑对象,没有关联的存储(Hive 3.0.0引入的物化视图除外),当查询引用视图时,Hive可以将视图的定义与查询结合起来,例如将查询中的过滤器推送到视图中(即使用视图时,可以把视图当成一张表,指定查询条件)

准备数据

student_info.txt

1	zs	18
2	ls	19
3	ww	20

student_score.txt

1	zs	100
2	ls	200
3	ww	300
-- 创建表并加载数据
create table student_info (id int,name string,age int) row format delimited fields terminated by '\t';
load data local inpath '/home/bigdata/student_info.txt' into table student_info;
create table student_score (id int,name string,score int) row format delimited fields terminated by '\t';
load data local inpath '/home/bigdata/student_score.txt' into table student_score;
-- 我们经常需要使用如下的查询
select a.id,a.name,a.age,b.score from student_info a join student_score b on a.id = b.id;

那么在Hive中经常使用以上查询,每次使用时都需要写一遍上面的SQL执行查询,这里我们就可以直接创建Hive视图,方便后期查询

Hive中创建视图语法

CREATE VIEW [IF NOT EXISTS] [db_name.]view_name 
  [(column_name [COMMENT column_comment], ...) ]
  [COMMENT view_comment]
  [TBLPROPERTIES (property_name = property_value, ...)]
  AS SELECT ... ;
-- 我们可以针对以上场景创建视图myview
create view myview as select a.id,a.name,a.age,b.score from student_info a join student_score b on a.id = b.id;
-- 在后续使用中,直接使用视图myview即可
select * from myview;
1       zs      18      100
2       ls      19      200
3       ww      20      300

在Hive中创建视图后,视图不是真正的表,在MySQL元数据表中可以看到增加了一条视图记录

视图注意点

  1. Hive中的视图只能查询,不能加载数据操作
  2. 视图创建只是保存了一份元数据,查询视图时执行对应的sql,视图不存储数据
  3. Hive中不支持物化视图(存储数据的视图)
  4. 视图定义中若包含了ORDER BY/LIMIT语句,当查询视图时也进行ORDER BY/LIMIT语句操作,则视图中 定义的优先级更高
  5. 视图支持嵌套视图

删除视图

Hive中删除视图语法DROP VIEW [IF EXISTS] [db_name.]view_name;

-- 我们可以将前面创建的视图删除
drop view myview;

Hive 索引

Hive索引的目标是提高对表的某些列查询的速度。例如SQL语句"where age=10",如果age列没有索引,则查询时会加载整个表或分区并处理所有行,如果age列存在索引,那么只需要加载和处理文件的一部分

索引所能提供的查询速度的提高是以创建索引和存储索引的磁盘空间的额外处理为代价的,Hive自0.7版本开始支持索引,但提供的功能很有限,效率也并不高,因此Hive索引很少使用

在Hive3版本之后,Hive索引被取消

Hive索引原理

  1. 在指定列上建立索引,生成一张索引表,此表对应Hive的一张物理表,记录以下三个字段:索引列的值、该值对应的HDFS文件路径、该值在文件中的偏移量
  2. 在执行索引字段查询时候,首先额外生成一个MapReduce job,根据对索引列的过滤条件,从索引表中过滤出索引列的值对应的hdfs文件路径及偏移量,输出到hdfs上的一个文件中,然后根据这些文件中的hdfs路径和偏移量,筛选原始input文件,生成新的split,作为整个job的split,达到不用全表扫描的目的

注意

  • 每次查询时候都要先用一个job扫描索引表,如果索引列的值非常稀疏,那么索引表本身也会非常大
  • 索引表不会自动rebuild,如果表有数据新增或删除,那么必须手动rebuild索引表数据

Hive索引使用

创建索引语法如下

CREATE INDEX index_name
ON TABLE base_table_name (col_name, ...)
AS 'index.handler.class.name' 
[WITH DEFERRED REBUILD]
[IDXPROPERTIES (property_name=property_value, ...)]
[IN TABLE index_table_name]

-- 注意:
-- as 指定索引类,常用:org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler
-- in table :指定索引表,若不指定,默认生成在default__基础表名_t1_index__表中

准备数据(person40.txt)

1	zs	18
2	ls	19
3	ww	20
4	ml	21
5	tq	22
6	gb	23
7	a1	24
8	w2	25
9	q3	26
10	u4	27
-- 创建索引只能在小于hive3版本上操作
-- 创建表person40,并加载如下数据
create table person40(id int,name string,age int) row format delimited fields terminated by '\t';
load data local inpath '/home/bigdata/person40.txt' into table person40;
-- 针对表person40中列"name"创建索引并查询
create index person40_index on table person40(name) as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' with deferred rebuild in table tbl_index;
-- 注意:创建好索引表tbl_index后,不会自动针对person40表name构建索引,必须"rebuild"重建索引后,才能在索引表tbl_index中查询到数据

-- 查询索引
SHOW INDEX ON person40;
-- 重建索引
ALTER INDEX person40_index ON person40 REBUILD;
-- 查询索引数据
select * from tbl_index;
-- 删除索引
DROP INDEX IF EXISTS person40_index ON person40;

Hive 权限

权限控制是大数据平台非常重要的一部分,关乎数据安全。Hive本身自带权限控制。Hive的权限控制可以验证用户是否有权限执行某一操作,这里说的权限控制不验证用户身份是否可以操作Hive,如果想要授权用户是否可以读取操作Hive可以通过Kerberos工具实现。Hive本身自带的权限控制只针对JDBC方式连接Hive有效,针对Hive cli方式无效

Hive权限管理有三种授权模型

  • Storage Based Authorization in the Metastore Server 基于存储的授权,可以对 Metastore 中的元数据进行保护,但是没有提供更加细粒度的访问控制(如:列级别、行级别)

  • SQL Standards Based Authorization in HiveServer2 基于 SQL 标准的 Hive 授权,完全兼容 SQL 的授权模型,推荐使用该模式

    cwiki.apache.org/confluence/…

  • Default Hive Authorization(Legacy Mode)Hive 默认授权,设计目的仅只是为了防止用户产生误操作,而不是防止恶意用户访问未经授权的数据

下面重点讲解第二种授权模型

基于SQL标准的hiveserver2授权模式

  • 完全兼容SQL的授权模型

  • 除支持对于用户的授权认证,还支持角色role的授权认证

    role可理解为一组权限的集合,通过role为用户授权;一个用户可以具有一个或多个角色,默认包含两种角色:public、admin,一个角色也可以具有一个或多个角色

基于SQL标准的hiveserver2授权模式的限制

  1. 启用当前认证方式之后,dfs,add,delete,compile,and reset等命令被禁用
  2. 通过set命令设置hive configuration的方式被限制某些用户使用(可通过修改配置文件hive-site.xml中hive.security.authorization.sqlstd.confwhitelist进行配置)
  3. 添加、删除函数以及宏的操作,仅为具有admin的用户开放
  4. 用户自定义函数(开放支持永久的自定义函数),可通过具有admin角色的用户创建,其他用户都可以使用
  5. transform功能被禁用

SQL Standards Based Authorization in HiveServer2配置

在Hive服务端配置hive-site.xml,添加或修改如下内容

  <!-- 开启权限 -->
  <property>
    <name>hive.security.authorization.enabled</name>
    <value>true</value>
  </property>
  <!-- 是否禁用规则 -->
  <property>
    <name>hive.server2.enable.doAs</name>
    <value>false</value>
  </property>
  <!--  定义谁是超级管理员,多个使用逗号隔开,启动的时候会自动创建 -->
  <property>
    <name>hive.users.in.admin.role</name>
    <value>bigdata</value>
  </property>
  <!-- 配置进行权限控制的类 -->
  <property>
    <name>hive.security.authorization.manager</name>
    <value>org.apache.hadoop.hive.ql.security.authorization.plugin.sqlstd.SQLStdHiveAuthorizerFactory</value>
  </property>
  <property>
    <name>hive.security.authenticator.manager</name>
    <value>org.apache.hadoop.hive.ql.security.SessionStateUserAuthenticator</value>
  </property>

重启Hive及相关服务

# 重启Hive时,首先将Hive服务端的metastore、hiveserver2服务关闭,然后再重启
# 先杀死metastore和hiveserver2
kill -9 `jps | grep RunJar | awk '{print $1}'`
# 启动metastore
hive --service metastore &
# 启动hiveserver2
hiveserver2 &

Hive 用户和角色授权操作

在Hive中有用户(user)、角色(role)概念,role可以理解为一组权限的集合。一个用户可以拥有一个或者多个角色,默认包含两种角色:public、admin

Hive 角色介绍

关于角色操作的命令如下

  • show roles 查看Hive中所有存在的角色 ,只有admin角色有权限执行
  • show current roles 查看当前具有的角色
  • create role role_name 创建角色
  • set role (role_name|ALL|NONE) 设置角色,前提是他已经拥有该角色,一般用于在控制台中设置当前用户为admin,来执行一些管理员的操作(即以当前用户的某个角色执行接下来的操作)
  • drop role role_name 删除角色

注意:hive没有创建用户的命令,用户默认不用创建,可以直接赋角色;用户即使有管理员角色,使用需要是管理员的命令时,需要SET ROLE ADMIN切换到管理员角色且只在当前会话有效

在Hive客户端通过beeline连接Hive并操作

# 使用bigdata登录
beeline -u jdbc:hive2://node01:10000/default -n bigdata
-- 查看当前登录用户bigdata的角色,我们发现角色为public,并非admin角色
SHOW CURRENT ROLES;
+---------+
|  role   |
+---------+
| public  |
+---------+

-- 虽然在配置中已经指定bigdata为admin角色,但是在使用时还需set设置才能生效,执行如下命令设置bigdata为admin角色
SET ROLE ADMIN;

-- 查看bigdata当前角色:
SHOW CURRENT ROLES;
+--------+
|  role  |
+--------+
| admin  |
+--------+

-- 查询Hive所有角色
show roles;
+---------+
|  role   |
+---------+
| admin   |
| public  |
+---------+

-- 创建角色 zhang
create role zhang;

-- 查看Hive所有角色
show roles;
+---------+
|  role   |
+---------+
| admin   |
| public  |
| zhang   |
+---------+

-- 删除角色 zhang
drop role zhang;

如果我们使用普通用户zhangsan来登录beeline连接hive,查看对应的角色,操作如下

# 使用zhangsan 登录 beeline
beeline -u jdbc:hive2://node01:10000/default -n zhangsan
-- 查看zhangsan 所属角色
SHOW CURRENT ROLES;
+---------+
|  role   |
+---------+
| public  |
+---------+

-- 设置zhangsan为admin角色,并不能成功,原因是配置中zhangsan不是admin角色
set role admin;
...
Error: Error while processing statement: FAILED: Execution Error...
给用户或角色授权角色

我们可以通过以下命令给某个存在的角色赋值其他角色,那么当前角色也拥有其他角色拥有的权限

  • 给用户或角色授权其他角色GRANT ROLE role_name [, role_name] ... TO [ROLE/USER] principal_specification [, principal_specification] ...[WITH ADMIN OPTION]
  • 查看用户或角色拥有的角色SHOW ROLE GRANT principal_specification
  • 给用户或角色取消授权其他角色REVOKE [ADMIN OPTION FOR] ROLE role_name [, role_name] ...FROM principal_specification [, principal_specification] ...

注意:以上principal_specification可以使用户也可以是角色

# 使用bigdata登录beeline
beeline -u jdbc:hive2://node01:10000/default -n bigdata

给角色授权其他角色操作如下

-- 设置当前用户bigdata为admin
set role admin;
-- 创建角色zhang
create role zhang;
-- 给角色zhang授权admin角色
grant role admin to role zhang with admin option;
-- 查看zhang角色拥有哪些角色
show role grant role zhang;
+--------+---------------+----------------+----------+
|  role  | grant_option  |   grant_time   | grantor  |
+--------+---------------+----------------+----------+
| admin  | true          | 1711329260000  | bigdata  |
+--------+---------------+----------------+----------+

给用户授权角色操作如下

-- 给zhangsan用户授权admin角色
grant role admin to user zhangsan with admin option;

-- 查看zhangsan用户拥有的角色
show role grant user zhangsan;
+---------+---------------+----------------+----------+
|  role   | grant_option  |   grant_time   | grantor  |
+---------+---------------+----------------+----------+
| admin   | true          | 1711329378000  | bigdata  |
| public  | false         | 0              |          |
+---------+---------------+----------------+----------+

查看某个角色的用户或角色列表

查看某个角色被哪些角色和用户所拥有,命令是show principals role;

-- 查看admin角色被哪些角色或用户拥有
show principals admin;
+-----------------+-----------------+---------------+----------+---------------+----------------+
| principal_name  | principal_type  | grant_option  | grantor  | grantor_type  |   grant_time   |
+-----------------+-----------------+---------------+----------+---------------+----------------+
| bigdata         | USER            | true          | admin    | ROLE          | 1711326871000  |
| zhang           | ROLE            | true          | bigdata  | USER          | 1711329260000  |
| zhangsan        | USER            | true          | bigdata  | USER          | 1711329378000  |
+-----------------+-----------------+---------------+----------+---------------+----------------+

撤销授权给用户或角色的角色

命令是REVOKE [ADMIN OPTION FOR] ROLE role_name [, role_name] ...FROM principal_specification [, principal_specification] ...,这里的principal_specification可以使用户也可以是角色

-- 删除zhang授权的admin角色:
revoke admin from role zhang;

-- 查看zhang角色授权的角色:
show role grant role zhang;
+-------+---------------+-------------+----------+
| role  | grant_option  | grant_time  | grantor  |
+-------+---------------+-------------+----------+
+-------+---------------+-------------+----------+

-- 删除用户zhangsan拥有的角色admin
revoke admin from user zhangsan;

-- 查看zhangsan用户拥有的角色
show role grant user zhangsan;
+---------+---------------+-------------+----------+
|  role   | grant_option  | grant_time  | grantor  |
+---------+---------------+-------------+----------+
| public  | false         | 0           |          |
+---------+---------------+-------------+----------+
Hive用户和角色授权库表操作权限

在Hive中库表操作权限包含如下几类

  1. ALL 赋予用户所有权限
  2. ALTER 允许用户修改对象的元数据
  3. UPDATE 允许用户修改对象的物理数据
  4. CREATE 允许用户创建对象。对于数据库,这意味着用户可以创建表,对于表,这意味着用户可以创建分区
  5. DROP 允许用户删除对象
  6. INDEX 允许用户在一个对象上创建索引(注意:目前还没有实现)
  7. LOCK 允许用户在启用并发时锁定或解锁表
  8. SELECT 允许用户访问对象的数据
  9. SHOW_DATABASE 允许用户查看可用的数据库

以上可以参考官网连接:cwiki.apache.org/confluence/…

# 使用bigdata登录beeline
beeline -u jdbc:hive2://node01:10000/default -n bigdata
-- 设置当前用户bigdata为admin
set role admin;

给用户或角色授权Hive库表操作权限

在Hive中有了用户和角色后,我们就可以对用户或者角色进行Hive库表操作权限授权,这样用户及角色就可以在Hive中拥有对应的操作权限,给用户或角色授权Hive操作权限命令是GRANT priv_type [(column_list)][, priv_type [(column_list)]] ... [ON object_specification] TO principal_specification [,principal_specification] ...[WITH GRANT OPTION],这里principal_specification指的是用户或者角色

-- 给用户zhangsan授予查询表person2权限,with grant option表示该用户(zhangsan)是否可以将该权限(查询表person2)授予其它用户
grant select on person2 to user zhangsan with grant option;

-- 给角色zhang授予查询表person2权限
grant select on person2 to role zhang with grant option;

查看用户或角色操作Hive库表权限

命令是SHOW GRANT principal_specification [ON object_specification [(column_list)]],principal_specification指的是用户或者角色;object_specification指的是表或者数据库,all代表所有表和库

-- 查看用户zhangsan拥有Hive操作权限
show grant user zhangsan on person2;
+-----------+----------+------------+---------+-----------------+-----------------+------------+---------------+----------------+----------+
| database  |  table   | partition  | column  | principal_name  | principal_type  | privilege  | grant_option  |   grant_time   | grantor  |
+-----------+----------+------------+---------+-----------------+-----------------+------------+---------------+----------------+----------+
| default   | person2  |            |         | zhangsan        | USER            | SELECT     | true          | 1711336573000  | bigdata  |
+-----------+----------+------------+---------+-----------------+-----------------+------------+---------------+----------------+----------+

-- 查看角色zhang用户Hive操作权限
show grant role zhang on person2;
+-----------+----------+------------+---------+-----------------+-----------------+------------+---------------+----------------+----------+
| database  |  table   | partition  | column  | principal_name  | principal_type  | privilege  | grant_option  |   grant_time   | grantor  |
+-----------+----------+------------+---------+-----------------+-----------------+------------+---------------+----------------+----------+
| default   | person2  |            |         | zhang           | ROLE            | SELECT     | true          | 1711336583000  | bigdata  |
+-----------+----------+------------+---------+-----------------+-----------------+------------+---------------+----------------+----------+

取消用户或角色操作Hive库表权限

命令是REVOKE [GRANT OPTION FOR] priv_type [(column_list)][, priv_type [(column_list)]] ... [ON object_specification] FROM principal_specification [, principal_specification] ...principal_specification 指的是用户或者角色

-- 取消用户 zhangsan hive操作表person2权限
revoke select on person2 from user zhangsan;

-- 查看用户 zhangsan 操作Hive 权限,可以看到权限被移除了
show grant user zhangsan;

-- 取消角色 zhang hive操作表person2权限
revoke select on person2 from role zhang;

-- 查看角色 zhang 操作Hive 权限,可以看到权限被移除了
show grant role zhang;
# 使用zhangsan用户登录
beeline -u jdbc:hive2://node01:10000/default -n zhangsan
-- 登录用户没有表的权限则不可以查询
select * from person2;
Error: Error while compiling statement: FAILED: HiveAccessControlException Permission denied ...