• 【Python大数据笔记_day09_hive函数和调优】


    hive函数

    函数分类标准[重点]

    原生分类标准:  内置函数 和 用户定义函数(UDF,UDAF,UDTF)
    ​
    分类标准扩大化:  本来,UDF 、UDAF、UDTF这3个标准是针对用户自定义函数分类的; 但是,现在可以将这个分类标准扩大到hive中所有的函数,包括内置函数和自定义函数;
    ​
    目前hive三大标准
    UDF:(User-Defined-Function)普通函数:  特点是一进一出(输入一行数据输出一行数据)        举例: split
    UDAF:(User-Defined Aggregation Function)聚合函数: 特点是多进一出(输入多行输出一行)   举例: count sum max  min  avg
    UDTF:(User-Defined Table-Generating Functions)表生成函数:  特点是一进多出(输入一行输出多行)   举例: explode
    ​
    查询所有hive函数名称:  show functions;
    查看某函数使用帮助文档: desc function [extended] 函数名;         注意: 加上extended关键字能查看详细信息示例
    
    1. -- 查看所有函数
    2. show functions;
    3. -- 分类标准扩大化
    4. -- UDF: 普通函数 特点: 一进一出 举例: split()
    5. -- 查看官方示例
    6. describe function extended split;
    7. -- 演示官方示例
    8. SELECT split('oneAtwoBthreeCfour', '[ABC]'); -- ["one","two","three","four"]
    9. -- UDAF: 聚合函数 特点: 多进一出 举例: sum() count() avg() max() min()
    10. -- 查看官方示例
    11. describe function extended count;
    12. /*
    13. count(*): 不忽略null值统计个数
    14. count(字段名): 忽略null值统计个数
    15. count(常量): 举例 : count(1) count(2) ...
    16. count(distinct 字段名): 忽略null值并且去重统计个数
    17. */
    18. -- UDTF: 表生成函数 特点: 一进多哦出 举例: explode()
    19. -- 查看官方示例
    20. describe function extended explode;
    21. /*
    22. 将数组a的元素分成多行,或将映射的元素分成多行和多列
    23. 数组: array[元素1,元素2,元素3...]   array(10,20,30)能够构造出数组[10,20,30]
    24. 映射: map{k1:v1,k2:v2...} map('a',10,'b',20,'c',30)构造出映射{'a':10,'b':20,'c':30}
    25. */
    26. -- 演示炸裂函数
    27. select explode(array(10,20,30));
    28. select explode(map('a',10,'b',20,'c',30));

    复杂类型函数

    hive复杂类型:   array  struct  map
    ​
    array类型: 又叫数组类型,存储同类型的单数据的集合
         取值: 字段名[索引]   注意: 索引从0开始
         获取长度的函数: size(字段名)       常用
         判断是否包含某个数据的函数: array_contains(字段名,某数据)   常用
         对数组进行排序的函数: sort_array(数组)
    ​
    struct类型: 又叫结构类型,可以存储不同类型单数据的集合
         取值: 字段名.子字段名n
        
    map类型: 又叫映射类型,存储键值对数据的映射(根据key找value)
        取值: 字段名[key]
        获取长度的函数: size(字段名)        常用       
        获取所有key的函数: map_keys()            常用 
        获取所有value的函数: map_values()        常用 
    
    1. -- 演示集合函数
    2. select array('binzi','666','888');
    3. select size(array('binzi','666','888'));
    4. select array_contains(array('binzi','666','888'),'binzi');
    5. select sort_array(array(3,1,5,2,4)); -- [1,2,3,4,5]
    6. select map('a',1,'b',2,'c',3);
    7. select size(map('a',1,'b',2,'c',3));
    8. select map_keys(map('a',1,'b',2,'c',3));-- ["a","b","c"]
    9. select map_values(map('a',1,'b',2,'c',3));-- [1,2,3]

    字符串函数

    字符串常见的函数:
    concat: 字符串紧凑拼接到一起生成新字符串
    concat_ws: 字符串用指定分隔符拼接到一起生成新字符串        常用 
    length: 获取字符串长度             常用 
    lower: 把字符串中的字母全部变成小写
    upper: 把字符串中的字母全部变成大写
    trim: 把字符串两端的空白去除         常用 
    ​
    拓展字符串函数
    substr: 截取字符串         常用 
    replace: 替换字符串        常用 
    regexp_replace: 正则替换字符串
    parse_url: 解析url(统一资源定位符)  组成: 协议/主机地址:端口号/资源路径?查询参数
    get_json_object: 获取json对象解析对应数据
    
    1. -- 1.字符串相关函数
    2. -- 演示字符串常见的函数
    3. -- concat: 字符串紧凑拼接到一起生成新字符串
    4. select concat('binzi', '666', '888'); -- 'binzi666888'
    5. -- concat_ws: 字符串用指定分隔符拼接到一起生成新字符串
    6. select concat_ws('-', 'binzi', '666', '888'); -- 'binzi-666-888'
    7. -- length: 获取字符串长度
    8. select length('binzi-666'); -- 9
    9. -- lower: 把字符串中的字母全部变成小写
    10. select lower('BINZI-666'); -- 'binzi-666'
    11. -- upper: 把字符串中的字母全部变成大写
    12. select upper('binzi-666'); -- 'BINZI-666'
    13. -- trim: 把字符串两端的空白去除
    14. select '   binzi 666 '; -- '   binzi 666   '
    15. select trim('   binzi 666 ');-- 'binzi 666'
    16. -- substr(字符串,开始索引,截取长度): 截取字符串,截取长度如果不写默认到结尾
    17. -- substring(字符串,开始索引,截取长度): 截取字符串
    18. -- 注意: 正索引从1开始正着数 负索引从-1开始倒着数
    19. select substr('binzi666',1,2); -- 'bi'
    20. select substr('binzi666',1); -- -- 'binzi666'
    21. select substr('binzi666',-4);--'i666'
    22. -- 已知'2023-05-21'要求分别截取年月日
    23. select substr('2023-05-21',1,4); -- 结果2023
    24. select substr('2023-05-21',1,7); -- 结果2023-05
    25. select substr('2023-05-21',6,2); -- 结果05
    26. select substr('2023-05-21',-2,2); -- 结果21
    27. -- current_date经常用于截取日期中的年月
    28. select `current_date`();
    29. select substr(`current_date`(),1,7);
    30. -- replace(大字符串,敏感词,替换后的内容):替换字符串
    31. select replace('你TMD哦','TMD','挺萌的');
    32. select replace('binzi-666', '666', 'num');
    33. --正则表达式替换函数:regexp_replace(str, regexp, rep)
    34. select regexp_replace('binzi-666', '\\d+', 'num');
    35. --正则表达式解析函数:regexp_extract(str, regexp, idx)
    36. -- 正则中()代表分组,自动从1开始生成编号,提取正则匹配到的指定组内容
    37. select regexp_extract('binzi-666-888', '(\\d+)-(\\d+)', 1);
    38. select regexp_extract('binzi-666-888', '(\\d+)-(\\d+)', 2);
    39. --URL解析函数:parse_url 注意要想一次解析出多个 可以使用parse_url_tuple这个UDTF函数
    40. -- URL: 统一资源定位符 也就是咱们常说的网址   组成: 协议/主机地址:端口号/资源路径?查询参数
    41. select parse_url('http://www.itcast.cn/path/binzi.html?user=binzi&pwd=123', 'HOST'); -- www.itcast.cn
    42. select parse_url('http://www.itcast.cn/path/binzi.html?user=binzi&pwd=123', 'PATH'); -- /path/binzi.html
    43. select parse_url('http://www.itcast.cn/path/binzi.html?user=binzi&pwd=123', 'QUERY'); -- user=binzi&pwd=123
    44. select parse_url('http://www.itcast.cn/path/binzi.html?user=binzi&pwd=123', 'QUERY', 'user'); -- binzi
    45. select parse_url('http://www.itcast.cn/path/binzi.html?user=binzi&pwd=123', 'QUERY', 'pwd'); -- 123
    46. -- json解析函数:get_json_object(json_txt, path), 细节: 整个json字符串用单引号'包裹, json字符串中的键, 值用双引号"包裹.
    47. -- json字符串的格式: {键:值, 键: 值}
    48. -- json数组的格式: [{键:值, 键: 值}, {键:值, 键: 值}, {键:值, 键: 值}]     -- 索引从 0 开始.
    49. select get_json_object('{"name":"杨过", "age":"18"}', '$.name');      -- 杨过, $表示json对象
    50. select get_json_object('[{"name":"杨过", "age":"18"}, {"name":"小龙女", "age":"26"}]', '$.[0]'); -- {"name":"杨过", "age":"18"}
    51. select get_json_object('[{"name":"杨过", "age":"18"}, {"name":"小龙女", "age":"26"}]', '$.[1].name'); -- 小龙女,   $表示json对象

    日期时间函数

    current_timestamp: 获取时间原点到现在的秒/毫秒,底层自动转换方便查看的日期格式        常用 
    to_date: 字符串格式时间戳转日期(年月日)
    current_date: 获取当前日期(年月日)        常用
    ​
    year: 获取指定日期时间中的年        常用 
    month:获取指定日期时间中的月        常用 
    day:获取指定日期时间中的日          常用 
    hour:获取指定日期时间中的时
    minute:获取指定日期时间中的分
    second:获取指定日期时间中的秒
    ​
    dayofmonth: 获取指定日期时间中的月中第几天
    dayofweek:获取指定日期时间中的周中第几天
    quarter:获取指定日期时间中的所属季度
    weekofyear:获取指定日期时间中的年中第几周
    ​
    datediff: 获取两个指定时间的差值        常用 
    date_add: 在指定日期时间上加几天        常用 
    date_sub: 在指定日期时间上减几天
    ​
    unix_timestamp: 获取unix时间戳(时间原点到现在的秒/毫秒)    注意: 可以使用yyyyMMdd HH:mm:ss进行格式化转换
    from_unixtime:  把unix时间戳转换为日期格式的时间          注意: 如果传入的参数是0,获取的是时间原点1970-01-01 00:00:00
    
    1. -- 2.日期时间函数
    2. -- 获取当前时间戳(时间原点到现在的秒/毫秒)
    3. select unix_timestamp(); -- 10位的数字代表多少秒
    4. select current_timestamp(); -- 自动转换 年月日时分秒格式
    5. -- 获取当前日期
    6. select current_date();
    7. -- 字符串格式时间戳转日期
    8. select to_date('2023-05-21 11:19:31.222000000');
    9. select to_date(current_timestamp());
    10. -- 依次获取年月日时分秒
    11. select year('2023-05-21 11:19:31.222000000'); -- 2023
    12. select month('2023-05-21 11:19:31.222000000'); -- 5
    13. select day('2023-05-21 11:19:31.222000000'); -- 21
    14. select hour('2023-05-21 11:19:31.222000000'); -- 11
    15. select minute('2023-05-21 11:19:31.222000000'); -- 19
    16. select second('2023-05-21 11:19:31.222000000'); -- 31
    17. -- 依次获取月中第几天,周中第几天,季度,年中第几周
    18. select dayofmonth('2023-05-21 11:19:31.222000000'); -- 21
    19. select dayofweek('2023-05-21 11:19:31.222000000'); -- 1
    20. select quarter('2023-05-21 11:19:31.222000000'); -- 2
    21. select weekofyear('2023-05-21 11:19:31.222000000'); -- 20
    22. -- 计算时间差
    23. select datediff(`current_date`(),'2023-11-03'); -- 12
    24. -- 获取明天的日期
    25. select date_add(current_timestamp(),1);
    26. select date_sub(current_timestamp(),-1);
    27. -- 获取昨天的日期
    28. select date_sub(current_timestamp(),1);
    29. select date_add(current_timestamp(),-1);
    30. -- 拓展
    31. --获取当前UNIX时间戳函数: unix_timestamp
    32. select unix_timestamp();
    33. --字符串日期转UNIX时间戳函数: unix_timestamp
    34. select unix_timestamp("2023-5-21 11:38:56"); -- 1684669136
    35. --指定格式日期转UNIX时间戳函数: unix_timestamp
    36. select unix_timestamp('2023-05-21 11:38:56','yyyy-MM-dd HH:mm:ss'); --1684669136
    37. --UNIX时间戳转日期函数: from_unixtime
    38. select from_unixtime(1684669136); -- 2023-05-21 11:38:56
    39. -- 获取时间原点日期
    40. select from_unixtime(0); -- 1970-01-01 00:00:00

    数学函数

    round: 指定小数保留位数    常用
    rand: 生成0-1的随机数
    pi: 生成π结果
    ceil: 向上取整
    floor: 向下取整
    1. -- 演示数学函数
    2. -- 随机数
    3. select rand();
    4. -- 应用解决数据倾斜问题,可以把之前大量相同的值后面拼接随机数
    5. select concat('男',rand());
    6. select concat('男',rand());
    7. -- 获取π值
    8. select '3.1415926';
    9. select pi();
    10. -- 四舍五入设置保留位数
    11. select round(pi(),4);
    12. -- 向上取整
    13. select ceil(pi());
    14. -- 向下取整
    15. select floor(pi());

    条件函数[练习]

    if(参数1,参数2,参数3): 如果参数1结果为true,就执行参数2内容,否则执行参数3的内容
    case...when.then...end: 条件判断类似于编程语言中的if..else if ...else...     常用
    ​
    ​
    isnull(数据) : 为空null: true 不为空:false
    ​
    isnotnull(数据): 不为空: true 为空null:false
    ​
    nvl(数据,参数2): 如果数据不为空打印数据,为空null打印第二个参数        常用 
    ​
    coalesce(参数1,参数2...): 从左到右依次查找,返回第一个不是null的值,如果找到最后都是null,就返回null    常用
    
    1. -- 演示条件函数
    2. -- if(条件判断,true的时候执行此处,false的时候执行此处)
    3. select if(10 > 5, '真', '假'); -- 真
    4. select if(10 < 5, '真', '假');
    5. --条件转换函数格式1: CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
    6. select
    7.       case 7
    8.           when 1 then '周一上班'
    9.           when 2 then '周二上班'
    10.           when 3 then '周三上班'
    11.           when 4 then '周四上班'
    12.           when 5 then '周五上班'
    13.           when 6 then '周六休息'
    14.           when 7 then '周日休息'
    15.           else '老弟啊,你是外星人吗?'
    16.       end;
    17. -- 条件转换函数格式2:CASE WHEN a==b THEN a==c [WHEN a==d THEN a==e]* [ELSE f] END
    18. select
    19.       case
    20.           when 7==1 then '周一上班'
    21.           when 7==2 then '周二上班'
    22.           when 7==3 then '周三上班'
    23.           when 7==4 then '周四上班'
    24.           when 7==5 then '周五上班'
    25.           when 7==6 then '周六休息'
    26.           when 7==7 then '周日休息'
    27.           else '老弟啊,你是外星人吗?'
    28.       end;
    29. -- 演示null相关函数
    30. -- isnull(数据) 为空: true 不为空:false
    31. select isnull(null); -- true
    32. -- isnotnull(数据) 不为空: true 为空:false
    33. select isnotnull('斌子'); -- true
    34. -- nvl(数据,前面的数据是null的时候执行此处): 如果数据不为空打印数据,为空打印第二个参数
    35. select nvl('binzi','666');
    36. select nvl(null,'666');
    37. -- coalesce(v1,v2...): 从左到右依次查找,返回第一个不是null的值,如果找到最后都是null,就返回null
    38. select COALESCE(null,11,22,33);-- 11
    39. select COALESCE(null,null,22,33);--22
    40. select COALESCE(null,null,null,33);--33
    41. select COALESCE(null,null,null,0);--0
    42. select COALESCE(null,null,null,null);--null

    类型转换函数

    类型转换: cast(数据 as 要转换的类型)        常用 
    1. -- 演示类型转换函数
    2. -- cast: 主要用于类型转换 注意: 转换失败返回null
    3. select cast(3.14 as int); -- 3
    4. select cast(3.14 as string) ; -- '3.14'
    5. select cast('3.14' as float); -- 3.14
    6. select cast('3.14' as int); -- 3
    7. select cast('binzi' as int); -- null
    8. -- -- 注意: 很多时候底层都默认做了自动转换
    9. select '3'+3; -- 6
    10. -- 实际应用场景:concat_ws要求被连接的必须是字符串,如果直接用666就报错
    11. select concat_ws('_','binzi',666,'888'); --此行报错,因为concat_ws只能拼接字符串类型
    12. select concat_ws('_','binzi',cast(666 as string),'888'); -- binzi_666_888

    数据脱敏函数

    1. -- 演示数据脱敏函数[了解]
    2. -- mask_hash: 返回指定字符串的hash编码
    3. select mask_hash('binzi');
    4. -- 拓展
    5. --将查询回的数据,大写字母转换为X,小写字母转换为x,数字转换为n。
    6. select mask("abc123DEF"); -- xxxnnnXXX
    7. --自定义替换的字母: 依次为大写小写数字
    8. select mask("abc123DEF",'大','小','数');
    9. select mask("abc123DEF",'/','.','%');
    10. --mask_first_n(string str[, int n]
    11. --对前n个进行脱敏替换 大写字母转换为X,小写字母转换为x,数字转换为n。
    12. select mask_first_n("abc123DEF",6);
    13. --mask_last_n(string str[, int n])
    14. --对后n个进行脱敏替换 大写字母转换为X,小写字母转换为x,数字转换为n。
    15. select mask_last_n("abc123DEF",6);
    16. --mask_show_first_n(string str[, int n])
    17. --除了前n个字符,其余进行掩码处理
    18. select mask_show_first_n("abc123DEF",6);
    19. --mask_show_last_n(string str[, int n])
    20. select mask_show_last_n("abc123DEF",6);

    其他函数

    1. -- 演示其他函数
    2. --取哈希值函数:hash
    3. select hash("binzi"); -- 93742710
    4. --MD5加密: md5(string/binary)
    5. select md5("binzi"); -- 32位   072853027b387fcf891a610137f8dc1b
    6. select length('072853027b387fcf891a610137f8dc1b');
    7. --SHA-1加密: sha1(string/binary)
    8. select sha1("binzi"); -- 40位 66368c80ca9125f9a8a945aaf1e1ec3f8b21f7f9
    9. select length('66368c80ca9125f9a8a945aaf1e1ec3f8b21f7f9');
    10. --SHA-2家族算法加密:sha2(string/binary, int) (SHA-224, SHA-256, SHA-384, SHA-512)
    11. select sha2("binzi",224);
    12. select sha2("binzi",512);
    13. --crc32加密:
    14. select crc32("binzi"); -- 3221865747
    15. -- 当前环境相关的
    16. select current_user(),logged_in_user(),current_database(),version();

    炸裂函数实战[练习]

    把一个容器的多个数据炸裂出单独展示:  explode(容器)
    ​
    炸裂函数配合侧视图使用如下
    格式:select 原表别名.字段名,侧视图名.字段名 from 原表 原表别名 lateral view explode(要炸开的字段) 侧视图名 as 字段名 ;
    
    1. -- UDTF: 一进多出
    2. select explode(array('binzi', '666', '888'));
    3. select explode(map('a', 1, 'b', 2, 'c', 3));

    实战

    1. -- 将NBA总冠军球队数据使用explode进行拆分,并且根据夺冠年份进行倒序排序。
    2. --step1:建表
    3. create table the_nba_championship(
    4.           team_name string,
    5.           champion_year array<string>
    6. ) row format delimited
    7. fields terminated by ','
    8. collection items terminated by '|';
    9. --step2:加载数据文件到表中 先上传到hdfs/source目录
    10. load data inpath '/source/The_NBA_Championship.txt' into table the_nba_championship;
    11. --step3:验证
    12. select * from the_nba_championship;
    13. -- 只查询冠军年份,降序排序
    14. select explode(champion_year) as year from the_nba_championship ;
    15. -- 配合侧视图完成需求
    16. with tmp as(
    17.    select a.team_name,b.year
    18.    from the_nba_championship a
    19.   lateral view explode(champion_year) b as year
    20.   )
    21. select * from tmp order by year desc;

    堆内存错误

    报错

    Error while processing statement: FAILED: Execution Error, return code -101 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. Java heap space

    解决方案:

    方式1: 找到hive-env.sh,添加以下内容

        export HADOOP_HEAPSIZE=2048

    方式2: 找到hive-site.xml添加以下内容

    1. <!-- hive堆内存-->
    2. <property>
    3.       <name>hive.heapsize</name>
    4.       <value>2048</value>
    5.   </property>

    高频面试题[练习]

    行转列

    collect_set(字段名): 把多个数据收集到一起,默认去重
    collect_list(字段名): 把多个数据收集到一起,默认不去重
    把多个子串用指定分隔符拼接成一个大字符串: concat_ws(分隔符,多个数据...)      注意: 如果拼接数据不是字符串可以使用cast转换
    示例:
    1. -- 数据准备
    2. --建表
    3. create table row2col2(
    4.                         col1 string,
    5.                         col2 string,
    6.                         col3 int
    7. )row format delimited fields terminated by '\t';
    8. --加载数据到表中
    9. load data inpath '/source/r2c2.txt' into table row2col2;
    10. -- 验证数据
    11. select * from row2col2;
    12. /*
    13. 需求1: 把原表数据变成以下格式
    14. a b [1,2,3]
    15. c d [4,5,6]
    16. */
    17. select
    18.   col1,
    19.   col2,
    20.   collect_list(col3)
    21. from
    22.   row2col2
    23. group by
    24.   col1, col2;
    25. /*
    26. 需求2: 把原表数据变成以下格式
    27. a b '1-2-3'
    28. c d '4-5-6'
    29. */
    30. select
    31.   col1,
    32.   col2,
    33.   concat_ws('-',collect_list(cast(col3 as string)))
    34. from
    35.   row2col2
    36. group by
    37.   col1, col2;

    列转行

    知识点
    把字符串按照指定分隔符切割: split(字符串,分隔符)
    ​
    炸裂函数配合侧视图使用格式: select 原表别名.字段名,侧视图名.字段名 from 原表 原表别名 lateral view explode(要炸开的字段) 侧视图名 as 字段名 ;
    需求

    示例
    1. -- 列转行
    2. --创建表
    3. create table col2row2(
    4.                         col1 string,
    5.                         col2 string,
    6.                         col3 string
    7. )row format delimited fields terminated by '\t';
    8. --加载数据
    9. load data inpath '/source/c2r2.txt' into table col2row2;
    10. -- 验证数据
    11. select * from col2row2;
    12. -- 单列数据先切割再炸开
    13. select split(col3,',') from col2row2;
    14. select explode(split(col3,',')) from col2row2;
    15. -- 再去完成需求,列转行生成最后完整表
    16. select col1,col2,tmp.col3
    17. from col2row2
    18. lateral view explode(split(col3,',')) tmp as col3;

    JSON文件处理

    get_json_object: 获取json对象解析对应数据  一次只能提取一个字段
    ​
    json_tuple: 直接获取json对应数据  这是一个UDTF函数 可以一次解析提取多个字段
    ​
    注意: 因为json_tuple是UDTF函数,所以也可以配合侧视图使用
    
    1. -- 演示json解析
    2. -- 需求: 把json解析后的数据保存成一个新表
    3. --创建表
    4. create table tb_json_test1 (
    5.   json string
    6. );
    7. --加载数据
    8. load data inpath '/source/device.json' into table tb_json_test1;
    9. -- 查看数据
    10. select * from tb_json_test1;
    11. -- 方式1: 逐个(字段)处理, get_json_object UDF函数 最大弊端是一次只能解析提取一个字段
    12. -- get_json_object UDF函数 最大弊端是一次只能解析提取一个字段
    13. create table device1 as
    14. select
    15.    --获取设备名称
    16.   get_json_object(json,"$.device") as device,
    17.    --获取设备类型
    18.   get_json_object(json,"$.deviceType") as deviceType,
    19.    --获取设备信号强度
    20.   get_json_object(json,"$.signal") as signal,
    21.    --获取时间
    22.   get_json_object(json,"$.time") as stime
    23. from tb_json_test1;
    24. -- 方式2: 逐条处理. json_tuple 这是一个UDTF函数 可以一次解析提取多个字段
    25. --json_tuple 这是一个UDTF函数 可以一次解析提取多个字段
    26. --单独使用 解析所有字段
    27. create table device2 as
    28. select
    29.   json_tuple(json,"device","deviceType","signal","time") as (device,deviceType,signal,stime)
    30. from tb_json_test1;
    31. --搭配侧视图使用(本次了解)
    32. select
    33.   device,deviceType,signal,stime
    34. from tb_json_test1
    35.         lateral view json_tuple(json,"device","deviceType","signal","time") b
    36.         as device,deviceType,signal,stime;
    37. -- 方式3: 在建表时候, 直接处理json, row format SerDe '能处理Json的SerDe类'
    38. --建表的时候直接使用JsonSerDe解析
    39. create table tb_json_test2 (
    40.                               device string,
    41.                               deviceType string,
    42.                               signal double,
    43.                               `time` string
    44. )ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe' STORED AS TEXTFILE;
    45. -- 加载数据
    46. load data inpath '/source/device.json' into table tb_json_test2;
    47. -- 查看
    48. select * from tb_json_test2;

    开窗函数

    基础使用[回顾]

    基础知识点[重点]

    开窗函数格式:  select ... 开窗函数 over(partition by 分组字段名 order by 排序字段名 asc|desc) ... from 表名;
    ​
    聚合开窗函数: 原来学的聚合函数(max,min,sum,count,avg)配合over()使用的时候,这些聚合函数也可以叫开窗函数
    ​
    排序开窗函数: row_number  dense_rank  rank
                row_number: 巧记: 1234   特点: 唯一且连续
                dense_rank: 巧记: 1223   特点: 并列且连续
                   rank   : 巧记: 1224   特点: 并列不连续
    1. -- 开窗函数: hive和mysql8都能使用
    2. -- 开窗函数本质在表后新增了一列
    3. -- 聚合开窗函数: max min sum avg count
    4. -- 聚合函数配合over()使用,也可以叫开窗函数
    5. select col1,
    6.       max(col3) over()
    7. from row2col2;
    8. -- 排序开窗函数: row_number rank dense_rank
    9. -- 排序函数必须配合over(order by 排序字段 asc|desc)
    10. /*
    11. row_number: 巧记: 1234   特点: 唯一且连续
    12. dense_rank: 巧记: 1223   特点: 并列且连续
    13.   rank   : 巧记: 1224   特点: 并列不连续
    14. */
    15. select *,
    16.       row_number() over (order by signal desc),
    17.       dense_rank() over (order by signal desc),
    18.       rank() over (order by signal desc)
    19. from device1;
    20. -- 开窗函数分组
    21. -- 注意不能用group by ,需要使用partition by,可以理解成partition by是group by的子句
    22. -- 演示排序函数和分组配合使用: 先分组再组内排序
    23. select *,
    24.       row_number() over (partition by deviceType order by signal desc),
    25.       dense_rank() over (partition by deviceType order by signal desc),
    26.       rank() over (partition by deviceType order by signal desc)
    27. from device1;
    28. -- 演示聚合函数和分组配合使用
    29. select *,
    30.       max(signal) over(partition by deviceType)
    31. from device1;
    32. -- 演示聚合函数同时和分组以及排序关键字配合使用
    33. --需求:求出每个用户截止到当天,累积的总pv数
    34. ---建表并且加载数据
    35. create table website_pv_info(
    36.   cookieid string,
    37.   createtime string,   --day
    38.   pv int
    39. ) row format delimited
    40. fields terminated by ',';
    41. -- 建表
    42. create table website_url_info (
    43.   cookieid string,
    44.   createtime string,  --访问时间
    45.   url string       --访问页面
    46. ) row format delimited
    47. fields terminated by ',';
    48. -- 加载数据 直接上传website_pv_info.txt和website_url_info.txt到hdfs中指定表路径中
    49. -- 查询数据
    50. select * from website_pv_info;
    51. select * from website_url_info;
    52. --需求:求出每个用户截止到当天,累积的总pv数
    53. --sum(...) over( partition by... order by ... ),在每个分组内,连续累积求和
    54. select cookieid, createtime, pv,
    55.       sum(pv) over(partition by cookieid order by createtime) as current_total_pv
    56. from website_pv_info;

    开窗函数控制范围

    开窗函数控制范围: rows between
                        - unbounded: 无界限
                        - x preceding:往前x行
                        - x following:往后x行
                        - current row:当前行
           
                        - unbounded preceding :表示从前面的起点  第一行
                        - unbounded following :表示到后面的终点  最后一行         
    1. -- 演示窗口范围的控制
    2. /*
    3. rows between
    4. - preceding:往前
    5. - following:往后
    6. - current row:当前行
    7. - unbounded:起点
    8. - unbounded preceding 表示从前面的起点 第一行
    9. - unbounded following:表示到后面的终点 最后一行
    10. */
    11. --默认从第一行到当前行
    12. select cookieid,createtime,pv,
    13.       sum(pv) over(partition by cookieid order by createtime) as pv1
    14. from website_pv_info;
    15. --第一行到当前行 等效于rows between不写 默认就是第一行到当前行
    16. select cookieid,createtime,pv,
    17.       sum(pv) over(partition by cookieid order by createtime rows between unbounded preceding and current row) as pv2
    18. from website_pv_info;
    19. --向前3行至当前行
    20. select cookieid,createtime,pv,
    21.       sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and current row) as pv4
    22. from website_pv_info;
    23. --向前3行 向后1行
    24. select cookieid,createtime,pv,
    25.       sum(pv) over(partition by cookieid order by createtime rows between 3 preceding and 1 following) as pv5
    26. from website_pv_info;
    27. --当前行至最后一行
    28. select cookieid,createtime,pv,
    29.       sum(pv) over(partition by cookieid order by createtime rows between current row and unbounded following) as pv6
    30. from website_pv_info;
    31. --第一行到最后一行 也就是分组内的所有行
    32. select cookieid,createtime,pv,
    33.       sum(pv) over(partition by cookieid order by createtime rows between unbounded preceding  and unbounded following) as pv6
    34. from website_pv_info;

    其他开窗函数

    其他开窗函数: ntile   lag和lead   first_value和last_value
    ​
    ntile(x)功能: 将分组排序之后的数据分成指定的x个部分(x个桶)   
            注意ntile规则:尽量平均分配 ,优先满足最小(编号1)的桶,彼此最多不相差1个。
    ​
    lag: 用于统计窗口内往上第n行值
    lead:用于统计窗口内往下第n行值
    ​
    first_value: 取分组内排序后,截止到当前行,第一个值
    last_value : 取分组内排序后,截止到当前行,最后一个值
    ​
    注意: 窗口函数结果都是单独生成一列存储对应数据
    1. -- 演示其他函数
    2. -- 演示ntile
    3. --把每个分组内的数据分为3桶
    4. SELECT
    5.   cookieid,
    6.   createtime,
    7.   pv,
    8.   ntile(3) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn2
    9. FROM website_pv_info
    10. ORDER BY cookieid,createtime;
    11. --需求:统计每个用户pv数最多的前3分之1天。
    12. --理解:将数据根据cookieid分 根据pv倒序排序 排序之后分为3个部分 取第一部分
    13. SELECT * from
    14. (SELECT
    15.     cookieid,
    16.     createtime,
    17.     pv,
    18.     NTILE(3) OVER(PARTITION BY cookieid ORDER BY pv DESC) AS rn
    19. FROM website_pv_info) tmp where rn =1;
    20. --lag 用于统计窗口内往上第n行值
    21. select cookieid, createtime, url,
    22.   row_number() over (partition by cookieid order by createtime) rn,
    23.   lag(createtime, 1) over (partition by cookieid order by createtime) la1,
    24.   lag(createtime, 2, '2000-01-01 00:00:00') over (partition by cookieid order by createtime) la2
    25. from website_url_info;
    26. --lead 用于统计窗口内往下第n行值
    27. select cookieid, createtime, url,
    28.   row_number() over (partition by cookieid order by createtime) rn,
    29.   lead(createtime, 1) over (partition by cookieid order by createtime) la1,
    30.   lead(createtime, 2, '2000-01-01 00:00:00') over (partition by cookieid order by createtime) la2
    31. from website_url_info;
    32. --FIRST_VALUE 取分组内排序后,截止到当前行,第一个值
    33. select cookieid, createtime, url,
    34.   row_number() over (partition by cookieid order by createtime) rn,
    35.   first_value(url) over (partition by cookieid order by createtime) fv
    36. from website_url_info;
    37. --LAST_VALUE 取分组内排序后,截止到当前行,最后一个值
    38. select cookieid, createtime, url,
    39.   row_number() over (partition by cookieid order by createtime) rn,
    40.   last_value(url) over (partition by cookieid order by createtime rows between unbounded preceding and unbounded following) fv
    41. from website_url_info;

    hive调优

    hive官方配置URL: Configuration Properties - Apache Hive - Apache Software Foundation

    hive命令个参数配置

    hive参数配置的意义:开发hive应用调优时,不可避免地需要设定hive的参数.设定hive的参数可以调优HQL代码的执行效率,或帮助定位问题.然而实践中经常遇到的一个问题,为什么我设定的参数没有起作用?这是对hive参数配置几种方式不了解导致的!

    hive参数设置范围 : 配置文件参数 >   命令行参数  >   set参数声明

    hive参数设置优先级: set参数声明  >   命令行参数   >  配置文件参数

    注意: 一般执行SQL需要指定的参数, 都是通过 set参数声明 方式进行配置,因为它属于当前会话的临时设置,断开后就失效了

     hive数据压缩

    hive底层是运行MapReduce,所以hive支持什么压缩格式本质上取决于MapReduce.

    压缩对比

    在后续可能会使用GZ(GZIP), 保证压缩后的数据更小, 同时压缩和解压的速度比较OK的,

    但是大部分的选择主要会选择另一种压缩方案, snappy, 此种方案可以保证在合理的压缩比下, 拥有更高的解压缩的速度

    snappy | A fast compressor/decompressor On a single core of a Core i7 processor in 64-bit mode, Snappy compresses at about 250 MB/sec or more and decompresses at about 500 MB/sec or more.

     

    开始压缩

     开启map输出阶段压缩可以减少job中map和Reduce task间数据传输量. 当Hive将输出写入到表中时,输出内容同样可以进行压缩。用户可以通过在查询语句或执行脚本中设置这个值为true,来开启输出结果压缩功能。

    1. -- 创建数据库
    2. create database hive05;
    3. -- 使用库
    4. use hive05;
    5. -- 开启压缩(map阶段或者reduce阶段)
    6. --开启hive支持中间结果的压缩方案
    7. set hive.exec.compress.intermediate; -- 查看默认
    8. set hive.exec.compress.intermediate=true ;
    9. --开启hive支持最终结果压缩
    10. set hive.exec.compress.output; -- 查看默认
    11. set hive.exec.compress.output=true;
    12. --开启MR的map端压缩操作
    13. set mapreduce.map.output.compress; -- 查看默认
    14. set mapreduce.map.output.compress=true;
    15. --设置mapper端压缩的方案
    16. set mapreduce.map.output.compress.codec; -- 查看默认
    17. set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
    18. -- 开启MR的reduce端的压缩方案
    19. set mapreduce.output.fileoutputformat.compress; -- 查看默认
    20. set mapreduce.output.fileoutputformat.compress=true;
    21. -- 设置reduce端压缩的方案
    22. set mapreduce.output.fileoutputformat.compress.codec; -- 查看默认
    23. set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;
    24. --设置reduce的压缩类型
    25. set mapreduce.output.fileoutputformat.compress.type; -- 查看默认
    26. set mapreduce.output.fileoutputformat.compress.type=BLOCK;

    hive数据存储

    行列存储原理

    行存储的特点: 查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。
    列存储的特点: 因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。

    行存储: textfile和squencefile
        优点: 每行数据连续存储              select * from 表名; 查询速度相对较快
        缺点: 每列类型不一致,空间利用率不高   select 列名 from 表名; 查询速度相对较慢
    列存储: orc和parquet
        优点: 每列数据连续存储         select 列名 from 表名;  查询速度相对较快
        缺点: 因为每行数据不是连续存储  select * from 表名;查询速度相对较慢
        
    注意: ORC文件格式的数据, 默认内置一种压缩算法:zlib , 在实际生产中一般会将ORC压缩算法替换为 snappy使用,格式为: STORED AS orc tblproperties ("orc.compress"="SNAPPY") 

    存储压缩比

    1. -- 存储格式应用对比
    2. -- 演示textfile行存储格式: 18.1 m
    3. create table log_text (
    4. track_time string,
    5. url string,
    6. session_id string,
    7. referer string,
    8. ip string,
    9. end_user_id string,
    10. city_id string
    11. )
    12. ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
    13. STORED AS TEXTFILE ; -- TEXTFILE当前默认的,可以省略
    14. -- 查询数据
    15. select * from log_text;
    16. -- 演示orc列存储(默认zlib): 2.78 m
    17. create table log_orc(
    18. track_time string,
    19. url string,
    20. session_id string,
    21. referer string,
    22. ip string,
    23. end_user_id string,
    24. city_id string
    25. )
    26. ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
    27. STORED AS orc ;-- 默认内置一种压缩算法:ZLIB
    28. -- 加载数据(先上传数据文件到根目录)
    29. insert into table log_orc select * from log_text;
    30. -- 查询数据
    31. select * from log_orc;
    32. -- [重点orc配合snappy]
    33. -- 演示orc列存储(指定snappy): 3.75 m
    34. create table log_orc_snappy(
    35. track_time string,
    36. url string,
    37. session_id string,
    38. referer string,
    39. ip string,
    40. end_user_id string,
    41. city_id string
    42. )
    43. ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
    44. STORED AS orc tblproperties ("orc.compress"="SNAPPY"); -- 配合SNAPPY压缩
    45. -- 加载数据(先上传数据文件到根目录)
    46. insert into table log_orc_snappy select * from log_text;
    47. -- 查询数据
    48. select * from log_orc_snappy;
    49. /*ORC文件格式的数据, 默认内置一种压缩算法:ZLIB , 在实际生产中一般会将ORC压缩算法替换为 snappy
    50. 格式为: STORED AS orc tblproperties ("orc.compress"="SNAPPY") */
    51. -- 演示parquet压缩存储:13.09 m
    52. create table log_parquet(
    53. track_time string,
    54. url string,
    55. session_id string,
    56. referer string,
    57. ip string,
    58. end_user_id string,
    59. city_id string
    60. )
    61. ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
    62. STORED AS PARQUET ;
    63. -- 加载数据(先上传数据文件到根目录)
    64. insert into table log_parquet select * from log_text;
    65. -- 查询数据
    66. select * from log_parquet;

     拓展dfs -du -h

    1. -- 查看hdfs文件大小除了去页面查看,还可以通过命令
    2. dfs -du -h '/user/hive/warehouse/hive05.db/log_text/log.data' ;
    3. dfs -du -h '/user/hive/warehouse/hive05.db/log_orc/000000_0' ;
    4. dfs -du -h '/user/hive/warehouse/hive05.db/log_orc_snappy/000000_0' ;
    5. dfs -du -h '/user/hive/warehouse/hive05.db/log_parquet/000000_0' ;

  • 相关阅读:
    pytorch环境安装和配置
    播放器缓存队列bug解决方案
    GO微服务实战第二十节 如何实现熔断机制?
    Linux_进程控制
    文盘 Rust -- tokio 绑定 cpu 实践
    vue3 + mark.js | 实现文字标注功能
    化工园区数字孪生可视化管控平台,赋予园区安全环保智慧发展
    阿赵UE引擎C++编程学习笔记——用户输入监听
    5.0、软件测试——边界值分析法
    Python R用法:深度探索与实用技巧
  • 原文地址:https://blog.csdn.net/qq_52442855/article/details/134430764