Hive的详细使用

Hive

1、Hive安装部署

安装Hive

  • 第一步:把 apache-hive-3.1.2-bin.tar.gz 上传到 linux 下,并解压

  • 第二步:添加到环境变量中(按照自己的路径配置)

    # HIVE_HOME
    export HIVE_HOME=/opt/software/hive/apache-hive-3.1.2-bin
    export PATH=$PATH:$HIVE_HOME/bin
    
  • 第三步:初始化元数据

    • bin/schematool -dbType derby -initSchema
  • 第四步:启动hdfs、yarn

    • start-all.sh
  • 第五步:启动hive

    • bin/hive



安装MySQL

  • 第一步:检查系统是否安装过MySQL

    • rpm -qa | grep mariadb
    • 若安装了,使用下面命令将其卸载
      • rpm -e --nodeps mariadb-libs
  • 第二步:将mysql-5.7.28-1.el7.x86_64.rpm-bundle.tar上传到linux上,并解压

    • tar -xvf mysql-5.7.28-1.el7.x86_64.rpm-bundle.tar
  • 第三步:在安装目录下执行 rpm 安装(按照顺序依次执行)

    rpm -ivh mysql-community-common-5.7.28-1.el7.x86_64.rpm
    rpm -ivh mysql-community-libs-5.7.28-1.el7.x86_64.rpm
    rpm -ivh mysql-community-libs-compat-5.7.28-1.el7.x86_64.rpm
    rpm -ivh mysql-community-client-5.7.28-1.el7.x86_64.rpm
    rpm -ivh mysql-community-server-5.7.28-1.el7.x86_64.rpm
    
  • 第四步:初始化数据库

    • mysqld --initialize --user=mysql
  • 第五步:查看临时生成的 root 用户的密码,方便后续修改密码

    • cat /var/log/mysqld.log
  • 第六步:启动MySQL

    • systemctl start mysqld
  • 第七步:登录数据库

    • mysql -uroot -p
  • 第八步:修改 root 用户的密码

    • set password = password("123456");
  • 第九步:修改 mysql 库下的 user 表中的 root 用户允许任意 ip 连接

    • update mysql.user set host='%' where user='root';
    • flush privileges;



Hive元数据配置到MySQL

  • 第一步:将 MySQL 的 JDBC 驱动(mysql-connector-java-5.1.37.jar)拷贝到 Hive 的 lib 目录下

  • 第二步:在$HIVE_HOME/conf 目录下新建 hive-site.xml 文件,并添加如下内容(按照自己的环境配置)

    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
    <configuration>
        <!-- jdbc 连接的 URL -->
        <property>
            <name>javax.jdo.option.ConnectionURL</name>
            <value>jdbc:mysql://hadoop151:3306/metastore?useSSL=false</value>
        </property>
        <!-- jdbc 连接的 Driver-->
        <property>
            <name>javax.jdo.option.ConnectionDriverName</name>
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <!-- jdbc 连接的 username-->
        <property>
            <name>javax.jdo.option.ConnectionUserName</name>
            <value>root</value>
        </property>
        <!-- jdbc 连接的 password -->
        <property>
            <name>javax.jdo.option.ConnectionPassword</name>
            <value>123456</value>
        </property>
        <!-- Hive 元数据存储版本的验证 -->
        <property>
            <name>hive.metastore.schema.verification</name>
            <value>false</value>
        </property>
        <!--元数据存储授权-->
        <property>
            <name>hive.metastore.event.db.notification.api.auth</name>
            <value>false</value>
        </property>
        <!-- Hive 默认在 HDFS 的工作目录 -->
        <property>
            <name>hive.metastore.warehouse.dir</name>
            <value>/user/hive/warehouse</value>
        </property>
    </configuration>
    
  • 第三步:登录MySQL并创建元数据库(metastore)

    • mysql -uroot -p
    • create database metastore;
    • quit,退出MySQL客户端
  • 第四步:初始化Hive元数据库

    • bin/schematool -initSchema -dbType mysql -verbase
  • 启动Hive

    • /bin/hive



访问Hive的方式

使用元数据服务的方式访问 Hive

  • 第一步:在 hive-site.xml 文件中添加配置

        <!-- 指定存储元数据要连接的地址 -->
        <property>
            <name>hive.metastore.uris</name>
            <value>thrift://hadoop151:9083</value>
        </property>
    
  • 第二步:启动metastore

    # 前台启动,打印日志
    bin/hive --service metastore
    
    # 后台启动
    nohup bin/hive --service metastore >/dev/null 2>&1 &
    
  • 第三步:进入hive

    • bin/hive



