Hive基础知识大全
1、Hive根本概念
1.1、Hive简介
Hive本质是将SQL转化为MapReduce的任务进行计算,底层由HDFS来提供数据存储。说白了hive可以理解为一个将SQL转换为MapReduce的任务的工具,乃至更进一步说hive就是MapReduce的一个客户端。
1.2、什么是Hive(口试题)
- Hive是数据库建模工具之一
- 可以向Hive传入一条交互式SQL,在海量数据中查询分析得到结果的平台
1.3、为什么要使用Hive
- 假如使用Hadoop的话,人员学习成本高,MapReduce的实现复杂查询逻辑的开发难度较大。
- 假如使用Hive的话,可以直接操纵接口接纳类SQL语法,免去了写MapReduce,大大进步了开发服从,而且功能扩展很方便(比如:开窗函数)
1.4、Hive的特点
- 可扩展性:Hive可以自由的扩展集群的规模、一样平常环境下不需要重启服务
- 延伸性:Hive支持自定函数,用户可以根据自己的需求来实现自己的函数
- 容错:纵然节点出现错误,SQL仍然可以完成实行
1.5、Hive的优缺点
长处
- 操纵接口接纳类SQL语法,提供快速开发的能力(简单,易上手)
- 避免了去写MapReduce,减少了开发人员的学习成本
- 由于Hive的延迟性比力高,因此Hive常用于数据分析,实用于对实时性要求不高的场合
- 由于Hive的实行延迟性比力高(不断的开关JVM虚拟机),Hive的优势在于处置惩罚大数据,对于小数据没有优势
- Hive支持自定义函数,用户可以根据自己的需求来实现满足自己需求的函数
- 集群可以自由扩展而且有良好的容错性,节点出现问题SQL仍然可以完成实行
缺点
- Hive的HiveSql表达能力有限
- 迭代是算法无法表达(反复调用,mr之间独立,只有一个map一个reduce,反复开关。名词表明:
反复调用:迭代式算法需要多次调用同一组计算,每次调用的结果会影响下一次调用的输入。
MR之间独立:传统的MapReduce任务是独立的,每个任务之间没有状态共享。这意味着每次MapReduce任务运行时,不知道之前任务的结果。
只有一个map和一个reduce:在描述迭代式算法时,这句话可能意味着每次迭代只有一个Map阶段和一个Reduce阶段,但每次都需要重新启动MapReduce作业。
反复开关:每次迭代需要启动和关闭MapReduce作业,这带来了大量的开销,因为每次启动和关闭作业都需要花费时间和资源。)
- Hive的服从比力低
- Hive自动天生的MapReduce作业,通常环境下不敷智能化
- Hive调优比力困难难,粒度较粗(HiveSql根据模本转成MapReduce,不能像自己编写的MapReduce一样精致,无法控制在map处置惩罚数据还是reduce处置惩罚数据)
迭代算法:迭代式算法是指那些需要反复实行同一组计算步骤的算法,每次迭代的结果依赖于前一次迭代的结果。
1.6、hive和mysql的区别
1.7、hive的应用场景
- 日志分析:大部门互联网公司使用hive进行日志分析,如百度、淘宝等。
- 统计一个网站一个时间段内的pv,uv,SKU,SPU,SKC
- 多维度数据分析(数据堆栈)
- 海量布局化(关系型)数据离线分析
- 构建数据堆栈
名词表明
- PV(Page View)访问量, 即页面浏览量或点击量,衡量网站用户访问的网页数量;在一定统计周期内用户每打开或刷新一个页面就记录1次,多次打开或刷新同一页面则浏览量累计。
- UV(Unique Visitor)独立访客,统计1天内访问某站点的用户数(以cookie为依据);访问网站的一台电脑客户端为一个访客。可以理解成访问某网站的电脑的数量。网站判断来访电脑的身份是通过来访电脑的cookies实现的。如果更换了IP后但不清除cookies,再访问相同网站,该网站的统计中UV数是不变的。如果用户不保存cookies访问、清除了cookies或者更换设备访问,计数会加1。00:00-24:00内相同的客户端多次访问只计为1个访客。
复制代码 1.8、Hive架构
1.8.1、Hive Client
Hive Client 是与Hive交互的工具,用户可以通过它提交HiveQL查询、实行数据操纵并获取结果。
- Client(hive shell)
- 启动:可以通过运行hive命令启动Hive CLI。
- 功能:支持实行HiveQL查询、检察表布局、插入数据、创建表等操纵。
- 局限性:由于CLI是基于命令行的,操纵可能不如图形界面直观,且在某些环境下(如长时间运行的查询)可能不太方便。
- JDBC/ODBC(java访问hive)
- JDBC客户端:例如,Java步伐可以通过Hive的JDBC驱动与HiveServer2进行连接和操纵。
- ODBC客户端:例如,使用ODBC接口,可以在Windows环境中使用Excel等工具连接Hive。
- 优势:提供与多种应用和工具的集成能力,适合构建复杂的数据处置惩罚和分析应用。
- Beeline(Beeline是Hive的JDBC客户端,提供了一种与HiveServer2交互的方式)
- 启动:通过运行beeline命令启动,可以连接到本地或远程的HiveServer2实例。
- 优势:相比于Hive CLI,Beeline更加轻量级,而且支持更好的多用户并发访问。
- 使用方式:范例的连接命令是!connect jdbc:hive2://hostname:port/default,然后输入用户名和密码进行连接。
- 特性:支持更丰富的SQL语法、参数化查询、脚本实行等。
1.8.2、Hive Metastore(Hive的元数据存储)
在Apache Hive中,Metastore(元数据存储)饰演着非常重要的脚色,它负责管理和存储Hive表的元数据信息。
元数据存储在数据库中,默认存在自带的derby数据库(单用户局限性)中,保举使用Mysql进行存储。
- 作用:对Hive表的源数据进行存储,元数据包括:表名、表所属的数据库(默认default数据库)、表的拥有者、列名、表的分区字段、表的类型(内部表还是外部表)、表的存储格式、表的存储位置。
1.8.3、sql语句是如何转换成MapReduce任务的(重点!!!!!!!!!!!!)
- 剖析器(SQL Parser):将SQL字符串转换成抽象语法树(从3.x版本后,转换成一些stage),在此阶段,Hive会检查语法错误:比如白哦是否在、字段是否存在。
- 编译器(Physical Plan):将抽象语法树(从3.x版本后,转换成一些stage)生存逻辑实行计划。
- 优化器(Query Optimizer):对逻辑实行计划进行优化。
- 实行器(Execution):将逻辑实行计划转换成可以运行的物理实行计划,也就是MapReduce任务
- 结果处置惩罚:Hive将天生的MapReduce作业提交给Hadoop集群中的YARN进行实行,在任务实行完成后,将结果返回给用户。
2、Hive的三种交互方式
(1) 第一种交互方式
shell交互Hive,用命令hive启动一个hive的shell命令行,在命令行中输入sql或者命令来和Hive交互。
- 服务端启动metastore服务(后台启动):nohup hive --service metastore &
- 进入命令:hive
- 退出命令行:quit;
复制代码 (2) 第二种交互方式
Hive启动为一个服务器,对外提供服务,其他机器可以通过客户端通过协议连接到服务器,来完成访问操纵,这是生产环境用法最多的
- 服务端启动hiveserver2服务:
- nohup hive --service metastore &
- nohup hiveserver2 &
- 需要稍等一下,启动服务需要时间:
- beeline -u jdbc:hive2://master:10000 -n root
- 退出命令行:!exit
复制代码 (3) 第三种交互方式
使用 –e 参数来直接实行hql的语句
- bin/hive -e "show databases;
- "
复制代码 使用 –f 参数通过指定文本文件来实行hql的语句
特点:实行完sql后,回到linux命令行。
- vim hive.sql
- create database bigdata30_test;
- use bigdata30_test;
- create table test1
- (
- id bigint,
- name string
- )
- ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
- show tables;
复制代码 (4) hive cli和beeline cli的区别
3、Hive元数据
Hive元数据库中一些重要的表布局及用途**,方便Impala、SparkSQL、Hive等组件访问元数据库的理解。
1、存储Hive版本的元数据表(VERSION),该表比力简单,但很重要,假如这个表出现问题,根本进不来Hive-Cli。比如该表不存在,当启动Hive-Cli的时间,就会报错“Table ‘hive.version’ doesn’t exist”
2、Hive数据库相干的元数据表(DBS、DATABASE_PARAMS)
DBS:该表存储Hive中所有数据库的根本信息。
DATABASE_PARAMS:该表存储数据库的相干参数。
3、Hive表和视图相干的元数据表
主要有TBLS、TABLE_PARAMS、TBL_PRIVS,这三张表通过TBL_ID关联。
TBLS:该表中存储Hive表,视图,索引表的根本信息。
TABLE_PARAMS:该表存储表/视图的属性信息。
TBL_PRIVS:该表存储表/视图的授权信息。
4、Hive文件存储信息相干的元数据表
主要涉及SDS、SD_PARAMS、SERDES、SERDE_PARAMS,由于HDFS支持的文件格式很多,而建Hive表时间也可以指定各种文件格式,Hive在将HQL剖析成MapReduce时间,需要知道去哪里,使用哪种格式去读写HDFS文件,而这些信息就保存在这几张表中。
SDS:该表保存文件存储的根本信息,如INPUT_FORMAT、OUTPUT_FORMAT、是否压缩等。TBLS表中的SD_ID与该表关联,可以获取Hive表的存储信息。
SD_PARAMS: 该表存储Hive存储的属性信息。
SERDES:该表存储序列化使用的类信息。
SERDE_PARAMS:该表存储序列化的一些属性、格式信息,比如:行、列分隔符。
5、Hive表字段相干的元数据表
主要涉及COLUMNS_V2:该表存储表对应的字段信息。
4、Hive的根本操纵
4.1 Hive库操纵
4.1.1 创建数据库
1)创建一个数据库,数据库在HDFS上的默认存储路径是/user/hive/warehouse/*.db。
2)避免要创建的数据库已经存在错误,增加if not exists判断。(尺度写法)
- create database [if not exists] testdb;
- create database if not exists bigdata30_test2;
复制代码 4.1.2 创建数据库和位置
- create database if not exists bigdata30_test3 location '/bigdata30/liliangdb';
复制代码 4.1.3 修改数据库
数据库的其他元数据信息都是不可更改的,包括数据库名和数据库所在的目录位置。(重点关注哪些不能改,以及为什么!!)
- alter database dept set dbproperties('createtime'='20220531');
复制代码 4.1.4 数据库详细信息
1)表现数据库(show)
2)可以通过like进行过滤
- show databases like 't*';
复制代码 3)检察详情(desc)
4)切换数据库(use)
4.1.5 删除数据库(将删除的目录移动到回收站中)
1)最简写法
2)假如删除的数据库不存在,最好使用if exists判断数据库是否存在。否则会报错:FAILED: SemanticException [Error 10072]: Database does not exist: db_hive
- drop database if exists testdb;
复制代码 3)假如数据库不为空,使用cascade命令进行逼迫删除。报错信息如下FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. InvalidOperationException(message atabase db_hive is not empty. One or more tables exist.)
- drop database if exists testdb cascade;
复制代码 4.2、Hive数据类型
4.2.1、基础数据类型
类型Java数据类型描述TINYINTbyte8位有符号整型。取值范围:-128~127。SMALLINTshort16位有符号整型。取值范围:-32768~32767。INTint32位有符号整型。取值范围:-2 31 ~2 31 -1。BIGINTlong64位有符号整型。取值范围:-2 63 +1~2 63 -1。BINARY二进制数据类型,目前长度限定为8MB。FLOATfloat32位二进制浮点型。DOUBLEdouble64位二进制浮点型。DECIMAL(precision,scale)10进制精确数字类型。precision:表现最多可以表现多少位的数字。取值范围:1 <= precision <= 38。scale:表现小数部门的位数。取值范围: 0 <= scale <= 38。假如不指定以上两个参数,则默认为decimal(10,0)。VARCHAR(n)变长字符类型,n为长度。取值范围:1~65535。CHAR(n)固定长度字符类型,n为长度。最大取值255。长度不足则会填充空格,但空格不参与比力。STRINGstring字符串类型,目前长度限定为8MB。DATE日期类型,格式为yyyy-mm-dd。取值范围:0000-01-01~9999-12-31。DATETIME日期时间类型。取值范围:0000-01-01 00:00:00.000~9999-12-31 23.59:59.999,精确到毫秒。TIMESTAMP与时区无关的时间戳类型。取值范围:0000-01-01 00:00:00.000000000~9999-12-31 23.59:59.999999999,精确到纳秒。说明 对于部门时区相干的函数,例如cast( as string),要求TIMESTAMP按照与当前时区符合的方式来展现。BOOLEANbooleanBOOLEAN类型。取值:True、False。 4.2.2、复杂数据类型
类型定义方法构造方法ARRAYarray<int>``array<struct<a:int, b:string>>array(1, 2, 3)``array(array(1, 2), array(3, 4))MAPmap<string, string>``map<smallint, array<string>>map(“k1”, “v1”, “k2”, “v2”)``map(1S, array(‘a’, ‘b’), 2S, array(‘x’, ‘y’))STRUCTstruct<x:int, y:int>struct<field1:bigint, field2:array<int>, field3:map<int, int>> named_struct(‘x’, 1, ‘y’, 2)named_struct(‘field1’, 100L, ‘field2’, array(1, 2), ‘field3’, map(1, 100, 2, 200)) Hive有三种复杂数据类型ARRAY、MAP 和 STRUCT。ARRAY和MAP与Java中的Array和Map雷同,而STRUCT与C语言中的Struct雷同,它封装了一个定名字段集合,复杂数据类型允许任意条理的嵌套。还有一个uniontype< 所有类型,所有类型… > 。
数组:array< 所有类型 >;
Map < 根本数据类型,所有数据类型 >;
struct < 名:所有类型[注释] >;
uniontype< 所有类型,所有类型… >
4.3、Hive表操纵
Hive的存储格式:
Hive没有专门的数据文件格式,常见的有以下几种:
TEXTFILE
SEQUENCEFILE
AVRO
RCFILE
ORCFILE
PARQUET
- TextFile:
- TEXTFILE 即正常的文本格式,是Hive默认文件存储格式,因为大多数情况下源数据文件都是以text文件格式保存(便于查看验数和防止乱码)。此种格式的表文件在HDFS上是明文,可用hadoop fs -cat命令查看,从HDFS上get下来后也可以直接读取。
- TEXTFILE 存储文件默认每一行就是一条记录,可以指定任意的分隔符进行字段间的分割。但这个格式无压缩,需要的存储空间很大。虽然可结合Gzip、Bzip2、Snappy等使用,使用这种方式,Hive不会对数据进行切分,从而无法对数据进行并行操作。
- 一般只有与其他系统由数据交互的接口表采用TEXTFILE 格式,其他事实表和维度表都不建议使用。
- RCFile:
- Record Columnar的缩写。是Hadoop中第一个列文件格式。能够很好的压缩和快速的查询性能。通常写操作比较慢,比非列形式的文件格式需要更多的内存空间和计算量。 RCFile是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。其次,块数据`列式存储`,有利于数据压缩和快速的列存取。
- ORCFile:
- Hive从0.11版本开始提供了ORC的文件格式,ORC文件不仅仅是一种列式文件存储格式,最重要的是有着很高的压缩比,并且对于MapReduce来说是可切分(Split)的。因此,在Hive中使用ORC作为表的文件存储格式,不仅可以很大程度的节省HDFS存储资源,而且对数据的查询和处理性能有着非常大的提升,因为ORC较其他文件格式压缩比高,查询任务的输入数据量减少,使用的Task也就减少了。ORC能很大程度的节省存储和计算资源,但它在读写时候需要消耗额外的CPU资源来压缩和解压缩,当然这部分的CPU消耗是非常少的。
- Parquet:
- 通常我们使用关系数据库存储结构化数据,而关系数据库中使用数据模型都是扁平式的,遇到诸如数组、Map和自定义Struct的时候就需要用户在应用层解析。但是在大数据环境下,通常数据的来源是服务端的埋点数据,很可能需要把程序中的某些对象内容作为输出的一部分,而每一个对象都可能是嵌套的,所以如果能够原生的支持这种数据,这样在查询的时候就不需要额外的解析便能获得想要的结果。Parquet的灵感来自于2010年Google发表的Dremel论文,文中介绍了一种支持嵌套结构的存储格式,并且使用了列式存储的方式提升查询性能。Parquet仅仅是一种存储格式,它是语言、平台无关的,并且不需要和任何一种数据处理框架绑定。这也是parquet相较于orc的仅有优势:支持嵌套结构。Parquet 没有太多其他可圈可点的地方,比如他不支持update操作(数据写成后不可修改),不支持ACID等.
- SEQUENCEFILE:
- SequenceFile是Hadoop API 提供的一种二进制文件,它将数据以<key,value>的形式序列化到文件中。这种二进制文件内部使用Hadoop 的标准的Writable 接口实现序列化和反序列化。它与Hadoop API中的MapFile 是互相兼容的。Hive 中的SequenceFile 继承自Hadoop API 的SequenceFile,不过它的key为空,使用value 存放实际的值, 这样是为了避免MR 在运行map 阶段的排序过程。SequenceFile支持三种压缩选择:NONE, RECORD, BLOCK。 Record压缩率低,一般建议使用BLOCK压缩。 SequenceFile最重要的优点就是Hadoop原生支持较好,有API,但除此之外平平无奇,实际生产中不会使用。
- AVRO:
- Avro是一种用于支持数据密集型的二进制文件格式。它的文件格式更为紧凑,若要读取大量数据时,Avro能够提供更好的序列化和反序列化性能。并且Avro数据文件天生是带Schema定义的,所以它不需要开发者在API 级别实现自己的Writable对象。Avro提供的机制使动态语言可以方便地处理Avro数据。最近多个Hadoop 子项目都支持Avro 数据格式,如Pig 、Hive、Flume、Sqoop和Hcatalog。
复制代码 Hive的四大常用存储格式存储服从及实行速度对比


结论:ORCFILE存储文件读操纵服从最高
耗时比力:ORC< arquet<RC<Text

结论:ORCFILE存储文件占用空间少,压缩服从高
占用空间:ORC< arquet<RC<Text
4.3.1、创建表
- 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]
- 字段解释说明:
- - CREATE TABLE
- 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。
- - EXTERNAL
- 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION)
- 创建内部表时,会将数据移动到数据仓库指向的路径(默认位置);
- 创建外部表时,仅记录数据所在的路径,不对数据的位置做任何改变。
- 在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据。
- - COMMENT:
- 为表和列添加注释。
- - PARTITIONED BY
- 创建分区表
- - CLUSTERED BY
- 创建分桶表
- - SORTED BY
- 不常用
- - ROW FORMAT
- DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char] [MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char] | SERDE serde_name [WITH SERDEPROPERTIES (property_name=property_value, property_name=property_value, ...)]
- 用户在建表的时候可以自定义SerDe或者使用自带的SerDe。
- 如果没有指定ROW FORMAT 或者ROW FORMAT DELIMITED,将会使用自带的SerDe。
- 在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的SerDe,Hive通过SerDe确定表的具体的列的数据。
- SerDe是Serialize/Deserilize的简称,目的是用于序列化和反序列化。
- - STORED AS指定存储文件类型
- 常用的存储文件类型:SEQUENCEFILE(二进制序列文件)、TEXTFILE(文本)、RCFILE(列式存储格式文件)
- 如果文件数据是纯文本,可以使用STORED AS TEXTFILE。
- 如果数据需要压缩,使用 STORED AS SEQUENCEFILE。
- - LOCATION :
- 指定表在HDFS上的存储位置。
- - LIKE
- 允许用户复制现有的表结构,但是不复制数据。
复制代码 建表1:创建内部表(全部使用默认建表方式)
当创建好表的时间,HDFS会在当前表所属的库中创建一个文件夹
当设置表路径的时间,假如直接指向一个已有的路径,可以直接去使用文件夹中的数据
当load数据的时间,就会将数据文件移动到到表对应的文件夹中
而且数据一旦被load,就不能被修改
我们查询数据也是查询文件中的文件,这些数据最终都会存放到HDFS
当我们删除表的时间,表对应的文件夹会被删除,同时数据也会被删除
默认建表的类型就是内部表
- #默认情况下使用的是default数据库
- #可以在切换到其它数据库:use bigdata30 该数据库在hdfs的具体位置/user/hive/warehouse/bigdata30.db
- #通过下面的语句创建students表后会在hdfs上生成一个students文件夹,文件夹里面是用来存储将来插入该表的students.txt数据(也可以是其他类型的文件)
- create table students
- (
- id bigint,
- name string,
- age int,
- gender string,
- clazz string
- )
- ROW FORMAT DELIMITED FIELDS TERMINATED BY '_'; // 必选,指定列分隔符
- //使用load加载数据:
- load data inpath '/data/students.txt' into table students;
- 加载数据的作用就是将hdfs上的/data/students.txt的数据移动到/user/hive/warehouse/bigdata30.db/students文件夹下
- //使用上传文件的方式加载数据
- hadoop fs -put students.txt /user/hive/warehouse/bigdata30.db/students
- #在Hive中创建表时指定列分隔符是为了解析数据文件中的列。当Hive读取数据文件时,它会使用指定的列分隔符来识别和分隔每一列的数据。
- 表的路径为: /user/hive/warehouse/bigdata30.db/students
- 删除文件后数据和文件夹同时删除
复制代码 建表2:创建外部表
外部表因为是指定其他的hdfs路径的数据加载到表中来,以是hive会认为自己不完全独占这份数据
删除hive表的时间,数据仍然保存在hdfs中,不会删除。
- // 外部表(一般情况下,建一个与表名相同的文件夹,然后再将数据上传到该文件夹下,在创建表的时候指定location的路径为数据的存储路径即可)
- create external table students
- (
- id bigint,
- name string,
- age int,
- gender string,
- clazz string
- )
- ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
- location '/data';
- //当指定的路径下有数据时,直接将数据加载到表中
- 表的存储路径hdfs://master:9000/data
- //当指定的路径下没有数据时,通过hadoop命令将数据上传到location指定的文件夹,数据自动加载到表中
- hadoop fs -put students.txt /data
- //也可以使用hive命令行中通过命令将本地文件导入到hdfs上
- hive> dfs -put /usr/local/soft/data/students.txt /data;
复制代码 建表3:指定存储格式
- create table IF NOT EXISTS students
- (
- id bigint,
- name string,
- age int,
- gender string,
- clazz string
- )
- ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
- STORED AS ORC
- // 指定储存格式为orcfile,inputFormat:RCFileInputFormat,outputFormat:RCFileOutputFormat,如果不指定,默认为textfile,
- 注意:除textfile以外,其他的存储格式的数据都不能直接加载,需要使用从表插入数据的方式。
- load data inpath '/data/students.txt' into table students;(不可用)
- insert into table students_test1 select * from students limit 10;(可用)
复制代码 建表4:使用查询语句建表 (这种方式比力常用)
- create table students1 as select * from students;
复制代码 建表5:只想建表,不需要加载数据
- create table students5 like students;
复制代码 简单用户信息表创建:
- create table students6(
- id int,
- uname string,
- pwd string,
- gender string,
- age int
- )
- row format delimited fields terminated by ','
- lines terminated by '\n';
- 在Hive中,建表语句中的lines terminated by '\n'是可选的,并不是必须的。这个语句用于指定在加载数据时每行数据的结束符号,默认情况下,Hive会将每行数据以换行符 \n 作为结束标志。如果你的数据文件每行以换行符结束,你可以不用显式地指定这个参数,Hive会自动识别。但如果你的数据文件行结尾使用了其他分隔符,你就需要使用这个参数来告诉Hive如何正确地解析每行数据。
复制代码- 1,admin,123456,nan,18
- 2,zhangsan,abc123,nan,23
- 3,lisi,654321,nv,16
复制代码 复杂人员信息表创建:
- create table IF NOT EXISTS t_person(
- name string,
- friends array<string>,
- children map<string,int>,
- address struct<street:string ,city:string>
- )
- row format delimited fields terminated by ',' -- 列与列之间的分隔符
- collection items terminated by '_' -- 集合数据类型元素与元素之间分隔符
- map keys terminated by ':' -- Map数据类型键与值之间的分隔符
- lines terminated by '\n'; -- 行与行之间的换行符
复制代码- songsong,bingbing_lili,xiao song:18_xiaoxiao song:19,beng bu_anhui
- yangyang,caicai_susu,xiao yang:18_xiaoxiao yang:19,he fei_anhui
复制代码 4.3.2、加载数据
1、使用hdfs dfs -put '本地数据' 'hive表对应的HDFS目录下'
- hadoop fs -put /uer/local/soft/bigdata30/students.txt /data/students
复制代码 2、使用 load data
注意:默认环境下加载的新数据会被追加到已有表的末尾,而不会覆盖或者清空已存在的数据
- load data inpath '/data/students.txt' into table students;
- // 清空表
- truncate table students;
- // 加上 local 关键字 可以将Linux本地目录下的文件 上传到 hive表对应HDFS 目录下 原文件不会被删除
- load data local inpath '/usr/local/soft/data/students.txt' into table students;
- // overwrite 覆盖加载
- load data local inpath '/usr/local/soft/data/students.txt' overwrite into table students;
复制代码 3、create table xxx as SQL语句
4、insert into table xxxx SQL语句 (没有as)
- // 将 students表的数据插入到students2 这是复制 不是移动 students表中的表中的数据不会丢失
- insert into table students1 select * from students;
- // 覆盖插入 把into 换成 overwrite
- insert overwrite table students1 select * from students;
复制代码 4.3.3、对表进行修改
表现表
- //显示当前数据库下的所有表
- show tables;
- //显示当前数据库下以u开头的所有表
- show tables like 'u*';
- //查看表的结构(表的字段和字段类型)
- desc t_person;
- //查看表的详细结构,包括表的存储位置,表的存储类型,和表的一些其他的属性
- desc formatted students;
复制代码 添加列
- alter table students2 add columns (education string);
复制代码 更新列
- alter table stduents2 change education educationnew string;
- 这条语句将会更改 students2 表中名为 education 的列的数据类型为 STRING,同时将其列名更改为 educationnew。
复制代码 4.3.4、工作案例
一样平常在公司中,使用外部表多一点,因为数据可以需要被多个步伐使用,避免误删,通常外部表会联合location一起使用
外部表还可以将其他数据源中的数据 映射到 hive中,比如说:hbase,ElasticSearch…
计划外部表的初志就是 让 表的元数据 与 数据 解耦
第一步:在hdfs上创建表数据存储的文件夹
- hdfs dfs -mkdir -p /bigdata30/dept
- hdfs dfs -mkdir -p /bigdata30/emp
- hdfs dfs -mkdir -p /bigdata30/salgrade
复制代码 第二步:将数据上传到hdfs上
- hadoop fs -put /uer/local/soft/bigdata30/dept.txt /bigadta30/dept
- hadoop fs -put /uer/local/soft/bigdata30/dept.txt /bigadta30/emp
- hadoop fs -put /uer/local/soft/bigdata30/dept.txt /bigadta30/salgrade
复制代码 第三步:创建表
创建dept表
- CREATE EXTERNAL TABLE IF NOT EXISTS dept (
- DEPTNO int,
- DNAME varchar(255),
- LOC varchar(255)
- ) row format delimited fields terminated by ','
- location '/bigdata30/dept';
- 10,ACCOUNTING,NEW YORK
- 20,RESEARCH,DALLAS
- 30,SALES,CHICAGO
- 40,OPERATIONS,BOSTON
复制代码 创建emp表
- CREATE EXTERNAL TABLE IF NOT EXISTS emp (
- EMPNO int,
- ENAME varchar(255),
- JOB varchar(255),
- MGR int,
- HIREDATE date,
- SAL decimal(10,0),
- COMM decimal(10,0),
- DEPTNO int
- ) row format delimited fields terminated by ','
- location '/bigdata30/emp';
-
- 7369,SMITH,CLERK,7902,1980-12-17,800,null,20
- 7499,ALLEN,SALESMAN,7698,1981-02-20,1600,300,30
- 7521,WARD,SALESMAN,7698,1981-02-22,1250,500,30
- 7566,JONES,MANAGER,7839,1981-04-02,2975,null,20
- 7654,MARTIN,SALESMAN,7698,1981-09-28,1250,1400,30
- 7698,BLAKE,MANAGER,7839,1981-05-01,2850,null,30
- 7782,CLARK,MANAGER,7839,1981-06-09,2450,null,10
- 7788,SCOTT,ANALYST,7566,1987-07-13,3000,null,20
- 7839,KING,PRESIDENT,null,1981-11-17,5000,null,10
- 7844,TURNER,SALESMAN,7698,1981-09-08,1500,0,30
- 7876,ADAMS,CLERK,7788,1987-07-13,1100,null,20
- 7900,JAMES,CLERK,7698,1981-12-03,950,null,30
- 7902,FORD,ANALYST,7566,1981-12-03,3000,null,20
- 7934,MILLER,CLERK,7782,1982-01-23,1300,null,10
复制代码 创建salgrade表
- CREATE EXTERNAL TABLE IF NOT EXISTS salgrade (
- GRADE int,
- LOSAL int,
- HISAL int
- ) row format delimited fields terminated by ','
- location '/bigdata30/salgrade';
- 1,700,1200
- 2,1201,1400
- 3,1401,2000
- 4,2001,3000
- 5,3001,9999
复制代码 4.3.5、Hive导出数据
将表中的数据备份
- //创建存放数据的目录
- mkdir -p /usr/local/soft/shujia
- //导出查询结果的数据(导出到Node01上)
- insert overwrite local directory '/usr/local/soft/shujia' select * from t_person;
复制代码
- -- 创建存放数据的目录
- mkdir -p /usr/local/soft/shujia
- -- 导出查询结果的数据
- insert overwrite local directory '/usr/local/soft/shujia'
- ROW FORMAT DELIMITED fields terminated by ','
- collection items terminated by '-'
- map keys terminated by ':'
- lines terminated by '\n'
- select * from t_person;
复制代码
- -- 导出查询结果的数据
- insert overwrite local directory '/usr/local/soft/shujia'
- ROW FORMAT DELIMITED fields terminated by ','
- collection items terminated by '-'
- map keys terminated by ':'
- lines terminated by '\n'
- select * from t_person;-- 创建存放数据的目录
- hdfs dfs -mkdir -p /shujia/bigdata30/copy
- -- 导出查询结果的数据
- insert overwrite directory '/data/' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' select clazz,count(1) from students group by clazz
复制代码
- // 创建存放数据的目录
- hdfs dfs -mkdir -p /bigdata30/data
- // 使用HDFS命令拷贝文件到其他目录
- hdfs dfs -cp /hive/warehouse/t_person/* /bigdata30/data
复制代码
- 将表布局和数据同时备份
将数据导出到HDFS
- //创建存放数据的目录
- hdfs dfs -mkdir -p /bigdata30/copy
- //导出查询结果的数据
- export table t_person to '/bigdata30/copy';
复制代码 删除表布局
恢复表布局和数据
- // 加上 local 关键字 可以将Linux本地目录下的文件 上传到 hive表对应HDFS 目录下 原文件不会被删除
- load data local inpath '/usr/local/soft/data/students.txt' into table students;
- // overwrite 覆盖加载
- load data local inpath '/usr/local/soft/data/students.txt' overwrite into table students;
复制代码 注意:时间不同步,会导致导入导出失败
Hive分区与排序(内置函数)
1、Hive分区(十分重要!!)
分区的目标:避免全表扫描,加快查询速度!
在大数据中,最常见的一种思想就是分治,我们可以把大的文件切割分别成一个个的小的文件,如许每次操纵一个个小的文件就会很容易了,同样的原理,在hive当中也是支持这种思想的,就是我们可以把大的数据,按照天天或者每小时切分成一个个小的文件,如许去操纵小的文件就会容易很多了。
假如现在我们公司一天产生3亿的数据量,那么为了方便管理和查询,就做以下的事变。
1)建立分区(可按照日期,部门等等具体业务分区)
2)分门别类的管理
1.1 静态分区(SP)
静态分区(SP)static partition–partition by (字段 类型)
借助于物理的文件夹分区,实现快速检索的目标。
一样平常对于查询比力频繁的列设置为分区列。
加载数据的时间直接把对应分区中所有数据放到对应的文件夹中。
创建单分区表语法:
- CREATE TABLE IF NOT EXISTS t_student (
- sno int,
- sname string
- ) partitioned by(grade int)
- row format delimited fields terminated by ',';
- -- 分区的字段不要和表的字段相同。相同会报错error10035
- 1,xiaohu01,1
- 2,xiaohu02,1
- 3,xiaohu03,1
- 4,xiaohu04,1
- 5,xiaohu05,1
- 6,xiaohu06,2
- 7,xiaohu07,2
- 8,xiaohu08,2
- 9,xiaohu09,3
- 10,xiaohu10,3
- 11,xiaohu11,3
- 12,xiaohu12,3
- 13,xiaohu13,3
- 14,xiaohu14,3
- 15,xiaohu15,3
- 16,xiaohu16,4
- 17,xiaohu17,4
- 18,xiaohu18,4
- 19,xiaohu19,4
- 20,xiaohu20,4
- 21,xiaohu21,4
- 22,xiaohu16,5
- 23,xiaohu17,4
- 24,xiaohu18,5
- 25,xiaohu19,5
- 26,xiaohu20,5
- 27,xiaohu21,5
- -- 载入数据
- -- 将相应年级的数据导入对应分区中(对应的是分区文件夹)
- --导入一年级的数据
- load data local inpath '/usr/local/soft/bigdata30/grade1.txt' into table t_student partition(grade=1);
- --导入二年级的数据
- load data local inpath '/usr/local/soft/bigdata30/grade2.txt' into table t_student partition(grade=2);
- -- 演示多拷贝一行上传,分区的列的值是分区的值,不是原来的值
复制代码 静态多分区表语法:
- CREATE TABLE IF NOT EXISTS t_teacher (
- tno int,
- tname string
- ) partitioned by(grade int,clazz int)
- row format delimited fields terminated by ',';
- --注意:前后两个分区的关系为父子关系,也就是grade文件夹下面有多个clazz子文件夹。
- 1,xiaoge01,1,1
- 2,xiaoge02,1,1
- 3,xiaoge03,1,2
- 4,xiaoge04,1,2
- 5,xiaoge05,1,3
- 6,xiaoge06,1,3
- 7,xiaoge07,2,1
- 8,xiaoge08,2,1
- 9,xiaoge09,2,2
- --载入数据
- load data local inpath '/usr/local/soft/bigdata30/teacher_1.txt' into table t_teacher partition(grade=1,clazz=1);
- load data local inpath '/usr/local/soft/bigdata30/teacher_2.txt' into table t_teacher partition(grade=1,clazz=2);
复制代码 分区表查询
- // 全表扫描,不推荐,效率低
- select count(*) from students_pt1;
- //查询分区表的数据
- select * from t_student where grade = 1;
- // 使用where条件进行分区裁剪,避免了全表扫描,效率高
- select count(*) from students_pt1 where grade = 1;
- // 也可以在where条件中使用非等值判断
- select count(*) from students_pt1 where grade<3 and grade>=1;
复制代码 检察分区
- show partitions t_teacher;
复制代码 添加分区
- alter table t_student add partition (grade=6);
- alter table t_teacher add partition (grade=3,clazz=1) location '/user/hive/warehouse/bigdata29.db/t_teacher/grade=3/clazz=1';
- location:表示hdfs上的分区路径(新添加在该表下的分区路径grade=3/clazz=1必须提前创建好)
复制代码 删除分区
- alter table t_student drop partition (grade=5);
复制代码 1.3 动态分区(DP)
- 动态分区(DP)dynamic partition
- 静态分区与动态分区的主要区别在于静态分区是手动指定,而动态分区是通过数据来进行判断。
- 详细来说,静态分区的列是在编译时期通过用户传递来决定的;动态分区只有在SQL实行时才华决定。
开启动态分区首先要在hive会话中设置如下的参数
- # 表示开启动态分区
- hive> set hive.exec.dynamic.partition=true;
- # 表示动态分区模式:strict(需要配合静态分区一起使用)、nostrict
- # strict: insert into table students_pt partition(dt='anhui',pt) select ......,pt from students;
- hive> set hive.exec.dynamic.partition.mode=nonstrict;
- ===================以下是可选参数======================
- # 表示支持的最大的分区数量为1000,可以根据业务自己调整
- hive> set hive.exec.max.dynamic.partitions.pernode=1000;
复制代码 其余的参数详细配置如下
- 设置为true表示开启动态分区的功能(默认为false)
- --hive.exec.dynamic.partition=true;
- 设置为nonstrict,表示允许所有分区都是动态的(默认为strict)
- -- hive.exec.dynamic.partition.mode=nonstrict;
- -- hive.exec.dynamic.partition.mode=strict;
- 每个mapper或reducer可以创建的最大动态分区个数(默认为100)
- 比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错
- --hive.exec.max.dynamic.partition.pernode=100;
- 一个动态分区创建可以创建的最大动态分区个数(默认值1000)
- --hive.exec.max.dynamic.partitions=1000;
- 全局可以创建的最大文件个数(默认值100000)
- --hive.exec.max.created.files=100000;
- 当有空分区产生时,是否抛出异常(默认false)
- -- hive.error.on.empty.partition=false;
复制代码
- --创建外部表
- CREATE EXTERNAL TABLE IF NOT EXISTS t_student_e (
- sno int,
- sname string,
- grade int,
- clazz int
- )
- row format delimited fields terminated by ','
- location "/bigdata30/teachers";
- --创建分区表
- CREATE TABLE IF NOT EXISTS t_student_d (
- sno int,
- sname string
- ) partitioned by (grade int,clazz int)
- row format delimited fields terminated by ',';
复制代码- 数据:
- 1,xiaohu01,1,1
- 2,xiaohu02,1,1
- 3,xiaohu03,1,1
- 4,xiaohu04,1,2
- 5,xiaohu05,1,2
- 6,xiaohu06,2,3
- 7,xiaohu07,2,3
- 8,xiaohu08,2,3
- 9,xiaohu09,3,3
- 10,xiaohu10,3,3
- 11,xiaohu11,3,3
- 12,xiaohu12,3,4
- 13,xiaohu13,3,4
- 14,xiaohu14,3,4
- 15,xiaohu15,3,4
- 16,xiaohu16,4,4
- 17,xiaohu17,4,4
- 18,xiaohu18,4,5
- 19,xiaohu19,4,5
- 20,xiaohu20,4,5
- 21,xiaohu21,4,5
复制代码 假如静态分区的话,我们插入数据必须指定分区的值。
假如想要插入多个班级的数据,我要写很多SQL而且实行24次很麻烦。
而且静态分区有可能会产生数据错误问题
- -- 会报错
- insert overwrite table t_student_d partition (grade=1,clazz=1) select * from t_student_e;
复制代码 假如使用动态分区,动态分区会根据select的结果自动判断数据应该load到哪儿分区去。
- insert overwrite table t_student_d partition (grade,clazz) select * from t_student_e;
复制代码 长处:不用手动指定了,自动会对数据进行分区
缺点:可能会出现数据倾斜
2、Hive分桶
2.1 业务场景
数据分桶的实用场景:
分区提供了一个隔离数据和优化查询的便利方式,不过并非所有的数据都可形成合理的分区,尤其是需要确定符合巨细的分区分别方式
不合理的数据分区分别方式可能导致有的分区数据过多,而某些分区没有什么数据的尴尬环境
分桶是将数据集分解为更容易管理的多少部门的另一种技术。
分桶就是将数据按照字段进行分别,可以将数据按照字段分别到多个文件当中去。(都各不相同)
2.2 数据分桶原理
- Hive接纳对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。
- bucket num = hash_function(bucketing_column) mod num_buckets ( hash(name)%n == x )
- 列的值做哈希取余 决定命据应该存储到哪个桶
2.3 数据分桶优势
方便抽样
使取样(sampling)更高效。在处置惩罚大规模数据集时,在开发和修改查询的阶段,假如能在数据集的一小部门数据上试运行查询,会带来很多方便
进步join查询服从
得到更高的查询处置惩罚服从。桶为表加上了额外的布局,Hive 在处置惩罚有些查询时能利用这个布局。具体而言,连接两个在(包罗连接列的)相同列上分别了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操纵。对于JOIN操纵两个表有一个相同的列,假如对这两个表都进行了桶操纵。那么将保存相同列值的桶进行JOIN操纵就可以,可以大大较少JOIN的数据量。
2.4 分桶实战
首先,分区和分桶是两个不同的概念,很多资料上说需要先分区在分桶,实在不然,分区是对数据进行分别,而分桶是对文件进行分别。
当我们的分区之后,末了的文件还是很大怎么办,就引入了分桶的概念。
将这个比力大的文件再分成多少个小文件进行存储,我们再去查询的时间,在这个小范围的文件中查询就会快很多。
对于hive中的每一张表、分区都可以进一步的进行分桶。
当然,分桶不是说将文件随机进行切分存储,而是有规律的进行存储。在看完下面的例子后进行表明,现在干巴巴的表明也不太好理解。它是由列的哈希值除以桶的个数来决定每条数据分别在哪个桶中。
创建顺序和分区一样,创建的方式不一样。
首先我们需要开启分桶的支持
- (依然十分重要,不然无法进行分桶操作!!!!)
- set hive.enforce.bucketing=true;
复制代码 数据预备(id,name,age)
- 1,tom,11
- 2,cat,22
- 3,dog,33
- 4,hive,44
- 5,hbase,55
- 6,mr,66
- 7,alice,77
- 8,scala,88
复制代码 创建一个普通的表
- create table person
- (
- id int,
- name string,
- age int
- )
- row format delimited
- fields terminated by ',';
复制代码 将数据load到这张表中
- load data local inpath '文件在Linux上的绝对路径' into table person ;
复制代码 创建分桶表
- create table psn_bucket
- (
- id int,
- name string,
- age int
- )
- clustered by(age) into 4 buckets
- row format delimited fields terminated by ',';
复制代码 将数据insert到表psn_bucket中
(注意:这里和分区表插入数据有所区别,分区表需要select 和指定分区,而分桶则不需要)
- insert into psn_bucket select * from person;
复制代码 在HDFS上检察数据
查询数据
我们在linux中使用Hadoop的命令检察一下(与我们料想的顺序一致)
- hadoop fs -cat /user/hive/warehouse/bigdata30.db/psn_bucket/*
复制代码 这里设置的桶的个数是4 数据按照 年龄%4 进行放桶(文件)
11%4 == 3 -----> 000003_0
22%4 == 2 -----> 000002_0
33%4 == 1 -----> 000001_0
44%4 == 0 -----> 000000_0
…以此类推
3、Hive JDBC
启动hiveserver2
- nohup hiveserver2 &
- 或者
- hiveserver2 &
复制代码 新建maven项目并添加两个依赖
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-common</artifactId>
- <version>2.7.6</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/org.apache.hive/hive-jdbc -->
- <dependency>
- <groupId>org.apache.hive</groupId>
- <artifactId>hive-jdbc</artifactId>
- <version>1.2.1</version>
- </dependency>
复制代码 编写JDBC代码
- import java.sql.*;
- public class HiveJDBC {
- public static void main(String[] args) throws ClassNotFoundException, SQLException {
- Class.forName("org.apache.hive.jdbc.HiveDriver");
- Connection conn = DriverManager.getConnection("jdbc:hive2://master:10000/bigdata29");
- Statement stat = conn.createStatement();
- ResultSet rs = stat.executeQuery("select * from students limit 10");
- while (rs.next()) {
- int id = rs.getInt(1);
- String name = rs.getString(2);
- int age = rs.getInt(3);
- String gender = rs.getString(4);
- String clazz = rs.getString(5);
- System.out.println(id + "," + name + "," + age + "," + gender + "," + clazz);
- }
- rs.close();
- stat.close();
- conn.close();
- }
- }
复制代码 4、Hive的4种排序
4.1 全局排序
- order by 会对输入做全局排序,因此只有一个reducer,会导致当输入规模较大时,需要较长的计算时间
- 使用 order by子句排序 :ASC(ascend)升序(默认)| DESC(descend)降序
- order by放在select语句的末端
- select * from 表名 order by 字段名1[,别名2...];
复制代码 4.2 局部排序(对reduce内部做排序)
- sort by 不是全局排序,其在数据进入reducer前完成排序。
- 假如用sort by进行排序,而且设置mapred.reduce.tasks>1,则sort by 只保证每个reducer的输出有序,不保证全局有序。asc,desc
- 设置reduce个数
- set mapreduce.job.reduces=3;
复制代码
- set mapreduce.job.reduces;
复制代码
- select * from 表名 sort by 字段名[,字段名...];
复制代码 4.3 分区排序(本身没有排序)
distribute by(字段)根据指定的字段将数据分到不同的reducer,且分发算法是hash散列。
雷同MR中partition,进行分区,联合sort by使用。(注意:distribute by 要在sort by之前)
对于distrbute by 进行测试,一定要多分配reduce进行处置惩罚,否则无法看到distribute by的结果。
设置reduce个数
- set mapreduce.job.reduce=7;
复制代码
- select * from 表名 distribute by 字段名[,字段名...] sort by 字段;
复制代码 4.3 分区并排序
- cluster by(字段)除了具有Distribute by的功能外,还会对该字段进行排序 asc desc
- cluster by = distribute by + sort by 只能默认升序,不能使用倒序
- select * from 表名 cluster by 字段名[,字段名...];
- select * from 表名 distribute by 字段名[,字段名...] sort by 字段名[,字段名...];
复制代码 5、Hive内置函数
- https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
复制代码- -- 1.查看系统自带函数
- show functions;
- -- 2.显示自带的函数的用法
- desc function xxxx;
- -- 3.详细显示自带的函数的用法
- desc function extended upper;
复制代码 5.1 内置函数分类
- 关系操作符:包括 = 、 <> 、 <= 、>=等
- 算数操作符:包括 + 、 - 、 *、/等
- 逻辑操作符:包括AND 、 && 、 OR 、 || 等
- 复杂类型构造函数:包括map、struct、create_union等
- 复杂类型操作符:包括A[n]、Map[key]、S.x
- 数学操作符:包括ln(double a)、sqrt(double a)等
- 集合操作符:包括size(Array)、sort_array(Array)等
- 类型转换函数: binary(string|binary)、cast(expr as )
- 日期函数:包括from_unixtime(bigint unixtime[, string format])、unix_timestamp()等
- 条件函数:包括if(boolean testCondition, T valueTrue, T valueFalseOrNull)等
- 字符串函数:包括acat(string|binary A, string|binary B…)等
- 其他:xpath、get_json_objectscii(string str)、con
复制代码 5.2 UDTF hive中特殊的一个功能(进一出多)
- -- UDF 进一出一
- -- UDAF 进多出一
- -- collect_set()和collect_list()将多行数据转成一行,区别就是list里面可重复而set里面是去重的
- -- concat_ws(':',collect_set(type)) ':' 表示你合并后用什么分隔,collect_set(stage)表示要合并表中的那一列数据
- select 字段名,concat_ws(':',collect_set(列名)) as 别名 from 表名 group by id;
- -- UDTF 进一出多
- -- explode 可以将一行数据变成多行数据
- select explode(split(列名,"数据的分隔符")) from 表名;
- -- lateral view 表生成函数,可以将explode的数据生成一个列表
- select id,name,列名 from 表1,lateral view explode(split(表1.列名,"数据的分隔符"))新列名 as 别列名;
- --注意:collect_set() 和 collect_list() 是 Hive 中用于聚合操作的集合函数,它们分别用于将列值聚合成集合或列表。
复制代码- -- 创建数据库表
- create table t_movie1(
- id int,
- name string,
- types string
- )
- row format delimited fields terminated by ','
- lines terminated by '\n';
- -- 电影数据 movie1.txt
- -- 加载数据到数据库 load data inpath '/shujia/movie1.txt' into table t_movie1;
- 1,这个杀手不太冷,剧情-动作-犯罪
- 2,七武士,动作-冒险-剧情
- 3,勇敢的心,动作-传记-剧情-历史-战争
- 4,东邪西毒,剧情-动作-爱情-武侠-古装
- 5,霍比特人,动作-奇幻-冒险
- -- explode 可以将一组数组的数据变成一列表
- select explode(split(types,"-")) from t_movie1;
- -- lateral view 表生成函数,可以将explode的数据生成一个列表
- select id,name,type from t_movie1 lateral view explode(split(types,"-")) typetable as type;
复制代码- -- 创建数据库表
- create table t_movie2(
- id int,
- name string,
- type string
- )
- row format delimited fields terminated by ','
- lines terminated by '\n';
- -- 电影数据 movie2.txt
- -- 加载数据到数据库 load data inpath '/shujia/movie2.txt' into table t_movie2; 1,这个杀手不太冷,剧情
- 1,这个杀手不太冷,动作
- 1,这个杀手不太冷,犯罪
- 2,七武士,动作
- 2,七武士,冒险
- 2,七武士,剧情
- 3,勇敢的心,动作
- 3,勇敢的心,传记
- 3,勇敢的心,剧情
- 3,勇敢的心,历史
- 3,勇敢的心,战争
- 4,东邪西毒,剧情
- 4,东邪西毒,动作
- 4,东邪西毒,爱情
- 4,东邪西毒,武侠
- 4,东邪西毒,古装
- 5,霍比特人,动作
- 5,霍比特人,奇幻
- 5,霍比特人,冒险
- -- collect_set()和collect_list()都是对列转成行,区别就是list里面可重复而set里面是去重的
- -- concat_ws(':',collect_set(type)) ':' 表示你合并后用什么分隔,collect_set(stage)表示要合并表中的那一列数据
- select id,concat_ws(':',collect_set(type)) as types from t_movie2 group by id;
复制代码 5.3 WordCount案例
数据预备
- hello,world
- hello,bigdata
- like,life
- bigdata,good
复制代码 建表
- create table wc2
- (
- line string
- )
- row format delimited fields terminated by '\n'
复制代码 导入数据
- load data local inpath '/usr/local/soft/data/wc1.txt' into table wc;
复制代码 步骤1:先对一行数据进行切分
- select split(line,',') from wc;
复制代码 步骤2:将行转列
- select explode(split(line,',')) from wc;
复制代码 步骤3:将相同的进行分组统计
- select w.word,count(*) from (select explode(split(line,',')) as word from wc) w group by w.word;
复制代码 Hive函数学习
1、count(*)、count(1) 、count(‘字段名’) 区别
从实行结果来看
- count(*)包括了所有的列,相称于行数,在统计结果的时间,不会忽略列值为NULL 最慢的
- count(1)忽略所有列,只计算行的数量,在统计结果的时间,不会忽略列值为NULL 最快的
- count(列名)只包括列名那一列,在统计结果的时间,会忽略列值为空(这里的空不是只空字符串或者0,而是表现null)的计数,即某个字段值为NULL时,不统计 仅次于count(1)
从实行服从来看
- 假如列为主键,count(列名)服从优于count(1)
- 假如列不为主键,count(1)服从优于count(列名)
- 假如表中存在主键,count(主键列名)服从最优
- 假如表中只有一列,则count(*)服从最优
- 假如表有多列,且不存在主键,则count(1)服从优于count(*)
在工作中假如没有特殊的要求,就使用count(1)来进行计数。
2、hive语句的实行顺序
1.from
2.join on 或 lateral view explode(需炸裂的列) tbl as 炸裂后的列名
3.where
4.group by
5.聚合函数 如Sum() avg() count(1)等
6.having 在此开始可以使用select中的别名
7.select 若包罗over()开窗函数,此时select中的内容作为窗口函数的输入,窗口中所选的数据范围也是在group by,having之后,并不是针对where后的数据进行开窗,这点要注意。需要注意开窗函数的实行顺序及时间点。
8.distinct
9.order by
10.limit(发起:以后在大数据环境中,一张表的数据量肯定十分庞大的,养成加limit的风俗)
where 条件里不支持不等式子查询,实际上是支持 in、not in、exists、not exists( hive3.x版本是支持的 )
- # 查询薪资大于SCOTT的薪资员工信息
- -- 列出与“SCOTT”从事相同工作的所有员工。
- select t1.EMPNO
- ,t1.ENAME
- ,t1.JOB
- from emp t1
- where t1.ENAME != "SCOTT" and t1.job in(
- select job
- from emp
- where ENAME = "SCOTT");
-
- 7900,JAMES,CLERK,7698,1981-12-03,950,null,30
- 7902,FORD,ANALYST,7566,1981-12-03,3000,null,20
- select t1.EMPNO
- ,t1.ENAME
- ,t1.JOB
- from emp t1
- where t1.ENAME != "SCOTT" and exists(
- select job
- from emp t2
- where ENAME = "SCOTT"
- and t1.job = t2.job
- );
复制代码 4、hive中巨细写不敏感(列名无所谓巨细写)
5、在hive中,数据中假如有null字符串,加载到表中的时间会变成 null (不是字符串)
假如需要判断 null,使用 某个字段名 is null 如许的方式来判断
或者使用 nvl() 函数,不能 直接 某个字段名 == null
6、使用explain检察SQL实行计划
口试题:hive中一条sql语句如何剖析成MapReduce作业实行的?(hive的版本)
- explain select t1.EMPNO
- ,t1.ENAME
- ,t1.JOB
- from emp t1
- where t1.ENAME != "SCOTT" and t1.job in(
- select job
- from emp
- where ENAME = "SCOTT");
-
- # 查看更加详细的执行计划,加上extended
- explain extended select t1.EMPNO
- ,t1.ENAME
- ,t1.JOB
- from emp t1
- where t1.ENAME != "SCOTT" and t1.job in(
- select job
- from emp
- where ENAME = "SCOTT");
复制代码 3、Hive 常用函数
3.1、关系运算
- // 等值比较 = == < = >
- // 不等值比较 != <>
- // 区间比较: select * from default.students where id between 1500100001 and 1500100010;
- // 空值/非空值判断:isnull、isnotnull、nvl()、isnull()
- // like、rlike、regexp用法
复制代码 3.2、数值计算
- 取整函数(四舍五入):round
- 向上取整:ceil
- 向下取整:floor
复制代码 3.3、条件函数(主要使用场景是数据洗濯的过程中使用,有些构建表的过程也是需要的)
- if: if(表达式,假如表达式建立的返回值,假如表达式不建立的返回值) (重点)
- 条件表达式?表达式1:表达式2;
- create table sc(
- sno string,
- cno string,
- score bigint
- )row format delimited fields terminated by '\n';
- select sal,if(sal<2000,'低薪',if(sal>=2000 and sal<3000,'中等','高薪')) as level from emp;
- select if(1>0,1,0);
- select if(1>0,if(-1>0,-1,1),0);
- select score,if(score>120,'优秀',if(score>100,'良好',if(score>90,'及格','不及格'))) as pingfen from sc;
复制代码
- select COALESCE(null,'1','2'); // 1 从左往右 依次匹配 直到非空为止
- select COALESCE('1',null,'2'); // 1
复制代码
- select sal,case when sal<2000 then '低薪'
- when sal>=2000 and sal<3000 then '中等薪资'
- else '高薪' end as level
- from emp;
- select score
- ,case when score>90 then '优秀'
- when score>80 then '良好'
- when score>=60 then '及格'
- else '不及格'
- end as pingfen
- from sc;
- select name
- ,case name when "施笑槐" then "槐ge"
- when "吕金鹏" then "鹏ge"
- when "单乐蕊" then "蕊jie"
- else "算了不叫了"
- end as nickname
- from students limit 10;
复制代码 注意条件的顺序
3.4、日期函数重点!!!
- select from_unixtime(1717666208,'YYYY年MM月dd日 hh时mm分ss秒');
- select from_unixtime(unix_timestamp(),'YYYY/MM/dd HH:mm:ss');
- // '2021年01月14日' -> '2021-01-14'
- select from_unixtime(unix_timestamp('2024年06月06日','yyyy年MM月dd日'),'yyyy-MM-dd');
- // "04牛2021数加16强" -> "2021/04/16"
- select from_unixtime(unix_timestamp("04牛2024数加11强","MM牛yyyy数加dd强"),"yyyy年MM月dd日");
复制代码 3.5、字符串函数
- concat('123','456'); // 123456
- concat('123','456',null); // NULL
- select concat_ws('#','a','b','c'); // a#b#c
- select concat_ws('#','a','b','c',NULL); // a#b#c 可以指定分隔符,并且会自动忽略NULL
- select concat_ws("|",cast(id as string),name,cast(age as string),gender,clazz) from students limit 10;
- select substring("abcdefg",1); // abcdefg HQL中涉及到位置的时候 是从1开始计数
- // '2021/01/14' -> '2021-01-14'
- select concat_ws("-",substring('2021/01/14',1,4),substring('2021/01/14',6,2),substring('2021/01/14',9,2));
- // 建议使用日期函数去做日期
- select from_unixtime(unix_timestamp('2021/01/14','yyyy/MM/dd'),'yyyy-MM-dd');
- select split("abcde,fgh",","); // ["abcde","fgh"]
- select split("a,b,c,d,e,f",",")[2]; // c 数组的下标依旧是从0开始
- select explode(split("abcde,fgh",",")); // abcde
- // fgh
- // 解析json格式的数据
- select get_json_object('{"name":"zhangsan","age":18,"score":[{"course_name":"math","score":100},{"course_name":"english","score":60}]}',"$.score[0].score"); // 60
- {
- "name": "zhangsan",
- "age": 18,
- "score": [{
- "course_name": "math",
- "score": 100
- }, {
- "course_name": "english",
- "score": 60
- }]
- }
- $.score[0].score
复制代码 3.6、例题:Hive 中的wordCount
- create table words(
- words string
- )row format delimited fields terminated by '\n';
- // 数据
- hello,java,hello,java,scala,python
- hbase,hadoop,hadoop,hdfs,hive,hive
- hbase,hadoop,hadoop,hdfs,hive,hive
- select word,count(*) from (select explode(split(words,',')) word from words) a group by a.word;
- // 结果
- hadoop 4
- hbase 2
- hdfs 2
- hello 2
- hive 4
- java 2
- python 1
- scala 1
复制代码 3.7、Hive窗口函数
普通的聚合函数每组(Group by)只返回一个值,而开窗函数则可为窗口中的每行都返回一个值。
简单理解,就是对查询的结果多出一列,这一列可以是聚合值,也可以是排序值。
开窗函数一样平常就是说的是over()函数,其窗口是由一个 OVER 子句 定义的多行记录
开窗函数一样平常分为两类,聚合开窗函数和排序开窗函数。
- -- 聚合格式
- select sum(字段名) over([partition by 字段名] [ order by 字段名]) as 别名,
- max(字段名) over() as 别名
- from 表名;
- -- 排序窗口格式
- select rank() over([partition by 字段名] [ order by 字段名]) as 别名 from 表名;
复制代码 注意点:
- over()函数中的分区、排序、指定窗口范围可组合使用也可以不指定,根据不同的业务需求联合使用
- over()函数中假如不指定分区,窗口巨细是针对查询产生的所有数据,假如指定了分区,窗口巨细是针对每个分区的数据
测试数据
- -- 创建表
- create table t_fraction(
- name string,
- subject string,
- score int)
- row format delimited fields terminated by ","
- lines terminated by '\n';
- -- 测试数据 fraction.txt
- 孙悟空,语文,10
- 孙悟空,数学,73
- 孙悟空,英语,15
- 猪八戒,语文,10
- 猪八戒,数学,73
- 猪八戒,英语,11
- 沙悟净,语文,22
- 沙悟净,数学,70
- 沙悟净,英语,31
- 唐玄奘,语文,21
- 唐玄奘,数学,81
- 唐玄奘,英语,23
- -- 上传数据
- load data local inpath '/usr/local/soft/bigdata17/xiaohu/data/fraction.txt' into table t_fraction;
复制代码 3.7.1、 聚合开窗函数
sum(求和)
min(最小)
max(最大)
avg(平均值)
count(计数)
lag(获取当前行上一行的数据)
lead(获取当前行下一行的数据)
- --
- select name,subject,score,sum(score) over() as sumover from t_fraction;
- +-------+----------+--------+----------+
- | name | subject | score | sumover |
- +-------+----------+--------+----------+
- | 唐玄奘 | 英语 | 23 | 321 |
- | 唐玄奘 | 数学 | 81 | 321 |
- | 唐玄奘 | 语文 | 21 | 321 |
- | 沙悟净 | 英语 | 31 | 321 |
- | 沙悟净 | 数学 | 12 | 321 |
- | 沙悟净 | 语文 | 22 | 321 |
- | 猪八戒 | 英语 | 11 | 321 |
- | 猪八戒 | 数学 | 73 | 321 |
- | 猪八戒 | 语文 | 10 | 321 |
- | 孙悟空 | 英语 | 15 | 321 |
- | 孙悟空 | 数学 | 12 | 321 |
- | 孙悟空 | 语文 | 10 | 321 |
- +-------+----------+--------+----------+
- select name,subject,score,
- sum(score) over() as sum1,
- sum(score) over(partition by subject) as sum2,
- sum(score) over(partition by subject order by score) as sum3,
- -- 由起点到当前行的窗口聚合,和sum3一样
- sum(score) over(partition by subject order by score rows between unbounded preceding and current row) as sum4,
- -- 当前行和前面一行的窗口聚合
- sum(score) over(partition by subject order by score rows between 1 preceding and current row) as sum5,
- -- 当前行的前面一行到后面一行的窗口聚合 前一行+当前行+后一行
- sum(score) over(partition by subject order by score rows between 1 preceding and 1 following) as sum6,
- -- 当前行与后一行之和
- sum(score) over(partition by subject order by score rows between current row and 1 following) as sum6,
- -- 当前和后面所有的行
- sum(score) over(partition by subject order by score rows between current row and unbounded following) as sum7
- from t_fraction;
- rows:行
- unbounded preceding:起点
- unbounded following:终点
- n preceding:前 n 行
- n following:后 n 行
- current row:当前行
- +-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
- | name | subject | score | sum1 | sum2 | sum3 | sum4 | sum5 | sum6 | sum7 |
- +-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
- | 孙悟空 | 数学 | 12 | 359 | 185 | 12 | 12 | 12 | 31 | 185 |
- | 沙悟净 | 数学 | 19 | 359 | 185 | 31 | 31 | 31 | 104 | 173 |
- | 猪八戒 | 数学 | 73 | 359 | 185 | 104 | 104 | 92 | 173 | 154 |
- | 唐玄奘 | 数学 | 81 | 359 | 185 | 185 | 185 | 154 | 154 | 81 |
- | 猪八戒 | 英语 | 11 | 359 | 80 | 11 | 11 | 11 | 26 | 80 |
- | 孙悟空 | 英语 | 15 | 359 | 80 | 26 | 26 | 26 | 49 | 69 |
- | 唐玄奘 | 英语 | 23 | 359 | 80 | 49 | 49 | 38 | 69 | 54 |
- | 沙悟净 | 英语 | 31 | 359 | 80 | 80 | 80 | 54 | 54 | 31 |
- | 孙悟空 | 语文 | 10 | 359 | 94 | 10 | 10 | 10 | 31 | 94 |
- | 唐玄奘 | 语文 | 21 | 359 | 94 | 31 | 31 | 31 | 53 | 84 |
- | 沙悟净 | 语文 | 22 | 359 | 94 | 53 | 53 | 43 | 84 | 63 |
- | 猪八戒 | 语文 | 41 | 359 | 94 | 94 | 94 | 63 | 63 | 41 |
- +-------+----------+--------+-------+-------+-------+-------+-------+-------+-------+
复制代码 rows必须跟在Order by 子句之后,对排序的结果进行限定,使用固定的行数来限定分区中的数据行数量。
**OVER():**指定分析函数工作的数据窗口巨细,这个数据窗口巨细可能会随着行的变而变化。
**CURRENT ROW:**当前行
**n PRECEDING:**往前n行数据
**n FOLLOWING:**往后n行数据
**UNBOUNDED:**起点,UNBOUNDED PRECEDING 表现从前面的起点, UNBOUNDED FOLLOWING表现到后面的终点
**LAG(col,n,default_val):**往前第n行数据,col是列名,n是往上的行数,当第n行为null的时间取default_val
**LEAD(col,n, default_val):**往后第n行数据,col是列名,n是往下的行数,当第n行为null的时间取default_val
**NTILE(n):**把有序分区中的行分发到指定命据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。
cume_dist(),计算某个窗口或分区中某个值的累积分布。假定升序排序,则使用以下公式确定累积分布:
小于即是当前值x的行数 / 窗口或partition分区内的总行数。其中,x 即是 order by 子句中指定的列的当前行中的值。
聚合开窗函数实战:
实战1:Hive用户购买明细数据分析
创建表和加载数据
- name,orderdate,cost
- jack,2017-01-01,10
- tony,2017-01-02,15
- jack,2017-02-03,23
- tony,2017-01-04,29
- jack,2017-01-05,46
- jack,2017-04-06,42
- tony,2017-01-07,50
- jack,2017-01-08,55
- mart,2017-04-08,62
- mart,2017-04-09,68
- neil,2017-05-10,12
- mart,2017-04-11,75
- neil,2017-06-12,80
- mart,2017-04-13,94
- 建表加载数据
- vim business.txt
- create table business
- (
- name string,
- orderdate string,
- cost int
- )ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
- load data local inpath "/shujia/bigdata17/xiaohu/data/business.txt" into table business;
复制代码 实战1需求:
需求1:查询在2017年4月份购买过的顾客及总人数
- # 分析:按照日期过滤、分组count求总人数
- select t1.name,t1.orderdate,count(1) over() as counts_04 from (select name,orderdate from business where month(orderdate)='04') t1;
复制代码 需求2:查询顾客的购买明细及月购买总额
- # 分析:按照顾客分组、sum购买金额
- select name,orderdate,cost,sum(cost) over(partition by name,month(orderdate)) from business;
复制代码 需求3:上述的场景,要将cost按照日期进行累加
- # 分析:按照顾客分组、日期升序排序、组内每条数据将之前的金额累加
- select name,orderdate,cost,sum(cost) over(partition by name order by orderdate rows between unbounded preceding and current row) from business;
复制代码 需求4:查询顾客上次的购买时间
- ·# 分析:查询出明细数据同时获取上一条数据的购买时间(肯定需要按照顾客分组、时间升序排序)
- select name,orderdate,cost,lag(orderdate,1) over(partition by name order by orderdate) as last_time from business;
复制代码 需求5:查询前20%时间的订单信息
- 分析:按照日期升序排序、取前20%的数据
- select t1.name,t1.orderdate,t1.cost from (select name,orderdate,cost,ntile(5) over(order by orderdate) as n from business) t1 where t1.n=1;
复制代码 3.7.2、 排序开窗函数(重点)
- RANK() 排序相同时会重复,总数不会变
- DENSE_RANK() 排序相同时会重复,总数会减少
- ROW_NUMBER() 会根据顺序计算
- PERCENT_RANK()计算给定行的百分比排名。可以用来计算超过了百分之多少的人(当前行的rank值-1)/(分组内的总行数-1)
- select name,subject,
- score,
- rank() over(partition by subject order by score desc) rp,
- dense_rank() over(partition by subject order by score desc) drp,
- row_number() over(partition by subject order by score desc) rnp,
- percent_rank() over(partition by subject order by score) as percent_rank
- from t_fraction;
复制代码- select name,subject,score,
- rank() over(order by score) as row_number,
- percent_rank() over(partition by subject order by score) as percent_rank
- from t_fraction;
复制代码 实战2:Hive分析学天生绩信息
创建表语加载数据
- name subject score
- 李毅 语文 87
- 李毅 数学 95
- 李毅 英语 68
- 黄仙 语文 94
- 黄仙 数学 56
- 黄仙 英语 84
- 小虎 语文 64
- 小虎 数学 86
- 小虎 英语 84
- 许文客 语文 65
- 许文客 数学 85
- 许文客 英语 78
- 建表加载数据
- vim score.txt
- create table score2
- (
- name string,
- subject string,
- score int
- ) row format delimited fields terminated by "\t";
- load data local inpath '/shujia/bigdata17/xiaohu/data/score.txt' into table score;
复制代码 需求1:每门学科学天生绩排名(是否并列排名、空位排名三种实现)
- 分析:学科分组、成绩降序排序、按照成绩排名
- select name,subject,score,
- rank() over(partition by subject order by score desc) rp,
- dense_rank() over(partition by subject order by score desc) drp,
- row_number() over(partition by subject order by score desc) rmp
- from
- score;
复制代码 需求2:每门学科成绩排名top 2的学生
- select t1.name,t1.subject,t1.score from (select name,subject,score,row_number() over(partition by subject order by score desc) as rn from score2) t1 where t1.rn<3;
复制代码 4、Hive 行转列
lateral view explode
- create table testArray2(
- name string,
- weight array<string>
- )row format delimited
- fields terminated by '\t'
- COLLECTION ITEMS terminated by ',';
- 小虎 "150","170","180"
- 火火 "150","180","190"
- select name,col1 from testarray2 lateral view explode(weight) t1 as col1;
- 小虎 150
- 小虎 170
- 小虎 180
- 火火 150
- 火火 180
- 火火 190
- select key from (select explode(map('key1',1,'key2',2,'key3',3)) as (key,value)) t;
- key1
- key2
- key3
- select name,col1,col2 from testarray2 lateral view explode(map('key1',1,'key2',2,'key3',3)) t1 as col1,col2;
- 小虎 key1 1
- 小虎 key2 2
- 小虎 key3 3
- 火火 key1 1
- 火火 key2 2
- 火火 key3 3
- select name,pos,col1 from testarray2 lateral view posexplode(weight) t1 as pos,col1;
- 小虎 0 150
- 小虎 1 170
- 小虎 2 180
- 火火 0 150
- 火火 1 180
- 火火 2 190
复制代码 5、Hive 列转行
- // testLieToLine
- name col1
- 小虎 150
- 小虎 170
- 小虎 180
- 火火 150
- 火火 180
- 火火 190
- create table testLieToLine(
- name string,
- col1 int
- )row format delimited
- fields terminated by '\t';
- select name,collect_list(col1) from testLieToLine group by name;
- // 结果
- 小虎 ["150","180","190"]
- 火火 ["150","170","180"]
- select t1.name
- ,collect_list(t1.col1)
- from (
- select name
- ,col1
- from testarray2
- lateral view explode(weight) t1 as col1
- ) t1 group by t1.name;
复制代码 6、Hive自定义函数UserDefineFunction
6.1、UDF:一进一出
定义UDF函数要注意下面几点:
- 继承org.apache.hadoop.hive.ql.exec.UDF
- 重写evaluate(),这个方法不是由接口定义的,因为它可继承的参数的个数,数据类型都是不确定的。Hive会检查UDF,看可否找到和函数调用相匹配的evaluate()方法
- <dependency>
- <groupId>org.apache.hive</groupId>
- <artifactId>hive-exec</artifactId>
- <version>1.2.1</version>
- </dependency>
复制代码 打包的时间可能会出现错误
Could not transfer artifact org.pentaho:pentaho-aggdesigner-algorithm:pom:5.1.5-jhyde
办理方案:
在pom文件中修改hive-exec的配置
- <dependency>
- <groupId>org.apache.hive</groupId>
- <artifactId>hive-exec</artifactId>
- <exclusions>
- <!--排除pentaho-aggdesigner-algorithm依赖,不将它引入-->
- <exclusion>
- <groupId>org.pentaho</groupId>
- <artifactId>pentaho-aggdesigner-algorithm</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
复制代码
- 编写代码,继承org.apache.hadoop.hive.ql.exec.UDF,实现evaluate方法,在evaluate方法中实现自己的逻辑
- [/code]
- [list]
- [*]打成jar包并上传至Linux虚拟机
- [*]在hive shell中,使用 add jar 路径将jar包作为资源添加到hive环境中
- [/list] [code]add jar /usr/local/soft/bigdata19/hive-bigdata19-1.0-SNAPSHOT.jar;
复制代码
- 使用jar包资源注册一个临时函数,fxxx1是你的函数名,'MyUDF’是主类名
- create temporary function fxxx1 as 'MyUDF';
复制代码
- select fxx1(name) as fxx_name from students limit 10;
- #施笑槐$
- #吕金鹏$
- #单乐蕊$
- #葛德曜$
- #宣谷芹$
- #边昂雄$
- #尚孤风$
- #符半双$
- #沈德昌$
- #羿彦昌$
复制代码 案例2:转大写
- [/code] [size=1]函数加载方式[/size]
- 命令加载
- 这种加载只对本session有效
- [code]# 1、将项目打包上传服务器:将打好的jar包传到linux系统中。(不要打依赖)
- # 进入到hive客户端,执行下面命令
- hive> add jar /usr/local/soft/bigdata17/data/xiaohu/hadoop-mapreduce-1.0-SNAPSHOT.jar
- # 2、创建一个临时函数名,要跟上面hive在同一个session里面:
- hive> create temporary function toUP as 'com.shujia.testHiveFun.udf.FirstUDF';
- 3、检查函数是否创建成功
- show functions;
- 4. 测试功能
- select toUp('abcdef');
- 5. 删除函数
- drop temporary function if exists toUp;
复制代码 创建永久函数
将jar上传HDFS:
- hadoop fs -put hadoop-mapreduce-1.0-SNAPSHOT.jar /jar/
复制代码 在hive命令行中创建永久函数:
- create function myUp as 'com.shujia.testHiveFun.udf.FirstUDF' using jar 'hdfs:/jar/hadoop-mapreduce-1.0-SNAPSHOT.jar';
- create function bfy_fun as 'com.shujia.udfdemo.HiveTest' using jar 'hdfs:/shujia/bigdata19/jar/hive-udf.jar';
复制代码 退出hive,再进入,实行测试:
删除永久函数,并检查:
6.2、UDTF:一进多出
UDTF是一对多的输入输出,实现UDTF需要完成下面步骤
M1001#xiaohu#S324231212,lkd#M1002#S2543412432,S21312312412#M1003#bfy
1001 xiaohu 324231212
1002 lkd 2543412432
1003 bfy 21312312412
继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF,
重写initlizer()、process()、close()。
实行流程如下:
UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)。
初始化完成后,会调用process方法,真正的处置惩罚过程在process函数中,在process中,每一次forward()调用产生一行;假如产生多列可以将多个列的值放在一个数组中,然后将该数组传入到forward()函数。
末了close()方法调用,对需要清理的方法进行清理。
“key1:value1,key2:value2,key3:value3”
key1 value1
key2 value2
key3 value3
方法一:使用 explode+split
- [/code] [size=1]方法二:自定UDTF[/size]
-
- [list]
- [*]代码
- [/list] [code]
复制代码
- create temporary function my_udtf as 'com.shujia.testHiveFun.udtf.HiveUDTF';
- select my_udtf("key1:value1,key2:value2,key3:value3");
复制代码 字段:id,col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12 共13列
数据:
a,1,2,3,4,5,6,7,8,9,10,11,12
b,11,12,13,14,15,16,17,18,19,20,21,22
c,21,22,23,24,25,26,27,28,29,30,31,32
转成3列:id,hours,value
例如:
a,1,2,3,4,5,6,7,8,9,10,11,12
a,0时,1
a,2时,2
a,4时,3
a,6时,4
…
- create table udtfData(
- id string
- ,col1 string
- ,col2 string
- ,col3 string
- ,col4 string
- ,col5 string
- ,col6 string
- ,col7 string
- ,col8 string
- ,col9 string
- ,col10 string
- ,col11 string
- ,col12 string
- )row format delimited fields terminated by ',';
复制代码 代码:
- [/code] 添加jar资源:
- [code]add jar /usr/local/soft/HiveUDF2-1.0.jar;
复制代码 注册udtf函数:
- create temporary function my_udtf as 'MyUDTF';
复制代码 SQL:
- select id,hours,value from udtfData lateral view my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) t as hours,value ;
复制代码 6.3、UDAF:多进一出
Hive Shell
第一种:
- hive -e "select * from test1.students limit 10"
复制代码 第二种:
将HQL写在一个文件里,再使用 -f 参数指定该文件
连续登岸问题
在电商、物流和银行可能常常会遇到如许的需求:统计用户连续交易的总额、连续登岸天数、连续登岸开始和竣事时间、间隔天数等
数据:
注意:每个用户天天可能会有多条记录
- id datestr amount
- 1,2019-02-08,6214.23
- 1,2019-02-08,6247.32
- 1,2019-02-09,85.63
- 1,2019-02-09,967.36
- 1,2019-02-10,85.69
- 1,2019-02-12,769.85
- 1,2019-02-13,943.86
- 1,2019-02-14,538.42
- 1,2019-02-15,369.76
- 1,2019-02-16,369.76
- 1,2019-02-18,795.15
- 1,2019-02-19,715.65
- 1,2019-02-21,537.71
- 2,2019-02-08,6214.23
- 2,2019-02-08,6247.32
- 2,2019-02-09,85.63
- 2,2019-02-09,967.36
- 2,2019-02-10,85.69
- 2,2019-02-12,769.85
- 2,2019-02-13,943.86
- 2,2019-02-14,943.18
- 2,2019-02-15,369.76
- 2,2019-02-18,795.15
- 2,2019-02-19,715.65
- 2,2019-02-21,537.71
- 3,2019-02-08,6214.23
- 3,2019-02-08,6247.32
- 3,2019-02-09,85.63
- 3,2019-02-09,967.36
- 3,2019-02-10,85.69
- 3,2019-02-12,769.85
- 3,2019-02-13,943.86
- 3,2019-02-14,276.81
- 3,2019-02-15,369.76
- 3,2019-02-16,369.76
- 3,2019-02-18,795.15
- 3,2019-02-19,715.65
- 3,2019-02-21,537.71
复制代码 建表语句
- create table deal_tb(
- id string
- ,datestr string
- ,amount string
- )row format delimited fields terminated by ',';
复制代码 计算逻辑
- 先按用户和日期分组求和,使每个用户天天只有一条数据
- [/code]
- [list]
- [*] 根据用户ID分组按日期排序,将日期和分组序号相减得到连续登岸的开始日期,假如开始日期相同说明连续登岸
- [*] [i]datediff(string end_date,string start_date);[/i] 即是0说明连续登录
- [*] 统计用户连续交易的总额、连续登岸天数、连续登岸开始和竣事时间、间隔天数
- [/list] [code]
复制代码
- 1 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
- 1 2019-02-08 2991.650 5 2019-02-12 2019-02-16 1
- 1 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1
- 1 2019-02-10 537.71 1 2019-02-21 2019-02-21 1
- 2 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
- 2 2019-02-08 3026.649 4 2019-02-12 2019-02-15 1
- 2 2019-02-10 1510.8 2 2019-02-18 2019-02-19 2
- 2 2019-02-11 537.71 1 2019-02-21 2019-02-21 1
- 3 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
- 3 2019-02-08 2730.04 5 2019-02-12 2019-02-16 1
- 3 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1
- 3 2019-02-10 537.71 1 2019-02-21 2019-02-21 1
复制代码 inated by ‘,’;
- 代码:```java```添加jar资源:```add jar /usr/local/soft/HiveUDF2-1.0.jar;
- ```注册udtf函数:```create temporary function my_udtf as 'MyUDTF';
- ```SQL:```select id,hours,value from udtfData lateral view my_udtf(col1,col2,col3,col4,col5,col6,col7,col8,col9,col10,col11,col12) t as hours,value ;
- ```## 6.3、UDAF:多进一出#### Hive Shell##### 第一种:```hive -e "select * from test1.students limit 10"
- ```##### 第二种:```hive -f hql文件路径
- ```> 将HQL写在一个文件里,再使用 -f 参数指定该文件#### 连续登岸问题> 在电商、物流和银行可能常常会遇到如许的需求:统计用户连续交易的总额、连续登岸天数、连续登岸开始和竣事时间、间隔天数等##### 数据:> 注意:每个用户天天可能会有多条记录```id datestr amount
- 1,2019-02-08,6214.23
- 1,2019-02-08,6247.32
- 1,2019-02-09,85.63
- 1,2019-02-09,967.36
- 1,2019-02-10,85.69
- 1,2019-02-12,769.85
- 1,2019-02-13,943.86
- 1,2019-02-14,538.42
- 1,2019-02-15,369.76
- 1,2019-02-16,369.76
- 1,2019-02-18,795.15
- 1,2019-02-19,715.65
- 1,2019-02-21,537.71
- 2,2019-02-08,6214.23
- 2,2019-02-08,6247.32
- 2,2019-02-09,85.63
- 2,2019-02-09,967.36
- 2,2019-02-10,85.69
- 2,2019-02-12,769.85
- 2,2019-02-13,943.86
- 2,2019-02-14,943.18
- 2,2019-02-15,369.76
- 2,2019-02-18,795.15
- 2,2019-02-19,715.65
- 2,2019-02-21,537.71
- 3,2019-02-08,6214.23
- 3,2019-02-08,6247.32
- 3,2019-02-09,85.63
- 3,2019-02-09,967.36
- 3,2019-02-10,85.69
- 3,2019-02-12,769.85
- 3,2019-02-13,943.86
- 3,2019-02-14,276.81
- 3,2019-02-15,369.76
- 3,2019-02-16,369.76
- 3,2019-02-18,795.15
- 3,2019-02-19,715.65
- 3,2019-02-21,537.71
- ```##### 建表语句```sqlcreate table deal_tb(
- id string
- ,datestr string
- ,amount string
- )row format delimited fields terminated by ',';
- ```##### 计算逻辑* 先按用户和日期分组求和,使每个用户天天只有一条数据```sql```* 根据用户ID分组按日期排序,将日期和分组序号相减得到连续登岸的开始日期,假如开始日期相同说明连续登岸* *datediff(string end_date,string start_date);* 即是0说明连续登录* 统计用户连续交易的总额、连续登岸天数、连续登岸开始和竣事时间、间隔天数``````* 结果```1 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
- 1 2019-02-08 2991.650 5 2019-02-12 2019-02-16 1
- 1 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1
- 1 2019-02-10 537.71 1 2019-02-21 2019-02-21 1
- 2 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
- 2 2019-02-08 3026.649 4 2019-02-12 2019-02-15 1
- 2 2019-02-10 1510.8 2 2019-02-18 2019-02-19 2
- 2 2019-02-11 537.71 1 2019-02-21 2019-02-21 1
- 3 2019-02-07 13600.23 3 2019-02-08 2019-02-10 NULL
- 3 2019-02-08 2730.04 5 2019-02-12 2019-02-16 1
- 3 2019-02-09 1510.8 2 2019-02-18 2019-02-19 1
- 3 2019-02-10 537.71 1 2019-02-21 2019-02-21 1
- ```
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |