IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> hive使用改写with cube优化实例:运行时间180分钟-->30分钟 -> 正文阅读

[大数据]hive使用改写with cube优化实例:运行时间180分钟-->30分钟

背景

数据需求,要求计算各个维度下的用户数,并将数据落在目标表中,结果需要支持任意维度的筛选。

维度包括:平台(platform),是否新用户(is_new),年龄(age),人生阶段(life_stage),城市类型(city_class),省份名称(province_name),使用年限(use_age),当前APP版本(app_version_final),启动播放(start_play)。 启动播放维度涵盖:启动用户,播放用户,启动无播放用户,播放无启动用户。

数据举例:

platformis_newagelife_stagecity_classprovince_nameuse_ageapp_version_finalstart_playdevice_id
gphone0----19.12.6播放用户2
gphone019-24岁中学生C青海省109.12.6启动用户3
gphone036-40岁-A-广东省789.12.6播放用户6
iphone031-35岁-A-江苏省7269.12.6启动用户7
iphone031-35岁工作C江苏省1849.12.6启动用户8
iphone031-35岁工作D湖南省8499.12.6启动用户9
iphone00-18岁中学生A广东省-9.12.6播放用户10
iphone00-18岁中学生A广东省-9.12.6播放无启动用户10
iphone031-35岁工作A-辽宁省1999.7.0启动用户11
iphone031-35岁工作C湖北省4969.12.6启动用户12
gphone036-40岁工作D安徽省-9.12.0启动用户13
gphone0-----9.12.0启动用户14
gphone0-----9.12.0启动无播放用户14
gphone036-40岁-D黑龙江省219.12.6播放用户19
gphone0----49.12.6启动用户20
iphone025-30岁工作E贵州省10939.5.8播放用户1
iphone025-30岁工作E贵州省10939.5.8播放无启动用户1

分析需求之后,思考应该使用with cube语法,以实现支持任意维度的筛选,但是维度很多,使用with cube之后可能会出现数据量很大的情况,做测试后发现可以运行。

分析数据来源,base_data_tbl包含了除去start_play以外的所有数据,做一次join即可。

warning:除去启动播放这个维度,其他维度都是没有重叠的数据的,也就是一个用户不可能又属于新用户又不属于新用户,但是一个用户可能既是播放用户,也是播放无启动用户,所以加入这个维度之后,需要在with cube的聚合字段中加入distinct,才能保证数据的正确性
如下图标黄数据所示:
在这里插入图片描述

代码分析

首先按照我们最基础的思路写一下代码

WITH demo2 AS	--创建临时表demo2,处理start_play维度信息,为join做准备
(
        SELECT  device_id
               ,'有启动无播放' AS start_play
        FROM data_source_tbl
        WHERE vv is null
        AND start_num is not null  
        UNION ALL
        SELECT  device_id
               ,'有播放无启动' AS start_play
        FROM data_source_tbl
        WHERE vv is not null
        AND start_num is null  
        UNION ALL
        SELECT  device_id
               ,'启动用户' AS start_play
        FROM data_source_tbl
        WHERE (vv is null AND start_num is not null) or (vv is not null AND start_num is not null)  
        UNION ALL
        SELECT  device_id
               ,'播放用户' AS start_play
        FROM data_source_tbl
        WHERE (vv is not null AND start_num is null) or (vv is not null AND start_num is not null)  
    )




INSERT OVERWRITE TABLE 目标表 partition(dt='2021-07-24')
SELECT  nvl(A.platform,'ALL')          AS platform
       ,nvl(A.is_new,'ALL')            AS is_new
       ,nvl(A.age,'ALL')               AS age
       ,nvl(A.life_stage,'ALL')        AS life_stage
       ,nvl(A.city_class,'ALL')        AS city_class
       ,nvl(A.province_name,'ALL')     AS province_name
       ,nvl(A.use_age,'ALL')           AS use_age
       ,nvl(A.app_version_final,'ALL') AS app_version_final
       ,nvl(B.start_play,'ALL')        AS start_play
       ,COUNT(distinct A.device_id)    AS dau	-- 所有字段使用nvl是为了最终建表完成后做查询时候的清晰显示
FROM
(	-- 这个子查询是为了将除了start_play以外的数据进行去重,使用了group by所有字段的方法
    SELECT  nvl(A.platform,'-')          AS platform
           ,nvl(A.is_new,'-')            AS is_new
           ,nvl(A.age,'-')               AS age
           ,nvl(A.life_stage,'-')        AS life_stage
           ,nvl(A.city_class,'-')        AS city_class
           ,nvl(A.province_name,'-')     AS province_name
           ,nvl(A.use_age,'-')           AS use_age
           ,nvl(A.app_version_final,'-') AS app_version_final
           ,nvl(A.device_id,'-')         AS device_id
    FROM base_data_tbl A
    WHERE A.dt='2021-07-24'
    GROUP BY  platform  
             ,is_new
             ,age
             ,life_stage
             ,city_class
             ,province_name
             ,use_age
             ,app_version_final
             ,device_id
) A
LEFT JOIN demo2 B ON A.device_id = B.device_id
GROUP BY  platform
         ,is_new
         ,age
         ,life_stage
         ,city_class
         ,province_name
         ,use_age
         ,app_version_final
         ,start_play WITH cube