使用 JDBC 方式访问 Hive

  • 第一步:在 hive-site.xml 文件中添加配置

        <!-- 指定存储元数据要连接的地址 -->
        <property>
            <name>hive.metastore.uris</name>
            <value>thrift://hadoop151:9083</value>
        </property>
        <!-- 指定 hiveserver2 连接的 host -->
        <property>
            <name>hive.server2.thrift.bind.host</name>
            <value>hadoop151</value>
        </property>
        <!-- 指定 hiveserver2 连接的端口号 -->
        <property>
            <name>hive.server2.thrift.port</name>
            <value>10000</value>
        </property>
    
  • 第二步:启动metastore

    bin/hive --service metastore

  • 第三步:启动 hiveserver2

    bin/hive --service hiveserver2

  • 第四步:启动 beeline 客户端

    • bin/beeline -u jdbc:hive2://hadoop151:10000 -n root



Hive 常见属性配置

运行日志信息配置

  • 将 /conf/hive-log4j2.properties.template 文件名改为 hive-log4j2.properties,并修改日志目录
    • property.hive.log.dir = /opt/software/hive/apache-hive-3.1.2-bin/logs



打印 当前库 和 表头

  • 在 hive-site.xml 中加入配置

        <property>
            <name>hive.cli.print.header</name>
            <value>true</value>
        </property>
        <property>
            <name>hive.cli.print.current.db</name>
            <value>true</value>
        </property>
    




2、Hive 数据类型

基本数据类型

Hive 数据类型Java 数据类型长度例子
TINYINTbyte1byte 有符号整数20
SMALINTshort2byte 有符号整数20
INTint4byte 有符号整数20
BIGINTlong8byte 有符号整数20
BOOLEANboolean布尔类型,true 或者falseTRUE FALSE
FLOATfloat单精度浮点数3.14159
DOUBLEdouble双精度浮点数3.14159
STRINGstring字符系列。可以指定字符集‘now is the time’ “for all good men”
TIMESTAMP时间类型
BINARY字节数组



集合数据类型

数据类型描述语法示例
STRUCT和c 语言中的 struct 类似,可通过“点”符号访问元素内容struct()例如struct<street:string, city:string>
MAPMAP是键-值对元组集合,使用数组表示法可以访问数据map()例如 map<string, int>
ARRAY数组是一组具有相同类型和名称的变量的集合Array()例如 array<string>



类型转化

  • 任何整数类型都可以隐式地转换为一个范围更广的类型,如 TINYINT 可以转换成 INT,INT 可以转换成 BIGINT
  • 所有整数类型、FLOAT 和 STRING 类型都可以隐式地转换成 DOUBLE
  • TINYINT、SMALLINT、INT 都可以转换为 FLOAT
  • BOOLEAN 类型不可以转换为任何其它的类型




3、DDL 数据定义

数据库

  • 显示数据库
    • show databases;
  • 过滤显示查询的数据库(查询数据库名为 hive 开头的)
    • show databases like 'hive*'
  • 显示数据库信息
    • desc database 数据库名称;
  • 显示数据库详细信息,extende
    • desc database extended 数据库名称;
  • 切换当前数据库
    • use 数据库名称;
  • 修改数据库(来设置这个数据库的属性信息)
    • alter database 数据库名称 set dbproperties('属性名'='属性内容');
  • 删除空数据库
    • drop database 数据库名称;
  • 删除非空数据库
    • drop database 数据库名称 cascade;



