ODPS-SQL多维度交叉的优化方法探究

2023-11-16

一、背景

odps是阿里集团的大数据计算平台,odps-sql语法类似于hive。

最近做了一个***项目,需求中用到了大量的维度交叉,等到需求实现后却发现新的问题——cube的交叉维度太多了(最初有17个),而且指标的计算逻辑比较复杂,造成数据加工太慢了,举例1天的增量表大概8个小时,需求中还有自然月和30天时间粒度的,根本没法实现,因此投入大量时间做了优化,最终结果:11个维度,1天表的加工时间是30分钟,7日表1个小时,30天表3个小时。

二、两种SQL方式

实现聚合查询有两种方式,一种是使用LATERAL VIEW + explode 将数据按某个维度扩张,另一种是使用grouping sets、rollup、cube的用法。

1.LATERAL VIEW + explode方法

explode函数用于列转行,explode(array)会将array数组的值拆成多行数据,配合LATERAL VIEW方法可以将源数据按某个维度复制,其中一份保持原样,另一份的指定维度置为固定值(比如“总计”),这样再做group聚合时就可以得到聚合数据。使用本方法的优点是如果某个维度需要特殊处理,会比较方便;缺点就是代码比较冗余,而且执行效率不如grouping高。

使用本方法map输入数据可能会产生较多的小文件,可以通过调节参数来加速。

SELECT cont_type,sub_cont_type,
    media_type_name,media_name,show_type,sold_type,
    count(distinct case when is_new_cont = 1 then feed_id end) as cont_cnt_add,
    count(distinct case when is_new_cont = 1 then media_id end) as media_cnt_add,
    count(distinct feed_id) as cont_cnt_store,
    count(distinct media_id) as media_cnt_store
    FROM(
            SELECT cont_type,sub_cont_type,
              media_type_name,media_name,show_type,
              IF (mask IN ('0') ,'总计',sold_type) AS sold_type,
              is_new_cont,
              feed_id,
              media_id
          FROM (
                SELECT cont_type,sub_cont_type,
                    media_type_name,media_name,sold_type,
                    IF (mask IN ('0') ,'总计',show_type) AS show_type,
                    is_new_cont,
                    feed_id,
                    media_id
                FROM (
                    
                        SELECT cont_type,sub_cont_type,
                            IF (mask IN ('0') ,'总计',media_type_name) AS media_type_name,
                            IF (mask IN ('0', '1') ,'总计',media_name) AS media_name, 
                            show_type,sold_type,
                            is_new_cont,
                            feed_id,
                            media_id
                        FROM (
                                SELECT
                                      cont_type,
                                      sub_cont_type,
                                      coalesce(media_type_name,'其他') as media_type_name,
                                      coalesce(media_name,'其他') as media_name,
                                      coalesce(show_type,'其他') as show_type,
                                      coalesce(sold_type,'其他') as sold_type,
                                      case when feed_create_date = '${bizdate}' then 1 else 0 end as is_new_cont,
                                      feed_id,
                                      media_id
                                  FROM dwd_tpp_cont_gyjc_feed_content_df
                                  WHERE ds = '${bizdate}' 
                        ) a 
                        LATERAL VIEW EXPLODE(SPLIT('0,1,2',',')) z AS mask
                ) a 
                LATERAL VIEW EXPLODE(SPLIT('0,1',',')) z AS mask
          ) a 
          LATERAL VIEW EXPLODE(SPLIT('0,1',',')) z AS mask
    ) a 
    GROUP BY cont_type,sub_cont_type,
    media_type_name,media_name,show_type,sold_type

 

2.grouping方法

首先推荐一篇odps grouping技巧的文章,这篇文章介绍了odps中group聚合分析时常用的grouping sets、rollup、cube的用法,本文不再赘述 。https://blog.csdn.net/kangkangwanwan/article/details/109768648

SELECT feed_type
    ,IF(GROUPING(media_type_name)=0,media_type_name,'all') as media_type_name
    ,IF(GROUPING(media_name)=0,media_name,'all') as media_name
    ,IF(GROUPING(show_type)=0,show_type,'all') as show_type
    ,IF(GROUPING(sold_type)=0,sold_type,'all') as sold_type
    ,count(distinct case when is_new_cont = 1 then feed_id end) as cont_cnt_add
    ,count(distinct case when is_new_cont = 1 then media_id end) as media_cnt_add
    ,count(distinct feed_id) as cont_cnt_store
    ,count(distinct media_id) as media_cnt_store