这段代码看上去没有问题,但是运行就会发现,在一个reduce阶段会卡在76%不动,查了一下原因,发现是一个reducer要处理过多地distinct数据了,处理速度很慢,我等了4个小时,代码都没跑完…

这时候我尝试更改配置项优化,不是一个reduce不行么,我配置成10个,发现还是慢,我最后配了40个,代码如下:

-- 在 Map 端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
-- 有数据倾斜的时候进行负载均衡(默认是 false)
set hive.groupby.skewindata = true;
-- 必须设置,否则无法开启这么大的grouping sets
SET hive.new.job.grouping.set.cardinality=1024;
-- 设置map和reduce的数量
set mapred.reduce.tasks=40;
set mapred.map.tasks= 9;  

其余代码不变,再次运行3个小时可以跑出结果,但是还是太慢了,想要刷数据的话一天才能刷几次,不太行

代码优化

下一步就需要进行代码层面的优化了,能否将distinct去掉?

最常见的使用group by代替distinct方法在当前场景下不能使用,因为是在做with cube聚合

那就把不写distinct可能出错的情景拿出来,然后过滤掉就可以了

这里详细解释一下:为什么当前结果不用distinct会有问题?因为start_play这个筛选维度一个用户可能对应多个元素,在我们进行join操作之后,可能有一个用户存在多行的可能,例如出现

868894031715839 1 NULL 2021-07-20 播放用户

868894031715839 2 NULL 2021-07-20 有播放无登录

这样两条数据,在进行with cube计算的时候,如果不进行处理,计算结果就会有误。

例如我在做platform维度和is_new维度的聚合,其他维度设置为nvl中的默认值ALL,如果不处理,start_play维度中的ALL就对应着很多重复数据,所以我们要将这种可能性进行过滤

我第一次尝试是不写with cube,直接手写所有可能,然后发现不太现实,因为可能性太多了,写两页都写不完。第二次尝试成功了,代码如下

use qube_pps;
--在 Map 端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
--有数据倾斜的时候进行负载均衡(默认是 false)
set hive.groupby.skewindata = true;
SET hive.new.job.grouping.set.cardinality=1024;


WITH demo2 AS
(
    -- 注意这里将ALL作为一个当前维度的标签,将所有用户设置为这个标签
    select device_id, 'ALL' as start_play
    from data_source_tbl

    union all
        SELECT  device_id
               ,'有启动无播放' AS start_play
        FROM data_source_tbl
        WHERE vv is null
        AND start_num is not null  
        UNION ALL
        SELECT  device_id
               ,'有播放无启动' AS start_play
        FROM data_source_tbl
        WHERE vv is not null
        AND start_num is null  
        UNION ALL
        SELECT  device_id
               ,'启动用户' AS start_play
        FROM data_source_tbl
        WHERE (vv is null AND start_num is not null) or (vv is not null AND start_num is not null)  
        UNION ALL
        SELECT  device_id
               ,'播放用户' AS start_play
        FROM data_source_tbl
        WHERE (vv is not null AND start_num is null) or (vv is not null AND start_num is not null)  
    )




INSERT OVERWRITE TABLE 目标表 partition(dt='2021-07-24')
select * from (
  SELECT  nvl(A.platform,'ALL')          AS platform
         ,nvl(A.is_new,'ALL')            AS is_new
         ,nvl(A.age,'ALL')               AS age
         ,nvl(A.life_stage,'ALL')        AS life_stage
         ,nvl(A.city_class,'ALL')        AS city_class
         ,nvl(A.province_name,'ALL')     AS province_name
         ,nvl(A.use_age,'ALL')           AS use_age
         ,nvl(A.app_version_final,'ALL') AS app_version_final
         ,nvl(A.start_play,'ERR')        AS start_play	-- 一遇到start_play为ERR的情况就过滤掉,为了不让数据不全,上面临时表中加上了ALL字段以保证最终结果的正确性
         ,COUNT(A.device_id)    AS dau
  FROM
  (
      SELECT  nvl(A.platform,'-')          AS platform
             ,nvl(A.is_new,'-')            AS is_new
             ,nvl(A.age,'-')               AS age
             ,nvl(A.life_stage,'-')        AS life_stage
             ,nvl(A.city_class,'-')        AS city_class
             ,nvl(A.province_name,'-')     AS province_name
             ,nvl(A.use_age,'-')           AS use_age
             ,nvl(A.app_version_final,'-') AS app_version_final
             ,nvl(A.device_id,'-')         AS device_id
             ,nvl(B.start_play,'-')        as start_play
      FROM base_data_tbl A
      left join demo2 B on B.device_id=A.device_id
      WHERE A.dt='2021-07-24'
  ) A
  GROUP BY  platform
           ,is_new
           ,age
           ,life_stage
           ,city_class
           ,province_name
           ,use_age
           ,app_version_final
           ,start_play 
  WITH cube
) t where start_play!='ERR'	-- 过滤操作

最终代码运行时间为20-40分钟,极大优化了效率。

总结

通过对with cube的深入理解,删去了distinct造成的性能瓶颈,分析问题产生的原因然后进行了性能优化

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:42:40  更:2021-07-31 16:43:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 15:29:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码