数据表

  • 建表语法

    CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name 
    [(col_name data_type [COMMENT col_comment], ...)] 
    [COMMENT table_comment]
    [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] 
    [CLUSTERED BY (col_name, col_name, ...)
    [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] 
    [ROW FORMAT row_format]
    [STORED AS file_format] 
    [LOCATION hdfs_path]
    [TBLPROPERTIES (property_name=property_value, ...)] 
    [AS select_statement]
    
    
    CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name  --EXTERNAL:创建外部表,IF NOT EXISTS:是否存在
    [(col_name data_type [COMMENT col_comment], ...)]  --列名  列类型  列注释
    [COMMENT table_comment]  --表注释
    [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]  --PARTITIONED BY:创建分区表
    [CLUSTERED BY (col_name, col_name, ...)]  --CLUSTERED BY:创建分桶表
    [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]  --SORTED BY:对桶中的字段进行排序
    [ROW FORMAT DELIMITED row_format]  --ROW FORMAT DELIMITED:一行数据分割的符号
    [STORED AS file_format]  --STORED AS:指定数据类型
    [LOCATION hdfs_path]  --LOCATION:指定表在 HDFS 上的存储位置
    [TBLPROPERTIES (property_name=property_value, ...)]  --TBLPROPERTIES:表的一些配置
    [AS select_statement]  --AS:后跟查询语句,根据查询结果创建表
    
    
    --创建数据表
    create external table if not exists psq(id int, name string)
    row format delimited fields terminated by ','
    stored as textfile
    location '/fzk';
    
  • 查询表的类型

    • desc formatted 数据表;
  • 将表修改成外部表(‘EXTERNAL’=‘TRUE’ : 区分大小写)

    • alter table 数据表 set tblproperties('EXTERNAL'='TRUE')
  • 将表修改成内部表(‘EXTERNAL’=‘FALSE’ : 区分大小写)

    • alter table 数据表 set tblproperties('EXTERNAL'='FALSE');
  • 重命名表

    • alter table 旧数据表名 rename to 新数据表名
  • 更新列

    • alter table 表名 change 旧列名 新列名 新列数据类型;
  • 增加和替换列(add:增加, replace:替换)

    • alter table jzx add|replace columns (列名 列数据类型);
  • 删除表

    • drop table 表名;




4、DML 数据操作

数据导入(五种)

  • 第一种:向表中装载数据(Load)

    • load data [local] inpath '数据的路径' [overwrite] into table 表名 [partition (partcoll=val,...)]
      • local:表示从本地加载数据到 hive 表;否则从HDFS 加载数据到 hive 表
      • inpath:表示加载数据的路径
      • overwrite:表示覆盖表中已有数据,否则表示追加
      • into table:表示加载到哪张表
      • partition:表示上传到指定分区
  • 第二种:通过查询语句向表中插入数据(insert)

    • insert [into|overwrite] table 表名 values(数据,...)
      • into:追加数据
      • overwrite:覆盖数据并添加
  • 第三种:查询语句中创建表并加载数据(As Select)(将table_2的数据加载到table_1中)

    • create table if not exists table_1 as select id, name from table_2
  • 第四种:将数据上传到 HDFS 的表的路径中

    • dfs -put /文件路径/文件名 /上传的hdfs路径
  • 第五种: Import 数据到指定 Hive 表中

    • 先用 export 导出后,再将数据导入

    • 将hdfs路径的数据导入到表中

      • import table 表名 from '/hdfs的路径'




数据导出

  • 第一种:insert 导出

    insert overwrite local directory '/路径'
    row format delimited fields terminated by '\t'
    select * from 表名;
    
    --解释
    insert overwrite local directory '/路径'  --local:导出到本地,若没有local则导出到HDFS
    row format delimited fields terminated by '\t'  --将查询的结构按照 '\t' 分隔符格式化
    select * from 表名;  --查询语句
    
  • 第二种:Export 导出到 HDFS 上

    • export table 表名 to /hdfs路径;



清除表中的数据(truncate)

  • truncate table 表名;




5、查询

普通查询

  • **基本查询、算术运算符、比较运算符、逻辑运算符、分组(group by、hiving)、连接(join)**查询语句和SQL一样



排序

全局排序(order by)

  • Order By:全局排序,只有一个 Reducer
  • ASC :升序(默认),DESC :降序
  • 用法和SQl一样



每个Reduce内部排序(Sort By)

  • Sort By:对于大规模的数据集 order by 的效率非常低。在很多情况下,并不需要全局排序,此时可以使用 sort by
  • Sort by 为每个 reducer 产生一个排序文件。每个 Reducer 内部进行排序,对全局结果集来说不是排序
  • select * from 表名 sort by 字段名 [asc|desc];



分区(Distribute By)

  • Distribute By: 在有些情况下,我们需要控制某个特定行应该到哪个 reducer,通常是为了进行后续的聚集操作。distribute by 子句可以做这件事。distribute by 类似 MR 中 partition (自定义分区),进行分区,结合 sort by 使用。
  • select * from 表名 distribute by 字段名1 sort by 字段名2 [asc|desc];



Cluster By

  • 当 distribute by 和 sorts by 字段相同时,可以使用 cluster by 方式。
  • cluster by 除了具有 distribute by 的功能外还兼具 sort by 的功能。但是排序只能是升序排序,不能指定排序规则为 ASC 或者 DESC
  • select * from 表名 cluster by 字段名;




6、分区表和分桶表

分区表

分区基本操作

  • 创建分区

    create table 表名(字段名 字段类型, ...)
    partitioned by (分区名称 分区类型)
    row format delimited fields terminated by '\t';
    
    --解释
    create table 表名(字段名 字段类型, ...)  --建表语句
    partitioned by (分区名称 分区类型)  --分区
    row format delimited fields terminated by '\t';  --行初始化
    
    --事例
    create table dept_partitioned(id int, name string, sal string)
    partitioned by (day string)
    row format delimited fields terminated by '\t';
    
  • 加载数据到表中

    load data local inpath '/本地文件' into table 表名 partition(分区名称=分区内容);
    
    --事例(将本地的dept001文件加载到dept_partitioned表的 'day=2021-04-22' 分区)
    load data local inpath '/opt/software/hive/data/partitioned/dept001' into table dept_partitioned partition(day='2021-04-22');
    
  • 查询分区表中数据

    select * from 表名 where 分区字段名 = 条件;
    
    --事例(查询分区为 day = '2021-04-22' 的数据)
    select * from dept_partitioned where day = '2021-04-22';
    
  • 增加分区

    alter table 表名 add partition(分区字段名=分区内容);
    
    --事例(添加分区为 day='2021-04-23')
    alter table dept_partition add partition(day='2021-04-23');
    
  • 删除分区

    alter table 表名 drop partition(分区字段名=条件);
    
    --事例(删除分区为 day='2021-04-23')
    alter table dept_partitioned drop partition(day='2021-04-23');
    
  • 列出分区表中的分区

    • show partitions 表名;



二级分区

  • 创建二级分区

    create table 表名(字段名 字段类型, ...)
    partitioned by (一级分区名称 一级分区类型, 二级分区名称 二级分区类型)
    row format delimited fields terminated by '\t';
    
    --解释
    create table 表名(字段名 字段类型, ...)  --建表语句
    partitioned by (一级分区名称 一级分区类型, 二级分区名称 二级分区类型)  --分区
    row format delimited fields terminated by '\t';  --行初始化
    
    --事例
    create table dept_partitioned(id int, name string, sal string)
    partitioned by (day string, hour string)
    row format delimited fields terminated by '\t';
    
  • 加载数据到表中

    load data local inpath '/本地文件' into table 表名 partition(一级分区名称=一级分区内容, 二级分区名称=二级分区内容);
    
    --事例(将本地的dept001文件加载到dept_partitioned表的 'day=2021-04-22, hour=10' 分区)
    load data local inpath '/opt/software/hive/data/partitioned/dept001' into table dept_partitioned partition(day='2021-04-22', hour='10');
    



动态分区调整

  • 关系型数据库中,对分区表 Insert 数据时候,数据库自动会根据分区字段的值,将数据插入到相应的分区中,Hive 中也提供了类似的机制,即动态分区(Dynamic Partition),只不过,使用 Hive 的动态分区,需要进行相应的配置

  • 开启动态分区参数设置

    • 开启动态分区功能(默认 true,开启)
      • set hive.exec.dynamic.partition=true;
    • 设置为非严格模式(动态分区的模式,默认 strict,表示必须指定至少一个分区为静态分区,nonstrict 模式表示允许所有的分区字段都可以使用动态分区)
      • set hive.exec.dynamic.partition.mode=nonstrict;
    • 在所有执行 MR 的节点上,最大一共可以创建多少个动态分区。默认 1000
      • set hive.exec.max.dynamic.partitions=1000;
    • 在每个执行 MR 的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即 day 字段有 365 个值,那么该参数就需要设置成大于 365,如果使用默认值 100,则会报错
      • set hive.exec.max.dynamic.partitions.pernode=100;
    • 整个 MR Job 中,最大可以创建多少个 HDFS 文件。默认 100000
      • set hive.exec.max.created.files=100000;
    • 当有空分区生成时,是否抛出异常。一般不需要设置。默认 false
      • set hive.error.on.empty.partition=false;



分桶表

  • 创建分桶

    create table 表名(字段名 字段类型, ...)
    clustered by(字段名)
    into 4 buckets
    row format delimited fields terminated by '\t';
    
    --解释
    create table 表名(字段名 字段类型, ...)  --建表语句
    clustered by(字段名)  --分桶
    into 4 buckets  --分四个分桶
    row format delimited fields terminated by '\t';  --行格式化
    
    --事例
    create table bucket(id int, name string)
    clustered by(id)
    into 4 buckets
    row format delimited fields terminated by '\t';
    
  • 导入数据到分桶表

    load data local inpath '/本地文件' into table 表名;
    
    --事例(将本地bucket.txt文件的数据导入到分桶表中)
    load data local inpath '/opt/software/hive/data/bucket/bucket.txt' into table bucket;
    
  • 查看分桶表数据

    • select * from 表名;
  • 抽样查询

    • 对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。Hive 可以通过对表进行抽样来满足这个需求

    • 语法: TABLESAMPLE(BUCKET x OUT OF y)x 的值必须小于等于 y 的值

      select * from 表名 tablesample(bucket x out of y on id);
      
      --事例
      select * from bucket tablesample(bucket 1 out of 4 on id);
      




7、函数

系统内置函数

  • 查看系统自带的函数
    • show functions
  • 显示自带的函数的用法
    • desc function 函数名称
  • 详细显示自带的函数的用法
    • desc function extended 函数名称



常用内置函数

  • NVL:给值为 NULL 的数据赋值,它的格式是 NVL( value,default_value)。它的功能是如果 value 为 NULL,则 NVL 函数返回 default_value 的值,否则返回 value 的值,如果两个参数都为 NULL ,则返回 NULL

    select nvl(字段名, 数据) from 表名;
    
    --例子:当comm字段的值为null,则用 -1 代替
    select comm,nvl(comm, -1) from emp;
    
  • CASE WHEN THEN ELSE END

    --例子
    select
        dept_id,
        sum(case sex when '男' then 1 else 0 end) male_count,    --sex字段的值为男值为 1,否则 0
        sum(case sex when '女' then 1 else 0 end) female_count   --sex字段的值为女值为 1,否则 0
    from emp_sex
    group by dept_id;
    



行转列

  • CONCAT(concat)concat(str1, str2, ... strN)

    • 将多个字符串拼接后输出

      select concat('a', '-', 'b')  --输出: a-b
      
  • CONCAT_WS(concat_ws)concat_ws(separator, [string | array(string)]+)

    • 它是一个特殊形式的 CONCAT()。第一个参数是其他参数间的分隔符

      select concat_ws('-', 'a', 'b', 'c', 'd')  --输出: a-b-c-d
      
  • COLLECT_SET(collect_set)collect_set(x)

    • 函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生 Array 类型字段

      select collect_set(deptno) from dept;  -- 将 deptno 字段去重,并产生 Array 类型字段
      



列转行

  • EXPLODE(explode)explode(a)

    • 将 hive 一列中复杂的 Array 或者 Map 结构拆分成多行

      -- deptno 字段为 Array 或者 Map 类型,将其拆分成多行
      select explode(deptno) from dept;
      
  • LATERAL VIEW(lateral view)lateral view udtf(expression) tableAlias AS columnAlias

    • 用于和 split, explode 等 UDTF 一起使用,能够将一列数据拆成多行数据,在此基础上可对拆分后的数据进行聚合

      SELECT
          movie,
          category_name
      FROM
      	movie_info lateral view explode(split(category,",")) movie_info_tmp AS category_name;  -- 将 category 字段的数据按照 ',' 切割,并显示 
      



窗口函数

相关函数说明
  • OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化
    • CURRENT ROW(current row):当前行
    • n PRECEDING(n preceding):往前 n 行数据
    • n FOLLOWING(n following):往后 n 行数据
    • UNBOUNDED(unbounded):起点/终点
      • UNBOUNDED PRECEDING(unbounded preceding):表示从前面的起点,
      • UNBOUNDED FOLLOWING(unbounded following):表示到后面的终点
  • LAG(lag) :往前第 n 行数据
    • lag (字段名, n, 默认数据) over (...)
  • LEAD(lead):往后第 n 行数据
    • lead (字段名, n, 默认数据) over (...)
  • NTILE(ntile):把有序窗口的行分发到指定数据的组中,各个组有编号,编号从 1 开始,对于每一行,NTILE 返回此行所属的组的编号。注意n 必须为 int 类型
    • ntile(n)
  • Rank
    • rank() :排序相同时会重复,总数不会变(例如第二名重复:1 2 2 4)
    • dense_rank() :排序相同时会重复,总数会减少(例如第二名重复:1 2 2 3)
    • row_number() :会根据顺序计算(例如第二名重复:1 2 3 4)



使用
-- over() 的使用
select name, orderdate, cost,
    sum(cost) over() as sample1,  --所有行相加
    sum(cost) over(partition by name) as sample2,  --按 name 分组,组内数据相加
    --按 name 分组,按 orderdate 升序,组内数据累加
    sum(cost) over(partition by name order by orderdate) as sample3,  
    --按 name 分组,按 orderdate 升序,由起点到当前行的聚合 相加
    sum(cost) over(partition by name order by orderdate rows between UNBOUNDED PRECEDING and current row ) as sample4 ,  
    sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING and current row) as sample5,  --当前行和前面一行做聚合
    sum(cost) over(partition by name order by orderdate rows between 1 PRECEDING AND 1 FOLLOWING ) as sample6,  --当前行和前边一行及后面一行做聚合
    sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7  --当前行及后面所有行做聚合