FROM (
    SELECT
        feed_type,
        coalesce(media_type_name,'其他') as media_type_name,
        coalesce(media_name,'其他') as media_name,
        coalesce(show_type,'其他') as show_type,
        coalesce(sold_type,'其他') as sold_type,
        case when feed_create_date = '${bizdate}' then 1 else 0 end as is_new_cont,
        feed_id,
        media_id
    FROM dwd_tpp_cont_gyjc_feed_log_di
    WHERE ds = '${bizdate}' 
) a 
GROUP BY feed_type
    ,cube(show_type,sold_type)
    ,rollup(media_type_name,media_name)
;

三、优化方法

用过kylin的同学应该对cube优化有一些基本的思路,比如将维度分为不同的组,组内交叉,组间隔离;如果有必选维度,则必选维度不参与交叉;尽量多的使用层级维度等等。如果维度之间毫无关系并且需要全部交叉的话,最终n个维度组成的cube有2^n个组,也就是数据膨胀了2^n倍,本例中200万条记录的表膨胀之后会变成400亿条!优化刻不容缓。

1.减少维度

第一个就是减少维度,看起来是废话,但是这是最根本的解决办法,odps支持的cube最大是10个,再多的维度造成的数据膨胀就是灾难性的,任何技巧在100亿条记录的时候都毫无用途。我们分析需求发现有一些维度是不太重要的,那为了保证数据的正常产出就必须精简。

举个例子,我们的30天表从11个维度降到7个维度之后加工时间从3小时降到了40分钟,非常明显。

2.多用rollup

rollup用于层级维度的情况,举个例子就是省、市、区,3个维度如果用cube会产生8个组合,但是由于存在层级关系,其实只需要4个就足够了。

group by rollup(a,b,c)  =   group by GROUPING SETS ((a,b,c),(a,b),(a),()) 
cube和rollup支持混合使用,写出来就是group by cube(a,b),rollup(c,d),rollup(e,f,g),我在最初使用rollup时一直有个担心,就是rollup部分在cube之外,会造成交叉维度的不完整,即group by cube(a,b,rollup(c,d),rollup(e,f,g))会将rollup项也作为一个维度参与到分组中,其实由于rollup的那个空括号,这样的组合是重复的,以下是我的分析过程

----1----
group by cube(a,b),rollup(c,d),rollup(e,f,g)
等价于
group by cube(a,b), GROUPING SETS ((c,d),(c),()),GROUPING SETS ((e,f,g),(e,f),(e),())
等价于
group by GROUPING SETS (
    (a,b,c,d,e,f,g),(a,b,c,d,e,f),(a,b,c,d,e),(a,b,c,d),(a,b,c,e,f,g),(a,b,c,e,f),(a,b,c,e),(a,b,c),(a,b,e,f,g),(a,b,e,f),(a,b,e),(a,b),
    (a,c,d,e,f,g)  ,(a,c,d,e,f)  ,(a,c,d,e)  ,(a,c,d)  ,(a,c,e,f,g)  ,(a,c,e,f)  ,(a,c,e)  ,(a,c)  ,(a,e,f,g)  ,(a,e,f)  ,(a,e)  ,(a)  ,
    (b,c,d,e,f,g)  ,(b,c,d,e,f)  ,(b,c,d,e)  ,(b,c,d)  ,(b,c,e,f,g)  ,(b,c,e,f)  ,(b,c,e)  ,(b,c)  ,(b,e,f,g)  ,(b,e,f)  ,(b,e)  ,(b)  ,
    (c,d,e,f,g)    ,(c,d,e,f)    ,(c,d,e)    ,(c,d)    ,(c,e,f,g)    ,(c,e,f)    ,(c,e)    ,(c)    ,(e,f,g)    ,(e,f)    ,(e)    ,()
    )

