记要 (三)"/>
Hive基础知识记要 (三)
关于内置函数的核心使用策略:
1、查看有那些内置函数
show functions;
2、查看某个函数的具体使用手册desc function extended substring;3、编写测试用例select xxxx();
特殊的常用的内置函数:
substring instr concat split
length size array_contains
max min distinct avg sum count
explode
if nvl coalesce两大类型:
1、关于日期时间的
2、关于字符串的操作
内置函数的练习,学习使用的过程中:
内置函数:hive-1.x版本:216个hive-2.x版本:271个但是 不管定义多少个内置函数,肯定没法满足所有任意场景的使用面试常见的问题:你在工作当中,有定义过哪些自定义函数呢?1、内置函数有271个,我能定义一个和这271个中的某一个是实现相同功能的么?split concat ..... 2、内置函数可以嵌套使用xx1(xx2(xx3(), xx4()))show functions;
自定义: User Defined Function
UDAF: aggregate 聚合函数max min sum count distinct avg
UDTF: table 表格生成函数explode接收的参数:1、array 多行2、map 多行2列
通用的思维
责任链 设计模式原来写MR程序: 实现接口
class MyMapper implements org.apache.hadoop.mapreduce.mapred.Mapper<>从hadoop0-2.x版本开始不一样:
现在写MR程序: 继承实现类
class MyMapper extends org.apache.hadoop.mapreduce.Mapper<>setup 默认实现: // do nohting map 原来是抽象方法,现在是实现方法cleanup 默认run多增加了三个方法:setup cleanup run void run(Context context){setup(context)// context里面装包了一个对象:recordReaderwhile(context.nextKeyValue()){map(context.getCurrnetKey(), context.getCurrnetValue(), context)}cleanup(context)}知识:基本上,各种java技术组件都在这么进化原来都是:实现接口现在都是:利用继承Storm interface Spoutinterface Boltextends RichSpoutextends RichBolt@override 重写技术组件中的使用方式:
1、能尽量减轻用户的负担,就别让用户去写提供了一个接口,同时也提供一些实现类(默认使用组件,要么提前帮忙实现好一部分业务代码)2、先指定规范,然后提供一部分常见的实现,另外的比较特殊的实现,全部交给用户自己做hive的内置函数:1、提供了常见 271个内置函数2、提供了一个规范,可以让用户自己去写函数do(Animal a)class Male implements Sex
class Female implements Sexdo(Sex sex)class SS implements Sex创建临时函数
实现一些比较复杂的字段数据的处理
1、内置函数
2、自定义函数
UDF
UDAF
UDTF
如果会把数据存储到Hive,使用的方式:load / insert / hadoop fs -put
集群的运维,其他的开发,测试,DBA
如果让使用内置函数不能满足要求,去使用自定义函数,需要编写java代码
用户体验不好,适用性不好。
提供了一种技术:
函数的概念:我给你一堆数据,你给我一堆数据。
你给我把数据进行处理
内置函数
自定义函数
hive的使用者:
运维,测试,DBA
写shell python ruby等等的脚本
hive的SQL语句中,去调用运维写的脚本如何?
如果可以的话,那么hive的使用群体,扩宽了。
脚本:解释型的编程语言编写的代码
java class: 编译型的编程的语言
hive缇欧刚了一种技术:
transform
外带的脚本程序 shell python
需求:
统计每部电影被多少人看了。
{
“movie”: “2398”,
“rate”: “4”,
“timeStamp”: “978302281”,
“uid”: “1”
}
2398,4,978302281,1
数据存储在:
/hive1904/jsontest/rating.json
创建原始表:
create external table rate_json(line string) row format delimited location “/hive1904/jsontest/”;
创建解析结果出来的表:
create table rate(movie int, rate int, unixtime int, userid int) row format delimited fields terminated by ‘\t’;
解析语句:
insert into table rate
select
get_json_object(line, ‘ . m o v i e ′ ) a s m o v i e , g e t j s o n o b j e c t ( l i n e , ′ .movie') as movie, get_json_object(line, ' .movie′)asmovie,getjsonobject(line,′.rate’) as rate,
get_json_object(line, ‘ . t i m e S t a m p ′ ) a s u n i x t i m e , g e t j s o n o b j e c t ( l i n e , ′ .timeStamp') as unixtime, get_json_object(line, ' .timeStamp′)asunixtime,getjsonobject(line,′.uid’) as userid
from rate_json;
需求:
统计每部电影被多少人看了。
select movie, count(userid) as total from rate group by movie order by total desc limit 3;
set hive.exec.mode.local.auto=true;
get_json_object怎么使用
weekday_mapper.py:python文件的功能:
你给我一行数据:
输入
2398 4 978302281 1
这个脚本就处理成:
输出
2398 4 2 1
最后的实现:
创建表:lastjsontable
create table lastjsontable(movie int, rate int, weekday int, userid int) row format delimited fields terminated by ‘\t’;
create table rate(movie int, rate int, unixtime int, userid int) row format delimited fields terminated by ‘\t’;
解析数据:
insert into table lastjsontable
select transform(movie,rate,unixtime,userid)
using ‘python weekday_mapper.py’
as(movie,rate,weekday,userid)
from rate;
总结:
如果你编写SQL的过程中,遇到了一种情况:
需要结合函数来实现一些复杂的数据处理:
三种方式:
1、271个内置函数
2、提供了一种通用的模式:自定义函数
3、提供了一种技术:transform的方式来调用外部的一个处理脚本python weekday_mapper.pysh myweekday.sh
01||huangbo||19
02||xuzheng||20
03||wangbaoqiang||21
01_huangbo_19
02_xuzheng_20
03_wangbaoqiang_21
hive的官网直接告诉我们:分割符:是 char 不是 string
SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
由于默认的SerDe组件:序列化 和 反序列 组件
LazySimpleSerDe不支持使用多字节的分隔符
RegexSerDe 正则匹配
(.)_(.)_(.*)
IT技术界通用的三大技术:
json
jackson
fastjson
gson
正则
xmldom4jsax4j
create table mydata2(id string, name string)
row format serde ‘org.apache.hadoop.hive.serde2.RegexSerDe’
with serdeproperties(‘input.regex’=’(.)\|\|(.)’,‘output.format.string’=’%1 s s %2 ss’)
stored as textfile;
TextInputFormat里面有两个重要的方法:
逻辑切片
List getSplits(JobContext job);
获取RecordReader对象
public RecordReader<LongWritable, Text>
createRecordReader(InputSplit split, TaskAttemptContext context)nextKeyValue()getCurrnetKey()getCurrentValue()
hive shell
进入hive之后的
quit 退出客户端的
set key=value 在hive的客户端 进行设置参数
hive-default.xml
set hive.exec.mode.local.auto=true;
只对当前客户端生效 重新进入客户端 重新设置
set key 在hive的客户端查询参数对应的值
set hive.exec.mode.local.auto;
set -v 打印所有的hive的参数
add FILE [file] 添加文件到hive的classpath下的
add jar 添加jar hive的classpath 下的
list FILE 显示所有的文件
list jar|jars 显示所有的jar
! [cmd] 在hive的客户端执行linux的命令 查看 创建 但是切换不可以支持
dfs [dfs cmd] dfs -ls cat 在hive执行hadoop命令
hadoop fs - 旧
hdfs dfs - 新
hadoop|hdfs 启动hadoop|hdfs的客户端
fs|dfs 连接hadoop的文件系统
hive>
[query] hql 查询
source FILE 在hive客户端 加载sql脚本
shell 脚本 shell 命令组成的 条件判断 循环
sql脚本 一系列sql组成的
transform
hive中解析脚本
进入hive之前的
hive [-hiveconf x=y]* [<-i filename>]* [<-f filename>|<-e query-string>]
设置参数
1)hive -hiveconf key=value 一次只能允许设置一个参数
hive -hiveconf hive.exec.mode.local.auto=true
启动hive客户端的同事 设置参数
2)-i 文件 通过一个文件 初始化所有参数 可以一次性设置多个参数 init
启动hive的时候 通过文件 初始化多个参数
执行sql语句
-f file
hive -f /home/hadoop/tmp_data/my.sql
启动客户端
执行脚本 source
退出客户端
-e
hive -e sql 语句
hive -e “show databases;”
hive -e “select * from test_shell.stu”
先进入hive客户端 执行sql语句 退出客户端
hive的转换流程
explain sql 查看sql语句的执行计划
explain
select
dept,avg(age) avg_age
from stu
group by dept
order by avg_age desc limit 1;
stage1: group by + avg mapreduce
stage2: order
stage0:limit 1
Operator 操作符
hive本质 将hql语句转换为一个个的hql的操作符 操作符根据语句的关键词提取的 select ,group by,聚合函数,order by ,limit,having
Operator操作符:
1)mapreduce操作 group by
2)hdfs的读写操作 fetch Operator hdfs
hive的典型语句 如何转换mr的
1)group by +聚合函数
map端:
key: group by 的字段
value:需要聚合的字段
shuffle:
combiner
reduce端:
相同的一组的数据 分到一起
求聚合结果 sum|avg|max|min
默认 group by +聚合函数一起使用 有优化的
在map端执行combiner
2)order by 全局排序的
select * from stu order by age desc;
set numreducetasks=3;
part-r-00000 34—25
part-r-00001 24—18
part-r-00002 <18
map端:
key:-age
value: 其他字段
shufle:
定义分区
34—25 0
24—18 1
《18 2
reduce:
直接输出
sort by 局部排序的
set numreducetasks=3;
select * from stu sort by age desc;
map
key: -age
value:其他
shuffle:
默认分区
每一个分区 排序
reduce:直接输出
3)join
默认情况下 join过程 执行的 mapjoin | reduce join
在hive中 默认有一个表是小表时候 执行的mapjoin
小表判断依据:
小表大小: set hive.mapjoin.smalltable.filesize=25000000; 23.8M
在hive中 较小表不超过23.8M 都是执行的map join
mapjoin :
将一个小表 加载到缓存中 读取到内存中map
map端 map函数 读取另一个大表 进行关联
大小
reduce join :
将两表关联的 关联键 作为map输出的key 对输出的value打标记 标记数据来源
reduce端 接受所有关联键的两表数据 可以进行关联了
大大 数据倾斜
4)count(distinct …)
distinct 字段
select distinct dept from stu;
CS MA IS
map端:
key:dept 需要去重的字段
value:null
reduce端:
需要去重的字段 分到一组
key 默认的一组 第一个
values null null null
hive数据倾斜 *****
hive的数据倾斜 mr的数据倾斜 reducetask 数据倾斜
不容易产生数据倾斜的情况:
1)map join
2) sum|max|min + group by
有combiner
3)不转换为mr任务的
Operator MR|HDFS
fetch Operator
哪些操作不执行mr的:
hive.fetch.task.conversion
none : 这个参数禁用
所有的查询 都来执行mr
minimal:
0.10—0.13
SELECT *,
where 字段分区字段,
LIMIT
不执行mr的
more 默认
SELECT 原始字段,
FILTER where ,
LIMIT
容易产生数据倾斜的
1)reduce join
2)group by 不和聚合函数一起
3)count(distinct )
典型场景分析:
join 过程 reduce join
1)大量的关联键为null值的时候
users 用户表 UserId address 10G
logs 日志表 所有用户浏览网站的信息 UserId null
500G 250G
select * from users a join logs b on a.UserId=b.UserId;
map
key:
UserId
value: 标识+其他
shuffle:
分区 null 其他
排序
分组
reduce:
一个分区— reducetask
null 其他 — 1个reducetask中 260G
for(){
for(){
}}
9reducetask ---1个28G --- 250G
解决:
1)将null值分散到多个reducetask中
null+随机数
null123
null234
select
*
from users a join logs b on a.UserId=nvl(b.UserId,b.UserId+rand())
2)null 值不参与关联 最后将null值 拼接到最后 推荐
select
*
from users a join
(
select * from logs where UserId is not null
) b
on a.UserId=b.UserId
union
select "","","",* from logs where UserId is null;
2)关联键 类型不统一
users UserId int 133
logs UserId string 133 =null
select * from users a join logs b on a.UserId=b.UserId;
解决方案:
修改数据类型 将数据类型统一
select * from users a join logs b on a.UserId=trim(b.UserId);
3)大大
reduce join
key值分布不均匀 分区数据不均匀 数据倾斜
hive中的所有类型join方案
1.小小 mapjoin
2.大小(《23.8M ) mapjoin
3.大中(>23.8M 内存能够承受)
默认执行reduce join 数据倾斜的
为了效率 也为了解决数据倾斜 强制执行mapjoin
/+mapjoin(需要强制加载到内存中的小表)/
users 1G
logs 1T
select
/+mapjoin(a)/*
from users a join logs b on a.UserId=b.UserId;
4.大大 (这两个表 都无法放在内存的)
users 500G 用户表 每当有一个用户注册 一条数据
500000000用户
40w
logs 1T 日志表 每一个点击行为 一条数据 一天分析一次
40w
select * from users a join logs b on a.UserId=b.UserId;
解决方案:
对其中一个表 瘦身
对users 表进行瘦身 只需要过滤出来 logs表能够关联的userid
1)求logs表中有哪些useriD
SELECT distinct UserId from logs;
2)对users表进行瘦身
create table users_final as
select
/+mapjoin(a)/b.
from (
SELECT distinct UserId from logs
) a join users b on a.UserId=b.UserId;
users 最终需要的
3)进行真正的关联
select
/+mapjoin(a)/*
from users_final a join logs b on a.UserId=b.UserId;
分桶表 一般不用
更多推荐
Hive基础知识记要 (三)
发布评论