from business;


-- lag() 的使用
select name,orderdate,cost,
	--显示orderdate字段的往前 1 行数据,若为null在显示为 '1900-01-01'
    lag(orderdate, 1, '1900-01-01') over(partition by name order by orderdate ) as time1,
    ----显示orderdate字段的往后 2 行数据
    lead(orderdate, 2) over (partition by name order by orderdate) as time2  
from business;


--ntile() 的使用(查询前20%的数据)
select * from (
    --按照orderdate升序排列,并将数据分为 5 份
	select name, orderdate, cost, ntile(5) over(order by orderdate) sorted
	from business) t
where sorted = 1;


-- rank 的使用
select name, subject, score,
    rank() over(partition by subject order by score desc) rp,  --rank()的使用
    dense_rank() over(partition by subject order by score desc) drp,  --dense_rank()的使用,
    row_number() over(partition by subject order by score desc) rmp  --row_number()的使用,
from score;



其他常用函数

----------------------常用日期函数
--unix_timestamp:返回当前或指定时间的时间戳	
select unix_timestamp();
select unix_timestamp("2020-10-28",'yyyy-MM-dd');

--from_unixtime:将时间戳转为日期格式
select from_unixtime(1603843200);

--current_date:当前日期
select current_date;

--current_timestamp:当前的日期加时间
select current_timestamp;

--to_date:抽取日期部分
select to_date('2020-10-28 12:12:12');

--year:获取年
select year('2020-10-28 12:12:12');

--month:获取月
select month('2020-10-28 12:12:12');

--day:获取日
select day('2020-10-28 12:12:12');

--hour:获取时
select hour('2020-10-28 12:12:12');

--minute:获取分
select minute('2020-10-28 12:12:12');

--second:获取秒
select second('2020-10-28 12:12:12');

--weekofyear:当前时间是一年中的第几周
select weekofyear('2020-10-28 12:12:12');

--dayofmonth:当前时间是一个月中的第几天
select dayofmonth('2020-10-28 12:12:12');

--months_between: 两个日期间的月份
select months_between('2020-04-01','2020-10-28');

--add_months:日期加减月
select add_months('2020-10-28',-3);

--datediff:两个日期相差的天数
select datediff('2020-11-04','2020-10-28');

--date_add:日期加天数
select date_add('2020-10-28',4);

--date_sub:日期减天数
select date_sub('2020-10-28',-4);

--last_day:日期的当月的最后一天
select last_day('2020-02-30');

--date_format(): 格式化日期
select date_format('2020-10-28 12:12:12','yyyy/MM/dd HH:mm:ss');

----------------------常用取整函数
--round: 四舍五入
select round(3.14);
select round(3.54);