----2----
group by cube(a,b,rollup(c,d),rollup(e,f,g) )
等价于
group by cube(a,b, GROUPING SETS ((c,d),(c),()),GROUPING SETS ((e,f,g),(e,f),(e),()) )
等价于
group by GROUPING SETS (
    (a,b,c,d,e,f,g),(a,b,c,d,e,f),(a,b,c,d,e),(a,b,c,d),(a,b,c,e,f,g),(a,b,c,e,f),(a,b,c,e),(a,b,c),(a,b,e,f,g),(a,b,e,f),(a,b,e),(a,b),
    (a,c,d,e,f,g)  ,(a,c,d,e,f)  ,(a,c,d,e)  ,(a,c,d)  ,(a,c,e,f,g)  ,(a,c,e,f)  ,(a,c,e)  ,(a,c)  ,(a,e,f,g)  ,(a,e,f)  ,(a,e)  ,(a)  ,
    (b,c,d,e,f,g)  ,(b,c,d,e,f)  ,(b,c,d,e)  ,(b,c,d)  ,(b,c,e,f,g)  ,(b,c,e,f)  ,(b,c,e)  ,(b,c)  ,(b,e,f,g)  ,(b,e,f)  ,(b,e)  ,(b)  ,
    (c,d,e,f,g)    ,(c,d,e,f)    ,(c,d,e)    ,(c,d)    ,(c,e,f,g)    ,(c,e,f)    ,(c,e)    ,(c)    ,(e,f,g)    ,(e,f)    ,(e)    ,()   ,

    (a,b,c,d)      ,(a,b,c)      ,(a,b)      ,        --重复
    (a,c,d)        ,(a,c)        ,(a)        ,
    (b,c,d)        ,(b,c)        ,(b)        ,
    (c,d)          ,(c)          ,()         ,

    (a,b,e,f,g)    ,(a,b,e,f)    ,(a,b,e)    ,(a,b)    ,        --重复
    (a,e,f,g)      ,(a,e,f)      ,(a,e)      ,(a)      ,
    (b,e,f,g)      ,(b,e,f)      ,(b,e)      ,(b)      ,
    (e,f,g)        ,(e,f)        ,(e)        ,()       ,

    (a,b)          ,        --重复
    (a)            ,
    (b)            ,
    ()
    )


由此可见,group by cube(a,b),rollup(c,d),rollup(e,f,g)和group by cube(a,b,rollup(c,d),rollup(e,f,g))是等价的。

3.减少维度的取值

维度尽量使用枚举值,这样使得数据的基数变小,组合之后的总数据量也会变小。

4.参数调节

odps-sql的任务是伏羲系统,job分解为task,最常见的task有map、reduce和join三种形式,调节参数也从这三方面入手

  • 如果发现map个数太少,每个map任务耗时太长,可能是输入数据都是小文件造成的,可以调小odps.sql.mapper.split.size值;
  • 如果发现reduce个数太少,可以调大odps.sql.reducer.instances参数;
  • 如果发现join个数太少,可以调大odps.sql.joiner.instances参数

注意:伏羲系统会自动调节参数,如果只是偶尔一次运行慢则不需要手动调节参数。

除此之外,还有一些小技巧,比如count(distinct)改为count(group by),会增加reduce个数,提高加工速度。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ODPS-SQL多维度交叉的优化方法探究 的相关文章

