一、hive入门手册
1.1数据仓库概念
对历史数据变化的统计,从而支撑企业的决策。比如:某个商品最近一个月的销量,预判下个月应该销售多少,从而补充多少货源。 1.2传统数据仓库面临的挑战 (1)无法满足快速增长的海量数据存储需求 (2)无法有效处理不同类型的数据 (3)计算和处理能力不足 1.3 Hive介绍 Hbase支持快速的交互式的大数据应用 pig,Hive支持批量式的数据分析业务 1.4 Hive与传统数据库的对比 1.5 Hive在企业中的部署与应用
2.Hive系统架构
Microsoft推出的ODBC(Open Database Connectivity)技术 [1] 为异质数据库的访问提供了统一的接口 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。 CIL (Common Intermediate Language) 公共中间语言
3.Hive工作原理
3.1 SQL转换为MapReduce作业的基本原理
3.2 Hive中SQL查询转换MapReduce作业的过程
4.Hive HA基本原理
5.Impala
5.1 Impala介绍 5.2 Impala系统架构 5.3 Impala查询执行过程 5.4 Impala和Hive的区别
6.Hive编程实践
6.1 Hive的安装和配置
6.2 Hive的基本数据类型
6.3 Hive的基本操作
1.create:创建数据库、表、视图
创建数据库 (1)创建数据库hive hive>create database hive; (2)创建数据库hive,因为hive已经存在,所以会抛出异常,加上if not exits 关键字,则不会抛出异常 hive>create database if not exits hive;
创建表 (1)在hive数据库中创建表usr,含三个属性id,name,age hive>use hive; hive>create table if not exists usr(id bigint,name string,age int); (2)在hive数据库中创建表usr,含三个属性id,name,age,存储路径为“/usr/local/hive/warehouse/hive/usr” hive>create table if not exits hive.usr(id bigint,name string,age int) >location '/usr/local/hive/warehouse/hive/usr';
创建视图 (1)创建视图little_usr,只包含usr表中id,age属性 hive>create view little_usr as select id,age from usr;
2.show:查看数据库、表、视图 查看数据库 (1)查看hive中包含的所有数据库
hive>show databases;
(2)查看hive中以h开头的所有数据库
hive>show databases like 'h.*';
查看表和视图 (1)查看数据库hive中所有的表和视图
hive>use hive;
hive>show tables;
(2)查看数据库hive中以u开头的所有表和视图
hive>show tables in hive like 'u.*';
3.load:向表中装在数据 (1)把目录‘/usr/local/data’下的数据文件中的数据装载进usr表并覆盖原有数据
hive>load data local inpath '/usr/local/data' overwrite into table usr;
(2)把目录‘/usr/local/data’下的数据文件中的数据装载进usr表不覆盖原有数据
hive>load data local inpath '/usr/local/data' into table usr;
(3)把分布式系统文件目录‘hdfs://master_server/usr/local/data’下的数据文件数据装载进usr表并覆盖原有数据
hive>load data local inpath ‘hdfs://master_server/usr/local/data’
>overwrite into table usr;
4.insert:向表中插入数据或从表中导出数据 (1)向表中usr1中插入来自usr表中的数据并覆盖原有数据
hive>insert overwrite table usr1
>select * from usr where age=10;
(2)向表中usr1中插入来自usr表中的数据并追加在原有数据后
hive>insert into table usr1 >select*from usr >where age=10;
6.4 Hive的应用实例(wordCount)
6.5 Hive的优势
WordCount算法在MapReduce中的编程实现和Hive中编程实现的主要不同点:
1.采用hive实现WordCount算法需要编写较少的代码量 在MapReduce中,WordCount类由63行Java代码编写而成 在hive中只需要编写7行代码
2.在MapReduce的实现中,需要进行编译生成jar文件来执行算法,而在hive中不需要 hiveQL语句的最终实现需要转换为MapReduce任务来执行,这都是由hive框架自动完成的,用户不需要了解具体实现细节。
7.Hive的几种数据模型
内部表 (Table 将数据保存到Hive 自己的数据仓库目录中:/usr/hive/warehouse) 外部表 (External Table 相对于内部表,数据不在自己的数据仓库中,只保存数据的元信息) 分区表 (Partition Table将数据按照设定的条件分开存储,提高查询效率,分区-----> 目录) 桶表 (Bucket Table本质上也是一种分区表,类似 hash 分区 桶 ----> 文件) 视图表 (视图表是一个虚表,不存储数据,用来简化复杂的查询) 注意:内部表删除表后数据也会删除,外部表数据删除后不会从hdfs中删除
1. 内部表/管理表
每一个Table在Hive中都有一个相应的目录存储数据 所有的Table数据都存储在该目录
create table if not exists aiops.appinfo ( appname string, level string, leader string, appline string, dep string, ips array<string>) ROW FORMAT DELIMITED FIELDS TERMINATED BY ' ' COLLECTION ITEMS TERMINATED BY ','; # 自定义文件和记录格式 ## 使用create table创建表,最后使用stored as sequencefile保存成sequence格式[默认是text格式] # 数据库授权 hive> grant create on database dbname to user hadoop; # 导入数据(本地导入和hdfs导入) hive> load data inpath 'hdfs://hdfs-name/sure.csv' overwrite into table aiops.appinfo; load data local inpath '/home/hdfs/online_state1' overwrite into table online_state PARTITION (end_dt='99991231'); # 查看表结构 hive> describe extended bgops; hive> describe bgops; # 修改列名 ## 这个命令可以修改表的列名,数据类型,列注释和列所在的位置顺序,FIRST将列放在第一列,AFTER col_name将列放在col_name后面一列 hive> ALTER TABLE aiops.appinfo CHANGE hostnum ipnum int comment 'some 注释' AFTER col3; # 修改表结构 ALTER TABLE aiops.appinfo replace columns (appname string,level string,leader string,appline string,dep string,ips array<string>); ALTER TABLE appinfo replace columns (appname string,appline string,level string,leader string,dep string,idcnum int,idcs array<string>,hostnum int,ips array<string>); ## 增加表的列字段(默认增加到最后一列,可以使用change column 来调整位置) hive> alter table appinfo add columns (appclass string comment 'app_perf_class'); # 导出表查询结果(会将结果导出到testoutput目录下) hive> insert overwrite local directory './testoutput' > row format delimited fields terminated by " " > select ip,appname,leader from appinfo LATERAL VIEW explode(ips) tmpappinfo AS ip;
2.外部表的使用场景
原始日志文件或同时被多个部门同时操作的数据集,需要使用外部表 如果不小心将meta data删除了,HDFS上的数据还在,可以恢复,增加了数据的安全性 注意:使用insert插入数据时会产生临时表,重新连接后会表会小时,因此大批量插入数据时不建议用insert tips1:在hdfs的hive路径下以.db结尾的其实都是实际的数据库 tips2:默认的default数据库就在hive的家目录
3. 分区表
注意:分区表通常分为静态分区表和动态分区表,前者需要导入数据时静态指定分区,后者可以直接根据导入数据进行分区。分区的好处是可以让数据按照区域进行分类,避免了查询时的全表扫描。
CREATE EXTERNAL TABLE if not exists aiops.tmpOnline(ip string, status string, .... ) PARTITIONED BY ( dt string); # 导入数据到静态分区表中(需要注意的是数据中没有dt字段) load data local inpath '/home/hdfs/tmpOnline' overwrite into table aiops.tmpOnline PARTITION (dt='99991231'); # 动态分区表的使用(动态分区和静态分区表的创建时没有区别的) # 注意:hive默认没有开启动态分区,需要进行参数修改 # 使用动态分区的记录中,必须在指定位置包含动态分区的字段才能被动态分区表识别 hive>set hive.exec.dynamic.partition.mode=nonstrict; hive> insert overwrite table aiops.tmpOnline partition(dt) select ip,appname,....,from_unixtime(unix_timestamp(),'yyyyMMdd') as dt from table; # 手动添加分区 alter table tablename add partition (dt='20181009'); # 删除分区,数据也会删除(所以一般会使用外部分区表?) ## 注意:如果数据有变动,是无法将数据load到同一个时间分区的记录的 alter table tablename drop partition (dt='20181009'); # 查询分区表没有加分区过滤,会禁止提交这个任务(strict方式每次查询必须制定分区) set hive.mapred.mode = strict|nostrict;
注意:在外部分区表中,如果将表删除了,重建表后只需要将分区加载进来即可恢复历史相关分区的数据。 多重分区的使用
# 创建多重分区表 create table log_m ( id int, name string, age int ) partitioned by (year string,month string,day string) row format delimited fields terminated by '|' collection items terminated by ',' map keys terminated by ':' lines terminated by ' '; # 插入数据 insert into table log_m partition (year='2018',month='10',day='10') values(1,'biaoge',24); insert into table log_m partition (year='2018',month='10',day='09') values(2,'bgbiao',25); hive> show partitions log_m; OK year=2018/month=10/day=09 year=2018/month=10/day=10 Time taken: 0.055 seconds, Fetched: 2 row(s) hive> # 多重动态分区 # 好像动态分区表不能直接load data hive> insert into table log_m partition(year,month,day) values(3,'xuxuebiao',28,'2016','09','10'); hive> show partitions log_m; OK year=2016/month=09/day=10 year=2018/month=10/day=09 year=2018/month=10/day=10 # 查询分区数据 hive> select * from log_m where year = '2018'; OK 2 bgbiao 25 2018 10 09 1 biaoge 24 2018 10 10 2 bgbiao 25 2018 10 10
4、Hive的复杂数据类型的使用
注意:Hive之所以能在大数据领域比较受欢迎,很大一部分原因在于相比其他SQL类存储系统支持更加复杂的数据类型
map: (key1, value1, key2, value2, ...) 一些列的k/v对 map<int,string...> struct: (var1,var2,var3...) 不同类型的值的组合 structabc:string,def:int... array: (var1,var2,var3...) 一种类型的值的组合 array<string...> uniontype: (string,map<>,struct<>,array<>)
注意:在创建hive表时可根据需要导入的数据进行类型识别并创建适合的数据类型 hive数据类型数据识别标识:
字段分割标识含义FIELDS TERMINATED BY表示字段与字段之间的分隔符COLLECTION ITEMS TERMINATED BY表示一个字段中各个item之间的分隔符[可用于array和struct类型]MAP KEYS TERMINATED BY表示map类型中的key/value的分隔符[可用于map类型]
# 创建表 create table union_testnew( foo uniontype<int, double, string, array<string>, map<string, string>> ) row format delimited collection items terminated by ',' map keys terminated by ':' lines terminated by ' ' stored as textfile; # 数据准备 [root@master wadeyu]# vim union_test.log 1 0,1 2 1,3.0 3 2,world 4 3,wade:tom:polly 5 4,k1^Dv1:k2^Dv2 # 导入数据 hive (badou)> load data local inpath './union_test.log' overwrite into table union_testnew; # 查询数据 hive (badou)> select * from union_testnew; OK union_testnew.foo {0:1} {1:3.0} {2:"world"} {3:["wade","tom","polly"]} {4:{"k1":"v1","k2":"v2"}} Time taken: 0.225 seconds, Fetched: 5 row(s)
(1)array类型的使用 1.1 array类型的基本使用 类型结构: array<struct> 例如:array<string>,array<int> 数据表示: 例如:[string1,string2],[int1,int2]
# 原始文件 bmpjob P2 bgops 服务研发组 10.0.0.212,10.0.0.225,10.0.0.243,10.0.55.31 # 创建数据库 hive> create table appinfo > ( > appname string, > level string, > leader string, > dep string, > ips array<string>) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY ' ' > COLLECTION ITEMS TERMINATED BY ','; # 加载数据到hive hive> load data inpath 'hdfs://hdfs-name/aiops/wander/appinfo.txt' overwrite into table appinfo; Loading data to table test.appinfo Table test.appinfo stats: [numFiles=1, numRows=0, totalSize=32568, rawDataSize=0] OK # 查询相关数据 hive> select * from appinfo limit 1; OK bmpjob P2 bgops 服务研发组 ["10.0.0.212","10.0.0.225","10.0.0.243","10.0.55.31"] hive> select appname,leader,ips[0] from appinfo limit 1; OK bmpjob bgops 10.0.0.212
1.2array与struct类型数据转换处理 背景
使用array结构时,一个字段中通常会有多个值,这个时候通常情况下是需要对某个值进行过滤的,一般情况下会使用lateral view结合UDTF(User-Defined Table-Generating Functions)进行过滤。而UDTF为了解决一行输出多行的需求,典型的就是explode()函数。 lateral view语法结构
lateralView: LATERAL VIEW udtf(expression) tableAlias AS columnAlias (',' columnAlias)
array和struct转字符串
# 借用split函数将array<string>结构内容转换为以","分割的字符串 select split(array<string>,',') from tablename
hive使用explode()函数进行行转列 语法:lateral view explode(col3) col3 as name explode(ARRAY): 列表中的每个元素生成一行 explode(MAP): map中每个key-value对,生成一行,key为一列,value为一列
hive> select ip,appname from appinfo LATERAL VIEW explode(ips) tmpappinfo AS ip limit 2; 10.0.0.212 bmpjob 10.0.0.225 bmpjob
hive使用concat_ws()函数进行列转行
# 借用concat_ws()和collect_set()函数进行相同列的重复数据转换 # collect_set()函数可以将相关列合并成array<>类型;concat_ws()函数会将array<>类型根据指定的分隔符进行合并 ## 示例数据 hive> select * from tmp_jiangzl_test; tmp_jiangzl_test.col1 tmp_jiangzl_test.col2 tmp_jiangzl_test.col3 a b 1 a b 2 a b 3 c d 4 c d 5 c d 6 ## 对于以上数据,我们可以将col3列根据列col1和col2进行合并 hive> select col1,col2,concat_ws(',',collect_set(col3)) from tmp_jiangzl_test group by col1,col2; col1 col2 _c2 a b 1,2,3 c d 4,5,6
(2)struct<>类型的使用 数据定义: struct<name:STRING, age:INT> 数据表示: biaoge:18
# 元数据格式 1,zhou:30 2,yan:30 3,chen:20 # 相关数据库结构 hive> create table test-struct(id INT, info struct<name:STRING, age:INT>) > ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' > COLLECTION ITEMS TERMINATED BY ':'; # 加载数据 hive> LOAD DATA LOCAL INPATH '/home/work/data/test5.txt' INTO TABLE test-struct; # 查询相关数据 hive> select info.age from test-struct; Total MapReduce jobs = 1 ...... Total MapReduce CPU Time Spent: 490 msec OK 30 30
map<>类型的使用 数据定义: map<string,int> 数据表示: key:value,key:value...
# 原始数据格式 1 job:80,team:60,person:70 2 job:60,team:80 3 job:90,team:70,person:100 # map结构的表结构创建 hive> create table employee(id string, perf map<string, int>) > ROW FORMAT DELIMITED > FIELDS TERMINATED BY ' ' > COLLECTION ITEMS TERMINATED BY ',' > MAP KEYS TERMINATED BY ':'; # 数据导入 hive> LOAD DATA LOCAL INPATH '/home/work/data/test7.txt' INTO TABLE employee; # 数据查询 hive> select perf['person'] from employee; Total MapReduce jobs = 1 ...... Total MapReduce CPU Time Spent: 460 msec OK 70 NULL # 使用explode()函数查询 hive> select explode(perf) as (p_name,p_score) from employee limit 4; OK job 80 team 60 person 70 # 使用explode()和lateral view结合查询 hive> select id,p_name,p_score from employee lateral view explode(perf) perf as p_name,p_score limit 3; OK 1 job 80 1 team 60 1 person 70 # 使用size()函数查看map结构中的键值对个数[也可查看array中的元素个数] hive> select size(perf) from employee 3 2 3
8.总结
本章详细介绍了hive的基本知识。hive是一个构建与Hadoop顶层的数据仓库工具,主要用于对存储在Hadoop文件中的数据集进行数据整理、特殊查询和分析处理。hive在某种程度上可以看做是用户编程接口,本身不存储和处理数据,依赖HDFS存储数据,依赖MapReduce处理数据。 hive支持使用自身提供的命令行CLI、简单网页HWI访问方式,及通过Karmasphere、Hue、Qubole等工具的外部访问 hive在数据仓库中的具体应用中,主要用于报表中心的报表分析统计上。在Hadoop集群上构建的数据仓库由多个hive进行管理,具体实现采用hive HA原理的方式,实现一台超强“hive”。 Impala作为新一代开源大数据分析引擎,支持实时计算,并在性能上比hive高出3~30倍,甚至在将来的某一天可能会超过hive的使用率而成为Hadoop上最流行的实时计算平台。
本章最后以单词统计为例,详细介绍了如何使用hive进行简单编程。
二、hive高级手册
1、Hive的常用函数
注意:使用show functions可以查看hive支持的相关函数
(1). hive常用函数列表
注意:聚合方法通常需要和group by语句组合使用
(2)、表生成函数:
表生成函数接收零个或者多个输入,然后产生多列或多行输出. 注意:当split被包含在""之中的时候需要使用四个进行转义[比如在hive -e ""中执行split函数]
## array()函数可以将一列输入转换成一个数组输出 hive> select array(1,2,3) from xuxuebiao; OK [1,2,3] [1,2,3] ## explode()函数以array数据类型作为输入,对数组中数据进行迭代,返回多行结果 hive> select explode(array(1,2,3)) from xuxuebiao; OK 1 2 3 ## 使用explode()函数查看array中的某个元素 hive> select * from appinfo LATERAL VIEW explode(ips) tmpappinfo AS realid where realid ='10.0.0.125' ; ## collect_set函数 ### 该函数的作用是将某字段的值进行去重汇总,产生Array类型字段 hive> select * from test; OK 1 A 1 C 1 B hive> select id,collect_set(name) from test group by id; OK 1 ["A","C","B"]
(3)、常用的条件判断以及数据清洗函数
在使用hive处理数据过程中,通常我们需要对相关数据进行清洗转换,此时我们可能会使用一些条件判断以及默认值处理函数。
# if条件判断常用于不同规格数据的清洗操作 hive> select ip,if(assign != '分配状态未知',0,assign) as fenpei from asset ; OK 10.0.0.1 分配状态未知 # case多条件判断 hive> select ip, case when assign = '已分配' then 1 when assign = '未分配' then 2 else 0 end as fenpei from asset hive (ods)> select name,salary, > case when salary < 800 then 'low' > when salary >= 800 and salary <=5000 then 'middle' > when salary >5000 and salary <10000 then 'high' > else 'very high' > end as bracket > from emp1; # parser_url()函数 hive> select parse_url('https://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%E8%BF%AA%E5%A3%AB%E5%B0%BC%E6%94%B6%E8%B4%AD%E7%A6%8F%E5%85%8B%E6%96%AF&rsv_idx=2','HOST') ; [url=http://www.baidu.com]www.baidu.com[/url] # 正则表达式 hive> select regexp_replace('foobar', 'oo|ar', ''); select regexp_replace('foobar', 'oo|ar', '-'); ## 输出第一个回溯引用(.*?)匹配到的内容即the select regexp_extract('foothebar', 'foo(.*?)(bar)', 1); ## 输出第而个回溯引用(bar)匹配到的内容即bar select regexp_extract('foothebar', 'foo(.*?)(bar)', 2); ## 输出全部内容 select regexp_extract('foothebar', 'foo(.*?)(bar)', 0); # 清洗组合 select if(4>5,5000,1000),coalesce(null,1,3,5),coalesce(null,null,null,null), case 3 when 1 then 'lala' when 2 then 'chye' else 'abc' end;
(4)hive高级函数
row_number() over()
(5)、hive常用的环境变量
2、hive优化
2、1性能优化
在工作中使用hive比较多,也写了很多HiveQL。这里从三个方面对 Hive 常用的一些性能优化进行了总结。
(1)表设计层面优化 利用分区表优化 分区表 是在某一个或者几个维度上对数据进行分类存储,一个分区对应一个目录。如果筛选条件里有分区字段,那么 Hive 只需要遍历对应分区目录下的文件即可,不需要遍历全局数据,使得处理的数据量大大减少,从而提高查询效率。 当一个 Hive 表的查询大多数情况下,会根据某一个字段进行筛选时,那么非常适合创建为分区表。 利用桶表优化 指定桶的个数后,存储数据时,根据某一个字段进行哈希后,确定存储在哪个桶里,这样做的目的和分区表类似,也是使得筛选时不用全局遍历所有的数据,只需要遍历所在桶就可以了。 选择合适的文件存储格式 Apache Hive 支持 Apache Hadoop 中使用的几种熟悉的文件格式。 TextFile 默认格式,如果建表时不指定默认为此格式。 存储方式:行存储。 每一行都是一条记录,每行都以换行符 结尾。数据不做压缩时,磁盘会开销比较大,数据解析开销也比较大。 可结合 Gzip、Bzip2 等压缩方式一起使用(系统会自动检查,查询时会自动解压),但对于某些压缩算法 hive 不会对数据进行切分,从而无法对数据进行并行操作。 SequenceFile 一种Hadoop API 提供的二进制文件,使用方便、可分割、个压缩的特点。 支持三种压缩选择:NONE、RECORD、BLOCK。RECORD压缩率低,一般建议使用BLOCK压缩。 RCFile 存储方式:数据按行分块,每块按照列存储 。 首先,将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。 其次,块数据列式存储,有利于数据压缩和快速的列存取。 ORC 存储方式:数据按行分块,每块按照列存储 Hive 提供的新格式,属于 RCFile 的升级版,性能有大幅度提升,而且数据可以压缩存储,压缩快,快速列存取。 Parquet 存储方式:列式存储 Parquet 对于大型查询的类型是高效的。对于扫描特定表格中的特定列查询,Parquet特别有用。Parquet一般使用 Snappy、Gzip 压缩。默认 Snappy。 Parquet 支持 Impala 查询引擎。 表的文件存储格式尽量采用 Parquet 或 ORC,不仅降低存储量,还优化了查询,压缩,表关联等性能; 选择合适的压缩方式 Hive 语句最终是转化为 MapReduce 程序来执行的,而 MapReduce 的性能瓶颈在与 网络IO 和 磁盘IO,要解决性能瓶颈,最主要的是 减少数据量,对数据进行压缩是个好方式。压缩虽然是减少了数据量,但是压缩过程要消耗CPU,但是在Hadoop中,往往性能瓶颈不在于CPU,CPU压力并不大,所以压缩充分利用了比较空闲的CPU。 如何选择压缩方式 压缩比率 压缩解压速度 是否支持split 支持分割的文件可以并行的有多个 mapper 程序处理大数据文件,大多数文件不支持可分割是因为这些文件只能从头开始读。
2.2 语法和参数层面优化
列裁剪 Hive 在读数据的时候,可以只读取查询中所需要用到的列,而忽略其他的列。这样做可以节省读取开销,中间表存储开销和数据整合开销。
set hive.optimize.cp = true; -- 列裁剪,取数只取查询中需要用到的列,默认为真
分区裁剪 在查询的过程中只选择需要的分区,可以减少读入的分区数目,减少读入的数据量。
set hive.optimize.pruner=true; // 默认为true
合并小文件 Map 输入合并 在执行 MapReduce 程序的时候,一般情况是一个文件需要一个 mapper 来处理。但是如果数据源是大量的小文件,这样岂不是会启动大量的 mapper 任务,这样会浪费大量资源。可以将输入的小文件进行合并,从而减少mapper任务数量。详细分析
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- Map端输入、合并文件之后按照block的大小分割(默认) set hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat; -- Map端输入,不合并
Map/Reduce输出合并 大量的小文件会给 HDFS 带来压力,影响处理效率。可以通过合并 Map 和 Reduce 的结果文件来消除影响。
set hive.merge.mapfiles=true; -- 是否合并Map输出文件, 默认值为真 set hive.merge.mapredfiles=true; -- 是否合并Reduce 端输出文件,默认值为假 set hive.merge.size.per.task=25610001000; -- 合并文件的大小,默认值为 256000000
合理控制 map/reduce 任务数量 合理控制 mapper 数量 减少 mapper 数可以通过合并小文件来实现,增加 mapper 数可以通过控制上一个 reduce 默认的 mapper 个数计算方式
输入文件总大小:total_size hdfs 设置的数据块大小:dfs_block_size default_mapper_num = total_size/dfs_block_size
MapReduce 中提供了如下参数来控制 map 任务个数:
set mapred.map.tasks=10;
从字面上看,貌似是可以直接设置 mapper 个数的样子,但是很遗憾不行,这个参数设置只有在大于default_mapper_num的时候,才会生效。
那如果我们需要减少 mapper 数量,但是文件大小是固定的,那该怎么办呢? 可以通过mapred.min.split.size设置每个任务处理的文件的大小,这个大小只有在大于dfs_block_size的时候才会生效
split_size=max(mapred.min.split.size, dfs_block_size) split_num=total_size/split_size compute_map_num = min(split_num, max(default_mapper_num, mapred.map.tasks))
这样就可以减少mapper数量了。
总结一下控制 mapper 个数的方法: 如果想增加 mapper 个数,可以设置mapred.map.tasks为一个较大的值 如果想减少 mapper 个数,可以设置maperd.min.split.size为一个较大的值 如果输入是大量小文件,想减少 mapper 个数,可以通过设置hive.input.format合并小文件
如果想要调整 mapper 个数,在调整之前,需要确定处理的文件大概大小以及文件的存在形式(是大量小文件,还是单个大文件),然后再设置合适的参数。 合理控制reducer数量 如果 reducer 数量过多,一个 reducer 会产生一个结数量果文件,这样就会生成很多小文件,那么如果这些结果文件会作为下一个 job 的输入,则会出现小文件需要进行合并的问题,而且启动和初始化 reducer 需要耗费和资源。 如果 reducer 数量过少,这样一个 reducer 就需要处理大量的数据,并且还有可能会出现数据倾斜的问题,使得整个查询耗时长。 默认情况下,hive 分配的 reducer 个数由下列参数决定:
参数1:hive.exec.reducers.bytes.per.reducer(默认1G) 参数2:hive.exec.reducers.max(默认为999)
reducer的计算公式为:N = min(参数2, 总输入数据量/参数1) 可以通过改变上述两个参数的值来控制reducer的数量。 也可以通过set mapred.map.tasks=10;直接控制reducer个数,如果设置了该参数,上面两个参数就会忽略。
2、3 join优化
优先过滤数据 尽量减少每个阶段的数据量,对于分区表能用上分区字段的尽量使用,同时只选择后面需要使用到的列,最大限度的减少参与 join 的数据量。
小表 join 大表原则 小表 join 大表的时应遵守小表 join 大表原则,原因是 join 操作的 reduce 阶段,位于 join 左边的表内容会被加载进内存,将条目少的表放在左边,可以有效减少发生内存溢出的几率。join 中执行顺序是从左到右生成 Job,应该保证连续查询中的表的大小从左到右是依次增加的。
使用相同的连接键 在 hive 中,当对 3 个或更多张表进行 join 时,如果 on 条件使用相同字段,那么它们会合并为一个 MapReduce Job,利用这种特性,可以将相同的 join on 的放入一个 job 来节省执行时间。 启用 mapjoin mapjoin 是将 join 双方比较小的表直接分发到各个 map 进程的内存中,在 map 进程中进行 join 操作,这样就不用进行 reduce 步骤,从而提高了速度。只有 join 操作才能启用 mapjoin。
set hive.auto.convert.join = true; -- 是否根据输入小表的大小,自动将reduce端的common join 转化为map join,将小表刷入内存中。 set hive.mapjoin.smalltable.filesize = 2500000; -- 刷入内存表的大小(字节) set hive.mapjoin.maxsize=1000000; -- Map Join所处理的最大的行数。超过此行数,Map Join进程会异常退出
尽量原子操作 尽量避免一个SQL包含复杂的逻辑,可以使用中间表来完成复杂的逻辑。 桶表 mapjoin 当两个分桶表 join 时,如果 join on的是分桶字段,小表的分桶数是大表的倍数时,可以启用 mapjoin 来提高效率。
set hive.optimize.bucketmapjoin = true; -- 启用桶表 map join
2.4、Group By 优化
默认情况下,Map阶段同一个Key的数据会分发到一个Reduce上,当一个Key的数据过大时会产生 数据倾斜。进行group by操作时可以从以下两个方面进行优化:
-
Map端部分聚合 事实上并不是所有的聚合操作都需要在 Reduce 部分进行,很多聚合操作都可以先在 Map 端进行部分聚合,然后在 Reduce 端的得出最终结果。
set hive.map.aggr=true; -- 开启Map端聚合参数设置 set hive.grouby.mapaggr.checkinterval=100000; -- 在Map端进行聚合操作的条目数目
-
有数据倾斜时进行负载均衡
set hive.groupby.skewindata = true; -- 有数据倾斜的时候进行负载均衡(默认是false)
当选项设定为 true 时,生成的查询计划有两个 MapReduce 任务。在第一个 MapReduce 任务中,map 的输出结果会随机分布到 reduce 中,每个 reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的group by key有可能分发到不同的 reduce 中,从而达到负载均衡的目的;第二个 MapReduce 任务再根据预处理的数据结果按照group by key分布到各个 reduce 中,最后完成最终的聚合操作。
2.5 Order By 优化
order by只能是在一个reduce进程中进行,所以如果对一个大数据集进行order by,会导致一个reduce进程中处理的数据相当大,造成查询执行缓慢。 在最终结果上进行order by,不要在中间的大数据集上进行排序。如果最终结果较少,可以在一个reduce上进行排序时,那么就在最后的结果集上进行order by。 如果是去排序后的前N条数据,可以使用distribute by和sort by在各个reduce上进行排序后前N条,然后再对各个reduce的结果集合合并后在一个reduce中全局排序,再取前N条,因为参与全局排序的order by的数据量最多是reduce个数 * N,所以执行效率很高。
2.6 COUNT DISTINCT优化
-- 优化前(只有一个reduce,先去重再count负担比较大):
select count(distinct id) from tablename;
-- 优化后(启动两个job,一个job负责子查询(可以有多个reduce),另一个job负责count(1)):
select count(1) from (select distinct id from tablename) tmp;
一次读取多次插入 有些场景是从一张表读取数据后,要多次利用,这时可以使用multi insert语法:
from sale_detail insert overwrite table sale_detail_multi partition (sale_date='2010', region='china' ) select shop_name, customer_id, total_price where ..... insert overwrite table sale_detail_multi partition (sale_date='2011', region='china' ) select shop_name, customer_id, total_price where .....;
说明: 一般情况下,单个SQL中最多可以写128路输出,超过128路,则报语法错误。 在一个multi insert中: 对于分区表,同一个目标分区不允许出现多次。 对于未分区表,该表不能出现多次。 对于同一张分区表的不同分区,不能同时有insert overwrite和insert into操作,否则报错返回。
2.7、启用压缩
map 输出压缩
set mapreduce.map.output.compress=true; set mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
中间数据压缩 中间数据压缩就是对 hive 查询的多个 job 之间的数据进行压缩。最好是选择一个节省CPU耗时的压缩方式。可以采用snappy压缩算法,该算法的压缩和解压效率都非常高。
set hive.exec.compress.intermediate=true; set hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec; set hive.intermediate.compression.type=BLOCK;
结果数据压缩 最终的结果数据(Reducer输出数据)也是可以进行压缩的,可以选择一个压缩效果比较好的,可以减少数据的大小和数据的磁盘读写时间; 注:常用的gzip,snappy压缩算法是不支持并行处理的,如果数据源是gzip/snappy压缩文件大文件,这样只会有有个mapper来处理这个文件,会严重影响查询效率。 所以如果结果数据需要作为其他查询任务的数据源,可以选择支持splitable的LZO算法,这样既能对结果文件进行压缩,还可以并行的处理,这样就可以大大的提高job执行的速度了。关于如何给Hadoop集群安装LZO压缩库可以查看这篇文章。
set hive.exec.compress.output=true; set mapreduce.output.fileoutputformat.compress=true; set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec; set mapreduce.output.fileoutputformat.compress.type=BLOCK;
Hadoop集群支持一下算法: org.apache.hadoop.io.compress.DefaultCodec org.apache.hadoop.io.compress.GzipCodec org.apache.hadoop.io.compress.BZip2Codec org.apache.hadoop.io.compress.DeflateCodec org.apache.hadoop.io.compress.SnappyCodec org.apache.hadoop.io.compress.Lz4Codec com.hadoop.compression.lzo.LzoCodec com.hadoop.compression.lzo.LzopCodec (3)、Hive架构层面优化 启用直接抓取 Hive 从 HDFS 中读取数据,有两种方式:启用 MapReduce 读取、直接抓取。 直接抓取数据比 MapReduce 方式读取数据要快的多,但是只有少数操作可以使用直接抓取方式。 可以通过hive.fetch.task.conversion参数来配置在什么情况下采用直接抓取方式: minimal:只有 select * 、在分区字段上 where 过滤、有 limit 这三种场景下才启用直接抓取方式。 more:在 select、where 筛选、limit 时,都启用直接抓取方式。
set hive.fetch.task.conversion=more; -- 启用fetch more模式
本地化执行 Hive 在集群上查询时,默认是在集群上多台机器上运行,需要多个机器进行协调运行,这种方式很好的解决了大数据量的查询问题。但是在Hive查询处理的数据量比较小的时候,其实没有必要启动分布式模式去执行,因为以分布式方式执行设计到跨网络传输、多节点协调等,并且消耗资源。对于小数据集,可以通过本地模式,在单台机器上处理所有任务,执行时间明显被缩短。
set hive.exec.mode.local.auto=true; -- 打开hive自动判断是否启动本地模式的开关 set hive.exec.mode.local.auto.input.files.max=4; -- map任务数最大值 set hive.exec.mode.local.auto.inputbytes.max=134217728; -- map输入文件最大大小
JVM重用 Hive 语句最终会转换为一系列的 MapReduce 任务,每一个MapReduce 任务是由一系列的Map Task 和 Reduce Task 组成的,默认情况下,MapReduce 中一个 Map Task 或者 Reduce Task 就会启动一个 JVM 进程,一个 Task 执行完毕后,JVM进程就会退出。这样如果任务花费时间很短,又要多次启动 JVM 的情况下,JVM的启动时间会变成一个比较大的消耗,这时,可以通过重用 JVM 来解决。 set mapred.job.reuse.jvm.num.tasks=5;
JVM也是有缺点的,开启JVM重用会一直占用使用到的 task 的插槽,以便进行重用,直到任务完成后才会释放。如果某个不平衡的job中有几个 reduce task 执行的时间要比其他的 reduce task 消耗的时间要多得多的话,那么保留的插槽就会一直空闲却无法被其他的 job 使用,直到所有的 task 都结束了才会释放。
并行执行 有的查询语句,hive会将其转化为一个或多个阶段,包括:MapReduce 阶段、抽样阶段、合并阶段、limit 阶段等。默认情况下,一次只执行一个阶段。但是,如果某些阶段不是互相依赖,是可以并行执行的。多阶段并行是比较耗系统资源的。
set hive.exec.parallel=true; -- 可以开启并发执行。 set hive.exec.parallel.thread.number=16; -- 同一个sql允许最大并行度,默认为8。
推测执行 在分布式集群环境下,因为程序Bug(包括Hadoop本身的bug),负载不均衡或者资源分布不均等原因,会造成同一个作业的多个任务之间运行速度不一致,有些任务的运行速度可能明显慢于其他任务(比如一个作业的某个任务进度只有50%,而其他所有任务已经运行完毕),则这些任务会拖慢作业的整体执行进度。为了避免这种情况发生,Hadoop采用了推测执行(Speculative Execution)机制,它根据一定的法则推测出“拖后腿”的任务,并为这样的任务启动一个备份任务,让该任务与原始任务同时处理同一份数据,并最终选用最先成功运行完成任务的计算结果作为最终结果。
set mapreduce.map.speculative=true; set mapreduce.reduce.speculative=true;
谓词下推 在关系型数据库如MySQL中,也有谓词下推(Predicate Pushdown,PPD)的概念。它就是将SQL语句中的where谓词逻辑都尽可能提前执行,减少下游处理的数据量。 例如以下HiveQL语句:
select a.uid,a.event_type,b.topic_id,b.title from calendar_record_log a left outer join ( select uid,topic_id,title from forum_topic where pt_date = 20190224 and length(content) >= 100 ) b on a.uid = b.uid where a.pt_date = 20190224 and status = 0;
对forum_topic做过滤的where语句写在子查询内部,而不是外部。Hive中有谓词下推优化的配置项hive.optimize.ppd,默认值true,与它对应的逻辑优化器是PredicatePushDown。该优化器就是将OperatorTree中的FilterOperator向上提,见下图。 group by代替distinct 当要统计某一列的去重数时,如果数据量很大,count(distinct)就会非常慢,原因与order by类似,count(distinct)逻辑只会有很少的reducer来处理。这时可以用group by来改写:
select t.a,sum(t.b),count(t.c),count(t.d) from ( select a,b,null c,null d from some_table union all select a,0 b,c,null d from some_table group by a,c union all select a,0 b,null c,d from some_table group by a,d ) t;
多表join时key相同 这种情况会将多个join合并为一个MR job来处理,例如:
select a.event_type,a.event_code,a.event_desc,b.upload_time from calendar_event_code a inner join ( select event_type,upload_time from calendar_record_log where pt_date = 20190225 ) b on a.event_type = b.event_type inner join ( select event_type,upload_time from calendar_record_log_2 where pt_date = 20190225 ) c on a.event_type = c.event_type;
利用map join特性 map join特别适合大小表join的情况。Hive会将build table和probe table在map端直接完成join过程,消灭了reduce,效率很高。
select /*+mapjoin(a)*/ a.event_type,b.upload_time from calendar_event_code a inner join ( select event_type,upload_time from calendar_record_log where pt_date = 20190225 ) b on a.event_type < b.event_type;
优化SQL处理join数据倾斜 2.2.1空值或无意义值 这种情况很常见,比如当事实表是日志类数据时,往往会有一些项没有记录到,我们视情况会将它置为null,或者空字符串、-1等。如果缺失的项很多,在做join时这些空值就会非常集中,拖累进度。 因此,若不需要空值数据,就提前写where语句过滤掉。需要保留的话,将空值key用随机方式打散,例如将用户ID为null的记录随机改为负值:
select a.uid,a.event_type,b.nickname,b.age from ( select (case when uid is null then cast(rand()*-10240 as int) else uid end) as uid, event_type from calendar_record_log where pt_date >= 20190201 ) a left outer join ( select uid,nickname,age from user_info where status = 4 ) b on a.uid = b.uid;
2.2..2 单独处理倾斜key 这其实是上面处理空值方法的拓展,不过倾斜的key变成了有意义的。一般来讲倾斜的key都很少,我们可以将它们抽样出来,对应的行单独存入临时表中,然后打上一个较小的随机数前缀(比如0~9),最后再进行聚合。SQL语句与上面的相仿,不再赘述。 不同数据类型 这种情况不太常见,主要出现在相同业务含义的列发生过逻辑上的变化时。 举个例子,假如我们有一旧一新两张日历记录表,旧表的记录类型字段是(event_type int),新表的是(event_type string)。为了兼容旧版记录,新表的event_type也会以字符串形式存储旧版的值,比如'17'。当这两张表join时,经常要耗费很长时间。其原因就是如果不转换类型,计算key的hash值时默认是以int型做的,这就导致所有“真正的”string型key都分配到一个reducer上。所以要注意类型转换:
select a.uid,a.event_type,b.record_data from calendar_record_log a left outer join ( select uid,event_type from calendar_record_log_2 where pt_date = 20190228 ) b on a.uid = b.uid and b.event_type = cast(a.event_type as string) where a.pt_date = 20190228;
build table过大 有时,build table会大到无法直接使用map join的地步,比如全量用户维度表,而使用普通join又有数据分布不均的问题。这时就要充分利用probe table的限制条件,削减build table的数据量,再使用map join解决。代价就是需要进行两次join。举个例子:
select /*+mapjoin(b)*/ a.uid,a.event_type,b.status,b.extra_info from calendar_record_log a left outer join ( select /*+mapjoin(s)*/ t.uid,t.status,t.extra_info from (select distinct uid from calendar_record_log where pt_date = 20190228) s inner join user_info t on s.uid = t.uid ) b on a.uid = b.uid where a.pt_date = 20190228;
表的优化 3.1小表join大表 (小表需要在左边.) 注:(新版的 hive 已经对小表 JOIN 大表和大表 JOIN 小表进行了优化。小表 放在左边和右边已经没有明显区别。) 3.2大表join大表 当一个表内有许多空值时会导致MapReduce过程中,空成为一个key值,对应的会有大量的value值, 而一个key的value会一起到达reduce造成内存不足;所以要想办法过滤这些空值. 【这里你是否明白一起达到,因为空值太多导致都到了同一个reduce,然后造成内存暴增,所以需要过滤】 (1).通过查询所有不为空的结果
insert overwrite table jointable select n.* from (select * from nullidtable where id is not null ) n left join ori o on n.id = o.id;
查询出空值并给其赋上随机数,避免了key值为空
insert overwrite table jointable select n.* from nullidtable n full join ori o on case when n.id is null then concat('hive', rand()) else n.id end = o.id;
建议: 如果用户对于运行时的偏差非常敏感的话,那么可以将这些功能关闭掉。如果用户因为输入数据量很大而需要执行长时间的map或者Reduce task的话,那么启动推测执行造成的浪费是非常巨大大。
3、hive的钩子,数据湖
通常,Hook是一种在处理过程中拦截事件,消息或函数调用的机制。 Hive hooks是绑定到了Hive内部的工作机制,无需重新编译Hive。从这个意义上讲,提供了使用hive扩展和集成外部功能的能力。换句话说,Hive hadoop可用于在查询处理的各个步骤中运行/注入一些代码。根据钩子的类型,它可以在查询处理期间的不同点调用: Pre-execution hooks-在执行引擎执行查询之前,将调用Pre-execution hooks。请注意,这个目的是此时已经为Hive准备了一个优化的查询计划。 Post-execution hooks -在查询执行完成之后以及将结果返回给用户之前,将调用Post-execution hooks 。 Failure-execution hooks -当查询执行失败时,将调用Failure-execution hooks 。 Pre-driver-run 和post-driver-run hooks-在driver执行查询之前和之后调用Pre-driver-run 和post-driver-run hooks。 Pre-semantic-analyzer 和 Post-semantic-analyzer hooks-在Hive在查询字符串上运行语义分析器之前和之后调用Pre-semantic-analyzer 和Post-semantic-analyzer hooks。 什么是数据湖: 数据湖是一种在系统或存储库中以自然格式存储数据的方法,它有助于以各种模式和结构形式配置数据,通常是对象块或文件。数据湖的主要思想是对企业中的所有数据进行统一存储,从原始数据(这意味着源系统数据的精确副本)转换为用于报告、可视化、分析和机器学习等各种任务的转换数据。湖中的数据包括结构化数据从关系数据库(行和列),半结构化数据(CSV、XML、JSON的日志),非结构化数据(电子邮件,文档,PDF)和二进制数据(图像、音频、视频)从而形成一个集中式数据存储容纳所有形式的数据。 数据湖的核心思想是把不同结构的数据统一存储,使不同数据有一致的存储方式,在使用时方便连接,真正解决数据集成问题。 数据湖泊和数据仓库的区别,主要就是数据仓库的数据进入这个池之前是预先分类的,这可以指导其后面如何进行数据的分析。但在大数据时代,这些都是素材而已,你根本不知道以后如何用它。也就是数据湖泊给后面的数据分析带来了更大的弹性。因此,这个放大数据的仓库,专家建议叫数据湖泊,以区别于数据仓库。 关于数据的数据 数据湖泊(lakes )和数据沼泽(swamps )之间的重要区别在于,组织良好的数据可以形成高效的湖泊,而沼泽只是数据过度复制或被用户孤立的数据。获取有关如何跨组织使用生产数据的信息不仅有利于构建组织良好的数据湖,而且还有助于数据工程师微调数据管道或数据本身。
要了解数据的消耗方式,我们需要找出一些基本问题的答案,例如: 经常访问哪些数据集(表/视图/数据库)? 查询何时运行最频繁? 哪些用户或应用程序正在大量使用这些资源? 什么类型的查询经常运行? 访问最多的对象可以轻松地受益于压缩,列式文件格式或数据分解等优化。可以为利用资源的应用程序或用户分配单独的队列,以平衡群集上的负载。群集资源可以在时间范围内按比例放大,此时大多数查询主要用于满足SLA并在低使用率期间按比例缩小以节省成本。 钩子是一种允许修改程序行为的机制。 它是一种拦截应用程序中的函数调用,消息或事件的技术。 Hive提供了许多不同类型的钩子,上文补充内容已经列出来。 可以在特定事件中调用每种类型的挂钩,并且可以根据用例自定义以执行不同的操作。 例如,在执行物理查询计划之前调用预执行挂钩,并在向job.xml提交查询以编辑敏感信息之前调用redactor挂钩。 Apache Atlas拥有最流行的Hive钩子实现之一,它可以监听Hive中的创建/更新/删除操作,并通过Kafka通知更新Atlas中的元数据。
Implementation Pre-execution hooks可以由ExecuteWithHookContext接口创建实现。这是一个空的接口,简单地调用run方法和HookContext。HookContext 有很多关于查询、HIVE实例和用户的信息。可以很容易地利用信息来检测数据湖如何被其用户使用。
public HookContext(QueryPlan queryPlan, QueryState queryState, Map<String, ContentSummary> inputPathToContentSummary, String userName, String ipAddress, String hiveInstanceAddress, String operationId, String sessionId, String threadId, boolean isHiveServerQuery, PerfLogger perfLogger, QueryInfo queryInfo) throws Exception {
实现HookContext的任何钩子得到查询计划(QueIGrPy)。在QueryPlan的hood下面,有许多getters 被用来收集关于查询的信息。举几个例子:
getQueryProperties - 获取有关查询的详细信息,包括查询是否具有joins,分组,分析函数或任何排序/排序操作。 getQueryStartTime - 返回查询的开始时间。 getOperationName - 返回查询执行的操作类型,例如CREATETABLE,DROPTABLE,ALTERDATABASE等, getQueryStr - 以字符串形式返回查询。
要创建我们自己的Hive钩子,我们只需要一个实现ExecuteWithHookContext的类,并使用我们的自定义逻辑覆盖其run方法来捕获数据。
public class CustomHook implements ExecuteWithHookContext { private static final Logger logger = Logger.getLogger(CustomHook.class.getName()); public void run(HookContext hookContext) throws Exception { assert (hookContext.getHookType() == HookType.PRE_EXEC_HOOK); SessionState ss = SessionState.get(); UserGroupInformation ugi = hookContext.getUgi(); Set<ReadEntity> inputs = hookContext.getInputs(); QueryPlan plan = hookContext.getQueryPlan(); this.run(ss, ugi, plan, inputs); }
需要SessionState和UserGroupInformation来收集有关Hive session 及其users的信息。
public void run(SessionState sess, UserGroupInformation ugi, QueryPlan qpln, Set<ReadEntity> inputs) throws Exception { if (sess != null) { String qid = sess.getQueryId() == null ? qpln.getQueryId() : sess.getQueryId(); String QueryID = qid; String Query = sess.getCmd().trim(); String QueryType = sess.getCommandType(); // get all information about query if (qpln != null) { Long Query_Start_Time = qpln.getQueryStartTime(); QueryProperties queryProps = qpln.getQueryProperties(); if (queryProps != null) { boolean Has_Join = queryProps.hasJoin(); boolean Has_Group_By = queryProps.hasGroupBy(); boolean Has_Sort_By = queryProps.hasSortBy(); boolean Has_Order_By = queryProps.hasOrderBy(); boolean Has_Distribute_By = queryProps.hasDistributeBy(); boolean Has_Cluster_By = queryProps.hasClusterBy(); boolean Has_Windowing = queryProps.hasWindowing(); } } // get user id String username = sess.getUserName() == null ? ugi.getUserName() : sess.getUserName(); // get list of database@table names List<String> tables = new ArrayList<String>(); for (Object o : inputs) { tables.add(o.toString()); } // Add logic here to format logging msg // logger.info(msg) } }
在分配挂钩之前,应将已编译的jar添加到Hive类路径中。 可以在hive-site.xml属性hive.aux.jars.path定义的位置添加jar。 可以使用属性hive.exec.pre.hooks将预执行挂钩设置为自定义挂钩的类。 使用Hive CLI,我们可以执行以下操作:
set hive.exec.pre.hooks=com.myApp.CustomHook;
一旦设置了pre-execution挂钩,就应该为每个用户的每个查询执行CustomHook的代码。 CustomHook收集的信息可以在通用日志记录存储库中记录为逗号分隔值,稍后可以在任何BI工具或Excel文件中提取,以找出有关数据湖使用模式的各种统计信息。
注意事项 虽然挂钩是捕获信息的好方法,但它们可能会增加查询执行的延迟。 钩子中的处理可以保持最小以避免这种开销。 通过Hive钩子无法捕获有关通过Spark的HiveContext在Hive表上完成的处理的信息。 Spark提供了自己的钩子机制。
三、hive的分析函数总结
一、关系运算:
-
等值比较: =. 4
-
不等值比较: <>. 4
-
小于比较: <. 4
-
小于等于比较: <=. 4
-
大于比较: >. 5
-
大于等于比较: >=. 5
-
空值判断: IS NULL. 5
-
非空判断: IS NOT NULL. 6
-
LIKE比较: LIKE. 6
-
JAVA的LIKE操作: RLIKE. 6
-
REGEXP操作: REGEXP. 7
二、数学运算:
-
加法操作: +. 7
-
减法操作: - 7
-
乘法操作: *. 8
-
除法操作: /. 8
-
取余操作: %.. 8
-
位与操作: &.. 9
-
位或操作: |. 9
-
位异或操作: ^. 9
-
位取反操作: ~. 10
三、逻辑运算
-
逻辑与操作: AND.. 10
-
逻辑或操作: OR. 10
-
逻辑非操作: NOT. 10
四、数值计算
-
取整函数: round. 11
-
指定精度取整函数: round. 11
-
向下取整函数: floor. 11
-
向上取整函数: ceil 12
-
向上取整函数: ceiling. 12
-
取随机数函数: rand. 12
-
自然指数函数: exp. 13
-
以10为底对数函数: log10. 13
-
以2为底对数函数: log2. 13
-
对数函数: log. 13
-
幂运算函数: pow.. 14
-
幂运算函数: power. 14
-
开平方函数: sqrt. 14
-
二进制函数: bin. 14
-
十六进制函数: hex. 15
-
反转十六进制函数: unhex. 15
-
进制转换函数: conv. 15
-
绝对值函数: abs. 16
-
正取余函数: pmod. 16
-
正弦函数: sin. 16
-
反正弦函数: asin. 16
-
余弦函数: cos. 17
-
反余弦函数: acos. 17
-
positive函数: positive. 17
-
negative函数: negative. 17
五、日期函数
-
UNIX时间戳转日期函数: from_unixtime. 18
-
获取当前UNIX时间戳函数: unix_timestamp. 18
-
日期转UNIX时间戳函数: unix_timestamp. 18
-
指定格式日期转UNIX时间戳函数: unix_timestamp. 18
-
日期时间转日期函数: to_date. 19
-
日期转年函数: year. 19
-
日期转月函数: month. 19
-
日期转天函数: day. 19
-
日期转小时函数: hour. 20
-
日期转分钟函数: minute. 20
-
日期转秒函数: second. 20
-
日期转周函数: weekofyear. 20
-
日期比较函数: datediff 21
-
日期增加函数: date_add. 21
-
日期减少函数: date_sub. 21
六、条件函数
-
If函数: if 21
-
非空查找函数: COALESCE. 22
-
条件判断函数:CASE. 22
-
条件判断函数:CASE. 22
七、字符串函数
-
字符串长度函数:length. 23
-
字符串反转函数:reverse. 23
-
字符串连接函数:concat. 23
-
带分隔符字符串连接函数:concat_ws. 23
-
字符串截取函数:substr,substring. 24
-
字符串截取函数:substr,substring. 24
-
字符串转大写函数:upper,ucase. 24
-
字符串转小写函数:lower,lcase. 25
-
去空格函数:trim.. 25
-
左边去空格函数:ltrim.. 25
-
右边去空格函数:rtrim.. 25
-
正则表达式替换函数:regexp_replace. 26
-
正则表达式解析函数:regexp_extract. 26
-
URL解析函数:parse_url 26
-
json解析函数:get_json_object. 27
-
空格字符串函数:space. 27
-
重复字符串函数:repeat. 27
-
首字符ascii函数:ascii 28
-
左补足函数:lpad. 28
-
右补足函数:rpad. 28
-
分割字符串函数: split. 28
-
集合查找函数: find_in_set. 29
八、集合统计函数
-
个数统计函数: count. 29
-
总和统计函数: sum.. 29
-
平均值统计函数: avg. 30
-
最小值统计函数: min. 30
-
最大值统计函数: max. 30
-
非空集合总体变量函数: var_pop. 30
-
非空集合样本变量函数: var_samp. 31
-
总体标准偏离函数: stddev_pop. 31
-
样本标准偏离函数: stddev_samp. 31
-
中位数函数: percentile. 31
-
近似中位数函数: percentile_approx. 32
-
近似中位数函数: percentile_approx. 32
-
直方图: histogram_numeric. 32
九、复合类型构建操作
-
Map类型构建: map. 32
-
Struct类型构建: struct. 33
-
array类型构建: array. 33
十、复杂类型访问操作
-
array类型访问: A[n] 33
-
map类型访问: M[key] 34
-
struct类型访问: S.x. 34
十一、复杂类型长度统计函数
-
Map类型长度函数: size(Map<K.V>) 34
-
array类型长度函数: size(Array<T>) 34
-
类型转换函数... 35
四、hive例子演示
一、关系运算:
1. 等值比较: =
语法:A=B 操作类型:所有基本类型 描述: 如果表达式A与表达式B相等,则为TRUE;否则为FALSE 举例:
hive>select 1 from lxw_dual where 1=1; 1
2、不等值比较: <>
语法: A <> B 操作类型: 所有基本类型 描述: 如果表达式A为NULL,或者表达式B为NULL,返回NULL;如果表达式A与表达式B不相等,则为TRUE;否则为FALSE 举例:
hive> select1 from lxw_dual where 1 <> 2; 1
-
小于比较: < 语法: A < B 操作类型: 所有基本类型 描述: 如果表达式A为NULL,或者表达式B为NULL,返回NULL;如果表达式A小于表达式B,则为TRUE;否则为FALSE 举例:
hive> select1 from lxw_dual where 1 < 2; 1
-
小于等于比较: <= 语法: A <= B 操作类型: 所有基本类型 描述: 如果表达式A为NULL,或者表达式B为NULL,返回NULL;如果表达式A小于或者等于表达式B,则为TRUE;否则为FALSE 举例:
hive> select1 from lxw_dual where 1 <= 1; 1
-
大于比较: > 语法: A > B 操作类型: 所有基本类型 描述: 如果表达式A为NULL,或者表达式B为NULL,返回NULL;如果表达式A大于表达式B,则为TRUE;否则为FALSE 举例: hive> select1 from lxw_dual where 2 > 1; 1
-
大于等于比较: >= 语法: A >= B 操作类型: 所有基本类型 描述: 如果表达式A为NULL,或者表达式B为NULL,返回NULL;如果表达式A大于或者等于表达式B,则为TRUE;否则为FALSE 举例: hive> select1 from lxw_dual where 1 >= 1; 1
注意:String的比较要注意(常用的时间比较可以先to_date之后再比较)
hive> select* from lxw_dual; OK 201111120900:00:00 2011111209 hive> selecta,b,a<b,a>b,a=b from lxw_dual; 201111120900:00:00 2011111209 false true false
3、空值判断: IS NULL
语法: A IS NULL 操作类型: 所有类型 描述: 如果表达式A的值为NULL,则为TRUE;否则为FALSE 举例:
hive> select1 from lxw_dual where null is null; 1
-
非空判断: IS NOTNULL 语法: A IS NOT NULL 操作类型: 所有类型 描述: 如果表达式A的值为NULL,则为FALSE;否则为TRUE 举例:
hive> select1 from lxw_dual where 1 is not null; 1
4、LIKE比较: LIKE
语法: A LIKE B 操作类型: strings 描述: 如果字符串A或者字符串B为NULL,则返回NULL;如果字符串A符合表达式B 的正则语法,则为TRUE;否则为FALSE。B中字符”_”表示任意单个字符,而字符”%”表示任意数量的字符。 举例:
hive> select1 from lxw_dual where 'football' like 'foot%'; 1 hive> select1 from lxw_dual where 'football' like 'foot____'; 1
注意:否定比较时候用NOT ALIKE B
hive> select1 from lxw_dual where NOT 'football' like 'fff%'; 1
-
JAVA的LIKE操作: RLIKE 语法: A RLIKE B 操作类型: strings 描述: 如果字符串A或者字符串B为NULL,则返回NULL;如果字符串A符合JAVA正则表达式B的正则语法,则为TRUE;否则为FALSE。 举例:
hive> select1 from lxw_dual where 'footbar’ rlike '^f.*r$’; 1
注意:判断一个字符串是否全为数字:
hive>select 1from lxw_dual where '123456' rlike '^\d+$'; 1 hive> select1 from lxw_dual where '123456aa' rlike '^\d+$';
3、REGEXP操作: REGEXP 语法: A REGEXP B 操作类型: strings 描述: 功能与RLIKE相同 举例:
hive> select1 from lxw_dual where 'footbar' REGEXP '^f.*r$'; 1
二、数学运算:
1. 加法操作: +
语法: A + B 操作类型:所有数值类型 说明:返回A与B相加的结果。结果的数值类型等于A的类型和B的类型的最小父类型(详见数据类型的继承关系)。比如,int + int 一般结果为int类型,而int + double 一般结果为double类型 举例:
hive> select1 + 9 from lxw_dual; 10 hive> createtable lxw_dual as select 1 + 1.2 from lxw_dual; hive>describe lxw_dual; _c0 double
2、减法操作: -
语法: A – B 操作类型:所有数值类型 说明:返回A与B相减的结果。结果的数值类型等于A的类型和B的类型的最小父类型(详见数据类型的继承关系)。比如,int – int 一般结果为int类型,而int – double 一般结果为double类型 举例:
hive> select10 – 5 from lxw_dual; 5 hive> createtable lxw_dual as select 5.6 – 4 from lxw_dual; hive>describe lxw_dual; _c0 double
3、乘法操作:
语法: A * B 操作类型:所有数值类型 说明:返回A与B相乘的结果。结果的数值类型等于A的类型和B的类型的最小父类型(详见数据类型的继承关系)。注意,如果A乘以B的结果超过默认结果类型的数值范围,则需要通过cast将结果转换成范围更大的数值类型 举例:
hive> select40 * 5 from lxw_dual; 200
4、除法操作: /
语法: A / B 操作类型:所有数值类型 说明:返回A除以B的结果。结果的数值类型为double 举例: hive> select40 / 5 from lxw_dual; 8.0
注意:hive中最高精度的数据类型是double,只精确到小数点后16位,在做除法运算的时候要特别注意 hive>select ceil(28.0/6.999999999999999999999) from lxw_duallimit 1; 结果为4 hive>select ceil(28.0/6.99999999999999) from lxw_dual limit1; 结果为5
5、取余操作: %
语法: A % B 操作类型:所有数值类型 说明:返回A除以B的余数。结果的数值类型等于A的类型和B的类型的最小父类型(详见数据类型的继承关系)。 举例:
hive> select 41 % 5 from lxw_dual; 1 hive> select 8.4 % 4 from lxw_dual; 0.40000000000000036
注意:精度在hive中是个很大的问题,类似这样的操作最好通过round指定精度
hive> select round(8.4 % 4 , 2) from lxw_dual; 0.4
四、操作符
1、位与操作: &
语法: A & B 操作类型:所有数值类型 说明:返回A和B按位进行与操作的结果。结果的数值类型等于A的类型和B的类型的最小父类型(详见数据类型的继承关系)。 举例:
hive> select 4 & 8 from lxw_dual; 0 hive> select 6 & 4 from lxw_dual; 4
2、位或操作: |
语法: A | B 操作类型:所有数值类型 说明:返回A和B按位进行或操作的结果。结果的数值类型等于A的类型和B的类型的最小父类型(详见数据类型的继承关系)。 举例:
hive> select 4 | 8 from lxw_dual; 12 hive> select 6 | 8 from lxw_dual; 14
3、位异或操作: ^
语法: A ^ B 操作类型:所有数值类型 说明:返回A和B按位进行异或操作的结果。结果的数值类型等于A的类型和B的类型的最小父类型(详见数据类型的继承关系)。 举例:
hive> select 4 ^ 8 from lxw_dual; 12 hive> select 6 ^ 4 from lxw_dual; 2
4.位取反操作: ~
语法: ~A 操作类型:所有数值类型 说明:返回A按位取反操作的结果。结果的数值类型等于A的类型。 举例:
hive> select ~6 from lxw_dual; -7 hive> select ~4 from lxw_dual; -5
五、逻辑运算:
1. 逻辑与操作: AND
语法: A AND B 操作类型:boolean 说明:如果A和B均为TRUE,则为TRUE;否则为FALSE。如果A为NULL或B为NULL,则为NULL 举例:
hive> select 1 from lxw_dual where 1=1 and 2=2; 1
2、逻辑或操作: OR
语法: A OR B 操作类型:boolean 说明:如果A为TRUE,或者B为TRUE,或者A和B均为TRUE,则为TRUE;否则为FALSE 举例:
hive> select 1 from lxw_dual where 1=2 or 2=2; 1
3、逻辑非操作: NOT
语法: NOT A 操作类型:boolean 说明:如果A为FALSE,或者A为NULL,则为TRUE;否则为FALSE 举例:
hive> select 1 from lxw_dual where not 1=2; 1
六、数值计算
1、取整函数: round
语法: round(double a) 返回值: BIGINT 说明: 返回double类型的整数值部分(遵循四舍五入) 举例:
hive> select round(3.1415926) from lxw_dual; 3 hive> select round(3.5) from lxw_dual; 4 hive> create table lxw_dual as select round(9542.158) fromlxw_dual; hive> describe lxw_dual; _c0 bigint
2、指定精度取整函数: round
语法: round(double a, int d) 返回值: DOUBLE 说明: 返回指定精度d的double类型 举例:
hive> select round(3.1415926,4) from lxw_dual; 3.1416
3、向下取整函数: floor
语法: floor(double a) 返回值: BIGINT 说明: 返回等于或者小于该double变量的最大的整数 举例:
hive> select floor(3.1415926) from lxw_dual; 3 hive> select floor(25) from lxw_dual; 25
4、向上取整函数: ceil
语法: ceil(double a) 返回值: BIGINT 说明: 返回等于或者大于该double变量的最小的整数 举例:
hive> select ceil(3.1415926) from lxw_dual; 4 hive> select ceil(46) from lxw_dual; 46
5、向上取整函数: ceiling
语法: ceiling(double a) 返回值: BIGINT 说明: 与ceil功能相同 举例:
hive> select ceiling(3.1415926) from lxw_dual; 4 hive> select ceiling(46) from lxw_dual; 46
6、取随机数函数: rand
语法: rand(),rand(int seed) 返回值: double 说明: 返回一个0到1范围内的随机数。如果指定种子seed,则会等到一个稳定的随机数序列 举例:
hive> select rand() from lxw_dual; 0.5577432776034763 hive> select rand() from lxw_dual; 0.6638336467363424 hive> select rand(100) from lxw_dual; 0.7220096548596434 hive> select rand(100) from lxw_dual; 0.7220096548596434
7、自然指数函数: exp
语法: exp(double a) 返回值: double 说明: 返回自然对数e的a次方 举例:
hive> select exp(2) from lxw_dual; 7.38905609893065
8、自然对数函数: ln
语法: ln(double a) 返回值: double 说明: 返回a的自然对数 举例:
hive> select ln(7.38905609893065) from lxw_dual; 2.0
自然对数函数: ln 语法: ln(double a) 返回值: double 说明: 返回a的自然对数 举例: hive> select ln(7.38905609893065) from lxw_dual; 2.0
9、以10为底对数函数: log10
语法: log10(double a) 返回值: double 说明: 返回以10为底的a的对数 举例:
hive> select log10(100) from lxw_dual; 2.0
10、以2为底对数函数: log2
语法: log2(double a) 返回值: double 说明: 返回以2为底的a的对数 举例:
hive> select log2(8) from lxw_dual; 3.0
11、对数函数: log
语法: log(double base, double a) 返回值: double 说明: 返回以base为底的a的对数 举例:
hive> select log(4,256) from lxw_dual; 4.0
12、幂运算函数: pow
语法: pow(double a, double p) 返回值: double 说明: 返回a的p次幂 举例:
hive> select pow(2,4) from lxw_dual; 16.0
13、幂运算函数: power
语法: power(double a, double p) 返回值: double 说明: 返回a的p次幂,与pow功能相同 举例:
hive> select power(2,4) from lxw_dual; 16.0
14、开平方函数: sqrt
语法: sqrt(double a) 返回值: double 说明: 返回a的平方根 举例:
hive> select sqrt(16) from lxw_dual; 4.0
15、二进制函数: bin
语法: bin(BIGINT a) 返回值: string 说明: 返回a的二进制代码表示 举例:
hive> select bin(7) from lxw_dual; 111
17、十六进制函数: hex
语法: hex(BIGINT a) 返回值: string 说明: 如果变量是int类型,那么返回a的十六进制表示;如果变量是string类型,则返回该字符串的十六进制表示 举例:
hive> select hex(17) from lxw_dual; 11 hive> select hex(‘abc’) from lxw_dual; 616263
18、反转十六进制函数: unhex
语法: unhex(string a) 返回值: string 说明: 返回该十六进制字符串所代码的字符串 举例:
hive> select unhex(‘616263’)from lxw_dual; abc hive> select unhex(‘11’)from lxw_dual; - hive> select unhex(616263) from lxw_dual; abc
19、进制转换函数: conv
语法: conv(BIGINT num, int from_base, int to_base) 返回值: string 说明: 将数值num从from_base进制转化到to_base进制 举例:
hive> select conv(17,10,16) from lxw_dual; 11 hive> select conv(17,10,2) from lxw_dual; 10001
20、绝对值函数: abs
语法: abs(double a) abs(int a) 返回值: double int 说明: 返回数值a的绝对值 举例:
hive> select abs(-3.9) from lxw_dual; 3.9 hive> select abs(10.9) from lxw_dual; 10.9
21、正取余函数: pmod
语法: pmod(int a, int b),pmod(double a, double b) 返回值: int double 说明: 返回正的a除以b的余数 举例:
hive> select pmod(9,4) from lxw_dual; 1 hive> select pmod(-9,4) from lxw_dual; 3
22、正弦函数: sin
语法: sin(double a) 返回值: double 说明: 返回a的正弦值 举例:
hive> select sin(0.8) from lxw_dual; 0.7173560908995228
23、反正弦函数: asin
语法: asin(double a) 返回值: double 说明: 返回a的反正弦值 举例:
hive> select asin(0.7173560908995228) from lxw_dual; 0.8
24、余弦函数: cos
语法: cos(double a) 返回值: double 说明: 返回a的余弦值 举例:
hive> select cos(0.9) from lxw_dual; 0.6216099682706644
25、反余弦函数: acos
语法: acos(double a) 返回值: double 说明: 返回a的反余弦值 举例:
hive> select acos(0.6216099682706644) from lxw_dual; 0.9
26、positive函数: positive
语法: positive(int a), positive(double a) 返回值: int double 说明: 返回a 举例:
hive> select positive(-10) from lxw_dual; -10 hive> select positive(12) from lxw_dual; 12
27、negative函数: negative
语法: negative(int a), negative(double a) 返回值: int double 说明: 返回-a 举例:
hive> select negative(-5) from lxw_dual; 5 hive> select negative(8) from lxw_dual; -8
七、日期函数
1、UNIX时间戳转日期函数:from_unixtime
语法: from_unixtime(bigint unixtime[, string format]) 返回值: string 说明: 转化UNIX时间戳(从1970-01-01 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式 举例:
hive> select from_unixtime(1323308943,'yyyyMMdd') from lxw_dual; 20111208
五、日期函数1. UNIX时间戳转日期函数:from_unixtime 语法: from_unixtime(bigint unixtime[, string format]) 返回值: string 说明: 转化UNIX时间戳(从1970-01-01 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式 举例: hive> select from_unixtime(1323308943,'yyyyMMdd') from lxw_dual; 20111208
2、获取当前UNIX时间戳函数:unix_timestamp
语法: unix_timestamp() 返回值: bigint 说明: 获得当前时区的UNIX时间戳 举例:
hive> select unix_timestamp() from lxw_dual; 1323309615
3、日期转UNIX时间戳函数:unix_timestamp
语法: unix_timestamp(string date) 返回值: bigint 说明: 转换格式为"yyyy-MM-ddHH:mm:ss"的日期到UNIX时间戳。如果转化失败,则返回0。 举例:
hive> select unix_timestamp('2011-12-07 13:01:03') from lxw_dual; 1323234063
4、指定格式日期转UNIX时间戳函数:unix_timestamp
语法: unix_timestamp(string date, string pattern) 返回值: bigint 说明: 转换pattern格式的日期到UNIX时间戳。如果转化失败,则返回0。 举例:
hive> select unix_timestamp('20111207 13:01:03','yyyyMMddHH:mm:ss') from lxw_dual; 1323234063
5、日期时间转日期函数:to_date
语法: to_date(string timestamp) 返回值: string 说明: 返回日期时间字段中的日期部分。 举例:
hive> select to_date('2011-12-08 10:03:01') from lxw_dual; 2011-12-08
6、日期转年函数: year
语法: year(string date) 返回值: int 说明: 返回日期中的年。 举例:
hive> select year('2011-12-08 10:03:01') from lxw_dual; 2011 hive> select year('2012-12-08')from lxw_dual; 2012
7、日期转月函数: month
语法: month (string date) 返回值: int 说明: 返回日期中的月份。 举例:
hive> select month('2011-12-08 10:03:01') from lxw_dual; 12 hive> select month('2011-08-08')from lxw_dual; 8
8、日期转天函数: day
语法: day (string date) 返回值: int 说明: 返回日期中的天。 举例:
hive> select day('2011-12-08 10:03:01') from lxw_dual; 8 hive> select day('2011-12-24')from lxw_dual; 24
9、日期转小时函数: hour
语法: hour (string date) 返回值: int 说明: 返回日期中的小时。 举例:
hive> select hour('2011-12-08 10:03:01') from lxw_dual; 10
10、日期转分钟函数: minute
语法: minute (string date) 返回值: int 说明: 返回日期中的分钟。 举例:
hive> select minute('2011-12-08 10:03:01') from lxw_dual; 3
11、日期转秒函数: second
语法: second (string date) 返回值: int 说明: 返回日期中的秒。 举例:
hive> select second('2011-12-08 10:03:01') from lxw_dual; 1
12、日期转周函数:weekofyear
语法: weekofyear (string date) 返回值: int 说明: 返回日期在当前的周数。 举例:
hive> select weekofyear('2011-12-08 10:03:01') from lxw_dual; 49
13、日期比较函数: datediff
语法: datediff(string enddate, string startdate) 返回值: int 说明: 返回结束日期减去开始日期的天数。 举例:
hive> select datediff('2012-12-08','2012-05-09')from lxw_dual; 213
14、日期增加函数: date_add
语法: date_add(string startdate, int days) 返回值: string 说明: 返回开始日期startdate增加days天后的日期。 举例:
hive> select date_add('2012-12-08',10)from lxw_dual; 2012-12-18
15、日期减少函数: date_sub
语法: date_sub (string startdate, int days) 返回值: string 说明: 返回开始日期startdate减少days天后的日期。 举例:
hive> select date_sub('2012-12-08',10)from lxw_dual; 2012-11-28
八、条件函数
1、If函数: if
语法: if(boolean testCondition, T valueTrue, T valueFalseOrNull) 返回值: T 说明: 当条件testCondition为TRUE时,返回valueTrue;否则返回valueFalseOrNull 举例:
hive> select if(1=2,100,200) from lxw_dual; 200 hive> select if(1=1,100,200) from lxw_dual; 100
2、非空查找函数: COALESCE
语法: COALESCE(T v1, T v2, …) 返回值: T 说明: 返回参数中的第一个非空值;如果所有值都为NULL,那么返回NULL 举例:
hive> select COALESCE(null,'100','50′) from lxw_dual; 100
3、条件判断函数:CASE
语法: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END 返回值: T 说明:如果a等于b,那么返回c;如果a等于d,那么返回e;否则返回f 举例:
hive> Select case 100 when 50 then 'tom' when 100 then 'mary'else 'tim' end from lxw_dual; mary hive> Select case 200 when 50 then 'tom' when 100 then 'mary'else 'tim' end from lxw_dual; tim
4、条件判断函数:CASE
语法: CASE WHEN a THEN b [WHEN c THEN d]* [ELSE e] END 返回值: T 说明:如果a为TRUE,则返回b;如果c为TRUE,则返回d;否则返回e 举例:
hive> select case when 1=2 then 'tom' when 2=2 then 'mary' else'tim' end from lxw_dual; mary hive> select case when 1=1 then 'tom' when 2=2 then 'mary' else'tim' end from lxw_dual; tom
九、字符串函数
1、字符串长度函数:length
语法: length(string A) 返回值: int 说明:返回字符串A的长度 举例:
hive> select length('abcedfg') from lxw_dual; 7
2、字符串反转函数:reverse
语法: reverse(string A) 返回值: string 说明:返回字符串A的反转结果 举例:
hive> select reverse(abcedfg’) from lxw_dual; gfdecba
3、字符串连接函数:concat
语法: concat(string A, string B…) 返回值: string 说明:返回输入字符串连接后的结果,支持任意个输入字符串 举例:
hive> select concat(‘abc’,'def’,'gh’) from lxw_dual; abcdefgh
4、带分隔符字符串连接函数:concat_ws
语法: concat_ws(string SEP, string A, string B…) 返回值: string 说明:返回输入字符串连接后的结果,SEP表示各个字符串间的分隔符 举例:
hive> select concat_ws(',','abc','def','gh') from lxw_dual; abc,def,gh
5、字符串截取函数:substr,substring
语法: substr(string A, int start),substring(string A, int start) 返回值: string 说明:返回字符串A从start位置到结尾的字符串 举例:
hive> select substr('abcde',3) from lxw_dual; cde hive> select substring('abcde',3) from lxw_dual; cde hive> selectsubstr('abcde',-1) from lxw_dual; (和ORACLE相同) e
6、字符串截取函数:substr,substring
语法: substr(string A, int start, int len),substring(string A, intstart, int len) 返回值: string 说明:返回字符串A从start位置开始,长度为len的字符串 举例:
hive> select substr('abcde',3,2) from lxw_dual; cd hive> select substring('abcde',3,2) from lxw_dual; cd hive>select substring('abcde',-2,2) from lxw_dual; de
7、字符串转大写函数:upper,ucase
语法: upper(string A) ucase(string A) 返回值: string 说明:返回字符串A的大写格式 举例:
hive> select upper('abSEd') from lxw_dual; ABSED hive> select ucase('abSEd') from lxw_dual; ABSED
8、字符串转小写函数:lower,lcase
语法: lower(string A) lcase(string A) 返回值: string 说明:返回字符串A的小写格式 举例:
hive> select lower('abSEd') from lxw_dual; absed hive> select lcase('abSEd') from lxw_dual; absed
9、去空格函数:trim
语法: trim(string A) 返回值: string 说明:去除字符串两边的空格 举例:
hive> select trim(' abc ') from lxw_dual; abc
10、左边去空格函数:ltrim
语法: ltrim(string A) 返回值: string 说明:去除字符串左边的空格 举例:
hive> select ltrim(' abc ') from lxw_dual; abc
11、右边去空格函数:rtrim
语法: rtrim(string A) 返回值: string 说明:去除字符串右边的空格 举例:
hive> select rtrim(' abc ') from lxw_dual; abc
12、正则表达式替换函数:regexp_replace
语法: regexp_replace(string A, string B, string C) 返回值: string 说明:将字符串A中的符合java正则表达式B的部分替换为C。注意,在有些情况下要使用转义字符,类似oracle中的regexp_replace函数。 举例:
hive> select regexp_replace('foobar', 'oo|ar', '') from lxw_dual; fb
13、正则表达式解析函数:regexp_extract
语法: regexp_extract(string subject, string pattern, int index) 返回值: string 说明:将字符串subject按照pattern正则表达式的规则拆分,返回index指定的字符。 举例:
hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 1) fromlxw_dual; the hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 2) fromlxw_dual; bar hive> select regexp_extract('foothebar', 'foo(.*?)(bar)', 0) fromlxw_dual; foothebar
注意,在有些情况下要使用转义字符,下面的等号要用双竖线转义,这是java正则表达式的规则。
select data_field, regexp_extract(data_field,'.*?bgStart\=([^&]+)',1) as aaa, regexp_extract(data_field,'.*?contentLoaded_headStart\=([^&]+)',1) as bbb, regexp_extract(data_field,'.*?AppLoad2Req\=([^&]+)',1) as ccc from pt_nginx_loginlog_st where pt = '2012-03-26'limit 2;
14、URL解析函数:parse_url
语法: parse_url(string urlString, string partToExtract [, stringkeyToExtract]) 返回值: string 说明:返回URL中指定的部分。partToExtract的有效值为:HOST, PATH, QUERY, REF, PROTOCOL, AUTHORITY, FILE, and USERINFO. 举例:
hive> selectparse_url('http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1', 'HOST') fromlxw_dual; facebook.com hive> selectparse_url('http://facebook.com/path1/p.php?k1=v1&k2=v2#Ref1', 'QUERY','k1') from lxw_dual; v1
15、json解析函数:get_json_object
语法: get_json_object(string json_string, string path) 返回值: string 说明:解析json的字符串json_string,返回path指定的内容。如果输入的json字符串无效,那么返回NULL。 举例:
hive> select get_json_object('{"store": > {"fruit":[{"weight":8,"type":"apple"},{"weight":9,"type":"pear"}], > "bicycle":{"price":19.95,"color":"red"} > }, > "email":"amy@only_for_json_udf_test.net", > "owner":"amy" > } > ','$.owner') from lxw_dual; > amy
16、空格字符串函数:space
语法: space(int n) 返回值: string 说明:返回长度为n的字符串 举例:
hive> select space(10) from lxw_dual; hive> select length(space(10)) from lxw_dual; 10
17、重复字符串函数:repeat
语法: repeat(string str, int n) 返回值: string 说明:返回重复n次后的str字符串 举例:
hive> select repeat('abc',5) from lxw_dual; abcabcabcabcabc
18、首字符ascii函数:ascii
语法: ascii(string str) 返回值: int 说明:返回字符串str第一个字符的ascii码 举例:
hive> select ascii('abcde') from lxw_dual; 97
19、左补足函数:lpad
语法: lpad(string str, int len, string pad) 返回值: string 说明:将str进行用pad进行左补足到len位 举例:
hive> select lpad('abc',10,'td') from lxw_dual; tdtdtdtabc
注意:与GP,ORACLE不同,pad 不能默认
注意:与GP,ORACLE不同,pad 不能默认
20、右补足函数:rpad
语法: rpad(string str, int len, string pad) 返回值: string 说明:将str进行用pad进行右补足到len位 举例:
hive> select rpad('abc',10,'td') from lxw_dual; abctdtdtdt
21、分割字符串函数: split
语法: split(string str, stringpat) 返回值: array 说明: 按照pat字符串分割str,会返回分割后的字符串数组 举例:
hive> select split('abtcdtef','t') from lxw_dual; ["ab","cd","ef"]
22、集合查找函数:find_in_set
语法: find_in_set(string str, string strList) 返回值: int 说明: 返回str在strlist第一次出现的位置,strlist是用逗号分割的字符串。如果没有找该str字符,则返回0 举例:
hive> select find_in_set('ab','ef,ab,de') from lxw_dual; 2 hive> select find_in_set('at','ef,ab,de') from lxw_dual; 0
十、集合统计函数
1、个数统计函数: count
语法: count(), count(expr), count(DISTINCT expr[, expr_.]) 返回值: int 说明: count()统计检索出的行的个数,包括NULL值的行;count(expr)返回指定字段的非空值的个数;count(DISTINCTexpr[, expr_.])返回指定字段的不同的非空值的个数 举例:
hive> select count(*) from lxw_dual; 20 hive> select count(distinct t) from lxw_dual; 10
2、总和统计函数: sum
语法: sum(col), sum(DISTINCT col) 返回值: double 说明: sum(col)统计结果集中col的相加的结果;sum(DISTINCT col)统计结果中col不同值相加的结果 举例:
hive> select sum(t) from lxw_dual; 100 hive> select sum(distinct t) from lxw_dual; 70
3、平均值统计函数: avg
语法: avg(col), avg(DISTINCT col) 返回值: double 说明: avg(col)统计结果集中col的平均值;avg(DISTINCT col)统计结果中col不同值相加的平均值 举例:
hive> select avg(t) from lxw_dual; 50 hive> select avg (distinct t) from lxw_dual; 30
4、最小值统计函数: min
语法: min(col) 返回值: double 说明: 统计结果集中col字段的最小值 举例:
hive> select min(t) from lxw_dual; 20
5、最大值统计函数: max
语法: maxcol) 返回值: double 说明: 统计结果集中col字段的最大值 举例:
hive> select max(t) from lxw_dual; 120
6、非空集合总体变量函数:var_pop
语法: var_pop(col) 返回值: double 说明: 统计结果集中col非空集合的总体变量(忽略null) 举例:
7、非空集合样本变量函数:var_samp
语法: var_samp (col) 返回值: double 说明: 统计结果集中col非空集合的样本变量(忽略null) 举例:
8、总体标准偏离函数:stddev_pop
语法: stddev_pop(col) 返回值: double 说明: 该函数计算总体标准偏离,并返回总体变量的平方根,其返回值与VAR_POP函数的平方根相同 举例:
9、样本标准偏离函数:stddev_samp
语法: stddev_samp (col) 返回值: double 说明: 该函数计算样本标准偏离 举例:
10.中位数函数:percentile
语法: percentile(BIGINT col, p) 返回值: double 说明: 求准确的第pth个百分位数,p必须介于0和1之间,但是col字段目前只支持整数,不支持浮点数类型 举例:
11、中位数函数:percentile
语法: percentile(BIGINT col, array(p1 [, p2]…)) 返回值: array<double> 说明: 功能和上述类似,之后后面可以输入多个百分位数,返回类型也为array<double>,其中为对应的百分位数。 举例:
select percentile(score,<0.2,0.4>) from lxw_dual;
取0.2,0.4位置的数据
12、近似中位数函数:percentile_approx
语法: percentile_approx(DOUBLE col, p [, B]) 返回值: double 说明: 求近似的第pth个百分位数,p必须介于0和1之间,返回类型为double,但是col字段支持浮点类型。参数B控制内存消耗的近似精度,B越大,结果的准确度越高。默认为10,000。当col字段中的distinct值的个数小于B时,结果为准确的百分位数 举例:
13、近似中位数函数:percentile_approx
语法: percentile_approx(DOUBLE col, array(p1 [, p2]…) [, B]) 返回值: array<double> 说明: 功能和上述类似,之后后面可以输入多个百分位数,返回类型也为array<double>,其中为对应的百分位数。 举例:
14、直方图:histogram_numeric
语法: histogram_numeric(col, b) 返回值: array<struct {‘x’,‘y’}> 说明: 以b为基准计算col的直方图信息。 举例:
hive> select histogram_numeric(100,5) from lxw_dual; [{"x":100.0,"y":1.0}]
十一、复合类型构建操作
1、Map类型构建: map
语法: map (key1, value1, key2, value2, …) 说明:根据输入的key和value对构建map类型 举例:
hive> Create table lxw_test as select map('100','tom','200','mary')as t from lxw_dual; hive> describe lxw_test; t map<string,string> hive> select t from lxw_test; {"100":"tom","200":"mary"}
2、Struct类型构建: struct
语法: struct(val1, val2, val3, …) 说明:根据输入的参数构建结构体struct类型 举例:
hive> create table lxw_test as select struct('tom','mary','tim')as t from lxw_dual; hive> describe lxw_test; t struct<col1:string,col2:string,col3:string> hive> select t from lxw_test; {"col1":"tom","col2":"mary","col3":"tim"}
3、array类型构建: array
语法: array(val1, val2, …) 说明:根据输入的参数构建数组array类型 举例:
hive> create table lxw_test as selectarray("tom","mary","tim") as t from lxw_dual; hive> describe lxw_test; t array<string> hive> select t from lxw_test; ["tom","mary","tim"]
十二、复杂类型访问操作
1、array类型访问: A[n]
语法: A[n] 操作类型: A为array类型,n为int类型 说明:返回数组A中的第n个变量值。数组的起始下标为0。比如,A是个值为['foo', 'bar']的数组类型,那么A[0]将返回'foo',而A[1]将返回'bar' 举例:
hive> create table lxw_test as selectarray("tom","mary","tim") as t from lxw_dual; hive> select t[0],t[1],t[2] from lxw_test; tom mary tim
2、map类型访问: M[key]
语法: M[key] 操作类型: M为map类型,key为map中的key值 说明:返回map类型M中,key值为指定值的value值。比如,M是值为{'f' -> 'foo', 'b'-> 'bar', 'all' -> 'foobar'}的map类型,那么M['all']将会返回'foobar' 举例:
hive> Create table lxw_test as selectmap('100','tom','200','mary') as t from lxw_dual; hive> select t['200'],t['100'] from lxw_test; mary tom
3、struct类型访问: S.x
语法: S.x 操作类型: S为struct类型 说明:返回结构体S中的x字段。比如,对于结构体struct foobar {int foo, int bar},foobar.foo返回结构体中的foo字段 举例:
hive> create table lxw_test as select struct('tom','mary','tim')as t from lxw_dual; hive> describe lxw_test; t struct<col1:string,col2:string,col3:string> hive> select t.col1,t.col3 from lxw_test; tom tim
十三、复杂类型长度统计函数
1、Map类型长度函数: size(Map<K.V>)
语法: size(Map<K.V>) 返回值: int 说明: 返回map类型的长度 举例:
hive> select size(map('100','tom','101','mary')) from lxw_dual; 2
2、array类型长度函数: size(Array<T>)
语法: size(Array<T>) 返回值: int 说明: 返回array类型的长度 举例:
hive> select size(array('100','101','102','103')) from lxw_dual; 4
3、类型转换函数
类型转换函数: cast 语法: cast(expr as <type>) 返回值: Expected "=" to follow "type" 说明: 返回array类型的长度 举例:
hive> select cast(1 as bigint) from lxw_dual;
三、hive企业实战手册
1、Shell脚本实现hive增量加载
实现思路: 1.每天凌晨将前一天增量的数据从业务系统导出到文本,并FTP到hadoop集群某个主节点上上传路径默认为:/mnt/data/crawler/ 2.主节点上通过shell脚本调用hive命令加载本地增量文件到hive临时表 3.shell脚本中,使用hive sql 实现临时表中的增量数据更新或者新增增量数据到hive主数据表中。 实现步骤:
1.建表语句, 分别创建两张表test_temp, test 表
create table crawler.test_temp( a.id string, a.name string, a.email string, create_time string ) row format delimited fields terminated by ',' stored as textfile ; +++++++++++++++++++++++++++++++++ create table crawler.test( a.id string, a.name string, a.email string, create_time string ) partitioned by (dt string) row format delimited fields terminated by ' ' stored as orc ;
2.编写处理加载本地增量数据到hive临时表的shell脚本test_temp.sh
#! /bin/bash ################################## # 调用格式: # # 脚本名称 [yyyymmdd] # # 日期参数可选,默认是系统日期-1 # ################################## dt='' table=test_temp #获取当前系统日期 sysdate=`date +%Y%m%d` #获取昨日日期,格式: YYYYMMDD yesterday=`date -d yesterday +%Y%m%d` #数据文件地址 file_path=/mnt/data/crawler/ if [ $# -eq 1 ]; then dt=$1 elif [ $# -eq 0 ]; then dt=$yesterday else echo "非法参数!" #0-成功,非0-失败 exit 1 fi filename=$file_path$table'_'$dt'.txt' if [ ! -e $filename ]; then echo "$filename 数据文件不存在!" exit 1 fi hive<<EOF load data local inpath '$filename' overwrite into table crawler.$table; EOF if [ $? -eq 0 ]; then echo "" echo $dt "$table 加载成功!" else echo "" echo $dt "$table 加载失败!" fi
3.增量加载临时数据到主数据表的shell脚本test.sh
#! /bin/bash ################################## table=test #获取当前系统日期 sysdate=`date +%Y%m%d` #实现增量覆盖 hive<<EOF set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; insert overwrite table crawler.test partition (dt) select a.id, a.name, a.email, a.create_time, a.create_time as dt from ( select id, name, email, create_time from crawler.test_temp union all select t.id, t.name, t.email, t.create_time from crawler.test t left outer join crawler.test_temp t1 on t.id = t1.id where t1.id is null ) a; quit; EOF if [ $? -eq 0 ]; then echo $sysdate $0 " 增量抽取完成!" else echo $sysdate $0 " 增量抽取失败!" fi
2、如何统计hive的日志数据
1、应用场景
集团搜索刚上线不久,日志量并不大 。这些日志分布在 5 台前端机,按小时保存,并以小时为周期定时将上一小时产生的数据同步到日志分析机,统计数据要求按小时更新。这些统计项,包括关键词搜索量 pv ,类别访问量,每秒访问量 tps 等等。 基于 hive ,我们将这些数据按天为单位建表,每天一个表,后台脚本根据时间戳将每小时同步过来的 5 台前端机的日志数据合并成一个日志文件,导入 hive 系统,每小时同步的日志数据被追加到当天数据表中,导入完成后,当天各项统计项将被重新计算并输出统计结果。 以上需求若直接基于 hadoop 开发,需要自行管理数据,针对多个统计需求开发不同的 map/reduce 运算任务,对合并、排序等多项操作进行定制,并检测任务运行状态,工作量并不小。但使用 hive ,从导入到分析、排序、去重、结果输出,这些操作都可以运用 hql 语句来解决,一条语句经过处理被解析成几个任务来运行,即使是关键词访问量增量这种需要同时访问多天数据的较为复杂的需求也能通过表关联这样的语句自动完成,节省了大量工作量。
2.实战
1、 分隔符问题 首先遇到的是日志数据的分隔符问题,我们的日志数据的大致格式如下: 2010-05-24 00:00:02@$$@QQ2010@$$@all@$$@NOKIA_1681C@$$@1@$$@10@$$@@$$@-1@$$@10@$$@application@$$@1 从格式可见其分隔符是“ @$$@ ”,这是为了尽可能防止日志正文出现与分隔符相同的字符而导致数据混淆。本来 hive支持在建表的时候指定自定义分隔符的,但经过多次测试发现只支持单个字符的自定义分隔符,像“ @$$@ ”这样的分隔符是不能被支持的,但是我们可以通过对分隔符的定制解决这个问题, hive 的内部分隔符是“ 01 ”,只要把分隔符替换成“