--ceil:  向上取整
select ceil(3.14);
select ceil(3.54);

--floor: 向下取整
select floor(3.14);
select floor(3.54);

----------------------常用字符串操作函数
--upper: 转大写
select upper('low');

--lower: 转小写
select lower('low');

--length: 长度
select length("atguigu");

--trim:  前后去空格
select trim(" atguigu ");

--lpad: 向左补齐,到指定长度
select lpad('atguigu',9,'g');

--rpad:  向右补齐,到指定长度
select rpad('atguigu',9,'g');

--regexp_replace:使用正则表达式匹配目标字符串,匹配成功后替换!
SELECT regexp_replace('2020/10/25', '/', '-');

----------------------集合操作
--size: 集合中元素的个数
select size(friends) from test3;

--map_keys: 返回map中的key
select map_keys(children) from test3;

--map_values: 返回map中的value
select map_values(children) from test3;

--array_contains: 判断array中是否包含某个元素
select array_contains(friends,'bingbing') from test3;

--sort_array: 将array中的元素排序
select sort_array(friends) from test3;



自定义函数

  • Hive 自带了一些函数,比如:max/min 等,但是数量有限,自己可以通过自定义 UDF 来方便的扩展
  • 当 Hive 提供的内置函数无法满足你的业务处理需要时,此时就可以考虑使用用户自定义函数