随机推荐

  • selenium官文文档阅读总结(day 3)

    1 关联型xpath的用法 driver find element By XPATH a text xxx ancestor 祖先元素的标签名 2 selenium等待 等待的作用 在系统运行的过程中 等待网页内容的加载显示 需要耗费的时间
  • 华为校招机试 - 工单调度策略(Java)

    题目描述 当小区通信设备上报警时 系统会自动生成待处理的工单 华为工单调度系统需要根据不同的策略 调度外线工程师 FME 上站修复工单对应的问题 根据与运营商签订的合同 不同严重程度的工单被处理并修复的时长要求不同 这个要求被修复的时长我们
  • 使用Go语言爬取网页并将其保存为图片

    要使用Go语言爬取网页并将其保存为图片 你可以使用Go的第三方库来实现 以下是一个使用chromedp库的示例代码 它使用Chrome浏览器的Headless模式来访问网页并截取屏幕截图 package main import contex
  • Mrtk 如何动态开启关闭网格渲染

    protected void Show IMixedRealityDataProviderAccess dataProviderAccess CoreServices SpatialAwarenessSystem as IMixedReal
  • Unity编辑器随机生成物体,更换场景之后物体丢失问题解决

    前言 obj GameObject PrefabUtility InstantiatePrefab configData bigMainScene 我在编辑器开发的时候实例化预制体到场景中之后 在跳转场景之后 然后在返回实例化过物体的场景会
  • 【Ansible自动化运维实战】使用Asible批量部署yum仓库

    Ansible自动化运维实战 使用Asible批量部署yum仓库 一 时间要求及目的 二 playbook内容 三 运行palybook 一 时间要求及目的 使用华为镜像源作为yum仓库批量分发达到所有受控端 二 playbook内容 ro
  • 【成电860考研】电子科技大学软件工程860考研专业课真题考频总结

    博主最近考研上岸啦 成电软件工程860专业课考了122 总分不高 这篇文章主要介绍专业课 我就不分享别的啦 博主考研的时候收集了几乎全网的资料 找到了几乎所有能找到的860资料进行汇总分析 得到了最后的真题考频 为了帮助学弟学妹们 博主决定
  • 4261. 孤独的照片

    数据范围为500 000 所以应该控制在O nlogn 或O n 我们发现要枚举的子串它其中有一个字母只出现一次 所以 我们可以去枚举只出现一次的字母是哪个 假设在第i个位置的字母为G 我们要枚举包含这个字母的 且只包含一个G的 且长度大于
  • QGroupBox布局中简单的操作

    QGroupBox中布局各个控件的使用 注意 我是先用了Qt designer设计 然后根据转成的 py文件代码 进行适当修改得到的 将进行三个示例讲解 目录 QGroupBox上添加栅格布局 某一组件充满整个QGroupBox QGrou
  • 抖音小程序实践三:接口开发指南

    通过官方文档可以更系统的学习到所有的接口 我这边罗列一下我自己用到测试过的接口供大家参考 前端 小程序对接官方文档 https microapp bytedance com docs zh CN mini app develop api o
  • RDMA技术详解——DMA和RDMA概念

    1 1 DMA DMA Direct Memory Access 直接内存访问 是一种能力 允许在计算机主板上的设备直接把数据发送到内存中去 数据搬运不需要CPU的参与 如下图所示 红线部分为传统内存访问 需要通过CPU进行数据copy来移
  • python导入数学函数_Python 数学函数模块(Math)

    1 内置的数学函数 min 和max 函数可用于查找可迭代的最小值或最大值 例如 x min 5 10 25 y max 5 10 25 print x print y abs 函数返回指定数字的绝对 正 值 例如 x abs 7 25 p
  • 微信小程序之 navigateTo

    navigateTo页面跳转传参 使用标签的方式跳转 变量需要 A页面
  • UE-从鼠标出进行射线检测

    第一种方式 Convert Mouse Location To World Space 将鼠标屏幕2D位置转换为场景空间3D位置和方向 将鼠标位置从2D转换成3D 第二种方式 Deprohiect Screen to World 将给定的2
  • 自动化驱动程序管理

    在部署操作系统时 每次都从下载和分发所需的驱动程序中实现真正的独立性可能是一场艰苦的战斗 特别是具有硬件多样化的环境 并且需要支持新的硬件类型时 借助 OS Deployer 可以对所有端点使用一个映像 无论品牌和型号如何 驱动程序将自动处
  • 数据结构与算法-队列

    定义 队列是ListInsert发生表尾 ListDelete发生在表头的线性表 主要操作 入队 出队 术语 表头 队头 表尾 队尾 插入 入队 删除 出队 特点 先入先出 FIFO 插入的位置是length 1 删除的位置的是1 一般读取
  • 【图像分割】基于形态学实现视网膜血管分割附matlab代码

    1 简介 目的 影像中血管的分割与特征提取 对疾病的早期诊断具有重要意义 针对很多视网膜血管提取算法分割精度不高的问题 提出了运用数学形态学中的高帽变换的方法对其进行检测 方法 首先 选取结构元素为 圆盘形 的形态学对图像进行高帽变换 经过
  • 期货开户抓住每一个波段利润

    个人认为 小资金帐户做趋势没太大意义 原因在于资金绝对值太小 1000万的帐户因其资金绝对值较大 所以30 的回报率就很可观 但10万的帐户即使做到100 资金回报也微不足道 大资金做趋势 小资金做波段这也成为了期货投机市场的普遍规律 如你
  • 【WIN_server_2008】实现【Web服务器】的安装与配置

    1 网络互通 一 WIN7 WIN 2008 WIN10菜单栏 编辑 虚拟机网络编辑器 VMnet1 如上篇文章设置 二 WIN7 WIN 2008 虚拟机设置 网络适配器 如下图配置 三 WIN7 WIN 2008 WIN10的IP 子网
  • ODPS-SQL多维度交叉的优化方法探究

    一 背景 odps是阿里集团的大数据计算平台 odps sql语法类似于hive 最近做了一个 项目 需求中用到了大量的维度交叉 等到需求实现后却发现新的问题 cube的交叉维度太多了 最初有17个 而且指标的计算逻辑比较复杂 造成数据加工