自定义UDF函数

  • 需求:自定义一个 UDF 实现计算给定字符串的长度

    select my_len("fzk")  -- 4
    
  • 第一步:创建Maven工程,并导入依赖(pom.xml)

    <dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.2</version>
        </dependency>
    </dependencies>
    
  • 第二步:编写实现类

    import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
    import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
    import org.apache.hadoop.hive.ql.metadata.HiveException;
    import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
    import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
    import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
    
    public class MyUDF extends GenericUDF {
        public ObjectInspector initialize(ObjectInspector[] objectInspectors) throws UDFArgumentException {
            //判断输入参数的个数
            if(objectInspectors.length != 1){
                throw new UDFArgumentLengthException("只能输入一个参数");
            }
    
            //函数本身返回值为 int,需要返回 int 类型的鉴别器对象
            return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
        }
    
        public Object evaluate(DeferredObject[] deferredObjects) throws HiveException {
            String data = deferredObjects[0].get().toString();
            if(data == null){
                return 0;
            }
    
            return data.length();
        }
    
        public String getDisplayString(String[] strings) {
            return null;
        }
    }
    
  • 第三步:将程序打包成 jar 包上传到服务器上

  • 第四步:创建函数

    • 方法一:创建永久函数与开发好的java class关联(开发环境使用)

      # 第一步:将jar包上传到hdfs上
      hadoop fs -put jar包全名称 /上传到hdfs的路径
      
      # 第二步:创建永久函数
      hive (default)> create function 函数名称 as '全限定类名' using jar 'jar包在hdfs地址';
      #例子
      hive (default)> create function my_len as 'com.itfzk.hive.udf.MyUDF' using jar 'hdfs://hadoop151:8020/user/hive/jars/my_len.jar';
      
    • 方法二:创建临时函数与开发好的 java class 关联(在 hive 客户端中执行)(开发环境不用)

      #第一步:在 hive 客户端中将 jar 包添加到 hive中
      hive (default)> add jar /上传的jar包的位置和名称;
      
      #第二步:创建临时函数
      hive (default)> create temporary function 函数别名 as "java类的全限定类名";
      # 例子
      hive (default)> create temporary function my_len as "com.itfzk.hive.udf.MyUDF";
      
  • 第五步:使用

    • select my_len("fzk")



自定义UDTF函数

  • 需求:自定义一个 UDTF 实现将一个任意分割符的字符串切割成独立的单词

    select my_udtf("fff,zzz,kkk", ",")
    --输出
    fff
    zzz
    kkk
    
  • 第一步:创建Maven工程,并导入依赖(pom.xml)

    <dependencies>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.2</version>
        </dependency>
    </dependencies>
    
  • 第二步:编写实现类

    import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
    import org.apache.hadoop.hive.ql.metadata.HiveException;
    import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
    import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
    import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
    import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
    import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MyUDTF extends GenericUDTF {
    
        @Override
        public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
            //定义输出数据的列名和类型
            List<String> fieldNames = new ArrayList<String>();
            List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
            //列名
            fieldNames.add("word");
            //类型
            fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
            return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames, fieldOIs);
        }
    
        public void process(Object[] objects) throws HiveException {
            //获取数据和分割条件,并对数据进行分割
            String data = objects[0].toString();
            String regex = objects[1].toString();
            String[] fields = data.split(regex);
            //输出内容
            List<String> outList = new ArrayList<String>();
            //遍历分割好的数据并写出
            for (String field : fields) {
                outList.clear();
                outList.add(field);
                //将集合内容写出
                forward(outList);
            }
        }
    
        public void close() throws HiveException {
    
        }
    }
    
  • 第三步:将程序打包成 jar 包上传到服务器上

  • 第四步:创建函数

    • 方法一:创建永久函数与开发好的java class关联(开发环境使用)

      # 第一步:将jar包上传到hdfs上
      hadoop fs -put jar包全名称 /上传到hdfs的路径
      
      # 第二步:创建永久函数
      hive (default)> create function 函数名称 as '全限定类名' using jar 'jar包在hdfs地址';
      #例子
      hive (default)> create function my_udtf as 'com.itfzk.hive.udtf.MyUDTF' using jar 'hdfs://hadoop151:8020/user/hive/jars/my_udtf.jar';
      
    • 方法二:创建临时函数与开发好的 java class 关联(在 hive 客户端中执行)(开发环境不用)

      #第一步:在 hive 客户端中将 jar 包添加到 hive中
      hive (default)> add jar /上传的jar包的位置和名称;
      
      #第二步:创建临时函数
      hive (default)> create temporary function 函数别名 as "java类的全限定类名";
      # 例子
      hive (default)> create temporary function my_udtf as "com.itfzk.hive.udtf.MyUDTF";
      
  • 第五步:使用

    • select my_udtf("fff,zzz,kkk", ",")




8、压缩和存储

压缩

压缩介绍

压缩算法对比介绍

压缩格式Hadoop 自带?算法文件扩展名是否可切片换成压缩格式后,原来的程序是否需要修改
DEFLATE是,直接使用DEFLATE.deflate和文本处理一样,不需要修改
Gzip是,直接使用DEFLATE.gz和文本处理一样,不需要修改
bzip2是,直接使用bzip2.bz2和文本处理一样,不需要修改
LZO否,需要安装LZO.lzo需要建索引,还需要指定输入格式
Snappy是,直接使用Snappy.snappy和文本处理一样,不需要修改

压缩性能的比较

压缩算法原始文件大小压缩文件大小压缩速度解压速度
gzip8.3GB1.8GB17.5MB/s58MB/s
bzip28.3GB1.1GB2.4MB/s9.5MB/s
LZO8.3GB2.9GB49.3MB/s74.6MB/s
Snappy250MB/s500MB/s

压缩算法的优缺点比较

压缩算法优点缺点
Gzip压缩率比较高不支持 Split;压缩/解压速度一般
Bzip2压缩率高;支持 Split压缩/解压速度慢
Lzo压缩/解压速度比较快;支持 Split压缩率一般;想支持切片需要额外创建索引
Snappy压缩和解压缩速度快不支持 Split;压缩率一般



开启 Map 输出阶段压缩

--开启 hive 中间传输数据压缩功能
set hive.exec.compress.intermediate=true;

--开启 mapreduce 中 map 输出压缩功能
set mapreduce.map.output.compress=true;

--设置 mapreduce 中 map 输出数据的压缩方式
set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;



开启 Reduce 输出阶段压缩

--开启 hive 最终输出数据压缩功能
set hive.exec.compress.output=true;

--开启 mapreduce 最终输出数据压缩
set mapreduce.output.fileoutputformat.compress=true;

--设置 mapreduce 最终数据输出压缩方式
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;

--设置 mapreduce 最终数据输出压缩为块压缩
set mapreduce.output.fileoutputformat.compress.type=BLOCK;



文件存储格式

  • Hive 支持的存储数据的格式主要有:TEXTFILESEQUENCEFILEORCPARQUET

TextFile 存储格式

  • 默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合 Gzip、Bzip2 使用,但使用 Gzip 这种方式,hive 不会对数据进行切分,从而无法对数据进行并行操作

    --创建 TextFile 存储格式
    create table log_text (
        字段名 字段类型,
    	...
    )
    row format delimited fields terminated by '\t'
    stored as textfile;  --TextFile 存储格式
    



Parquet 存储格式

  • Parquet 文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此 Parquet 格式文件是自解析的

    --创建 Parquet 存储格式
    create table log_parquet(
    	字段名 字段类型,
    	...
    )
    row format delimited fields terminated by '\t'
    stored as parquet;  -- Parquet 存储格式
    



Orc 存储格式

  • 每个 Orc 文件由 1 个或多个 stripe 组成,每个 stripe 一般为 HDFS的块大小,每一个 stripe 包含多条记录,这些记录按照列进行独立存储

    --创建 Orc 存储格式
    create table log_orc(
    	字段名 字段类型,
    	...
    )
    row format delimited fields terminated by '\t'
    stored as orc  --Orc 存储格式
    tblproperties("orc.compress"="NONE"); -- 设置 orc 存储不使用压缩
    



存储和压缩结合

--创建一个 SNAPPY 压缩的 ORC 存储方式
create table log_orc_snappy(
    字段名 字段类型,
	...
)
row format delimited fields terminated by '\t'
stored as orc  --Orc 存储格式
tblproperties("orc.compress"="SNAPPY");  --SNAPPY 压缩



--创建一个 SNAPPY 压缩的 parquet 存储方式
create table log_parquet_snappy(
    字段名 字段类型,
	...
)
row format delimited fields terminated by '\t'
stored as parquet  --parquet 存储格式
tblproperties("parquet.compression"="SNAPPY");  --SNAPPY 压缩




9、常用参数设置

参数都是默认值

---------------------------- Fetch 抓取
--Fetch 抓取,默认是more,none:查询语句都走reduce
set hive.fetch.task.conversion=more


---------------------------- 本地模式
--开启本地 MapReduce
set hive.exec.mode.local.auto=true; 
--设置 本地MapReduce 的最大输入数据量,当输入数据量小于这个值时采用 本地MapReduce 的方式,默认为 134217728,即 128M
set hive.exec.mode.local.auto.inputbytes.max=134217728;
--设置 本地MapReduce 的最大输入文件个数,当输入文件个数小于这个值时采用 本地MapReduce 的方式,默认为 4
set hive.exec.mode.local.auto.input.files.max=4;


---------------------------- 小表大表 Join(MapJOIN)
--设置自动选择 Mapjoin
set hive.auto.convert.join=true;
--大表小表的阈值设置(默认 25M 以下认为是小表)
set hive.mapjoin.smalltable.filesize=25000000;


---------------------------- 小文件进行合并
--对小文件进行合并的功能
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
--在 map-only 任务结束时合并小文件
set hive.merge.mapfiles=true;
--在 map-reduce 任务结束时合并小文件
set hive.merge.mapredfiles=true;
--合并文件的大小,默认 256M
set hive.merge.size.per.task=268435456;
--当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge
set hive.merge.smallfiles.avgsize = 16777216;


---------------------------- 合理设置 Reduce 数
--调整 reduce 个数
set mapreduce.job.reduces=-1;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值