猫猫镇楼.jpg
本文档是为了记录数据仓库进驻某新业务帮忙建设业务数仓时,实践阿里建模方法论时,沉淀下来的切实可用的方法论细节(并不覆盖全部,只覆盖涉及的模块),我们的目标是内部这一套方法论实践成熟后,可以以该方法论作为模板来支撑新业务建设业务数仓。这里把一些通用的经验性笔记写出来,希望对同样对建模有苦恼的数仓同行们有帮助。
确定目标
接下业务建数仓的需求后,第一步就是搞清楚我们的目标是什么。这里的目标,不仅包括来自领导层的有明确口头传达或落文档的目标,如希望看到产品的周期性使用情况,各环节成本消耗,是否具有足够的用户粘性去开始大规模投放等等;也包括一些领导自己也可能不清楚或无意识,但我们需要在业务调研过程中了解的,比如关心业务当前的稳定性(未来迭代的频繁和范围),这决定了我们的模型是否在未来有被推到重来的风险;以及业务侧领导希望把建数仓的成本挂靠到哪里,人力成本如何算,决定了数仓建模团队的组织形式和我们中台数仓的介入方式(第二点提到的);还有对产出的紧急程度,这决定了我们是否需要倒排时间,以及是采用能快速迭代的增量式开发还是避免返工的一蹴而就式模型。虽然大部分领导对新项目的产出时间预期都是越快越好,但作为一名有经验的建模工作者很重要的一个责任就是,在完成目标的同时尽量避免给未来增加工作量(善战者无赫赫战功)。系统方案被评审的一项关键指标就是完成后该系统的人力维护成本,如果因扩展性做得不好导致未来迭代繁琐,长期上的(维护)人工成本大,那么就不是个好建模方案。虽然Kimball建模理念是每次都对当前最关键的业务过程做增量式迭代,是一种快速迭代而非一蹴而就的模型,但仍需要多花时间打磨,思考当前设计能否扩展新业务,未来的性能瓶颈等,尽力去把一切元素考虑周全,这也符合Kimabll书中说的,为维度属性耗费的精力越多,效果就越好。
基于上面介绍的,我们要在做事前想清楚两个目标,一个是我们需要支持的业务侧的业务目标(大数据的决策分析系统即为此献策),一个是大数据侧的目标,即我们希望实现的是什么,因业务侧在大数据方面可能并不了解,这个目标可能不是来自上层,而是我们要自己给自己制定的。本次XX项目的目标即为:
业务目标
以XX为抓手,培养用户的使用习惯,再推动用户接入XXX(主要营收来源)以产生收益,并逐步扩大生态,覆盖更多业务。
大数据的目标
帮助XX大数据团队产出第一版建模设计,让XX侧大数据研发能意识到维度建模理论的优势,让他们接受理论并培养他们到能由他们接手第2-3期建模设计;沉淀XX业务知识库,方便未来XX数据接入数仓或者未来参与业务侧开发;在XX业务落实建模理论并产生收益,让老板认可数仓的建模能力。
目标用户
此外还需要筛选出我们本次项目的核心用户,此处推荐我所在大数据部门老大的方法,用于区分核心用户和理解各团队目标:想象你在一艘大船上(公司/大部门),这艘大船的目的地(目标)是什么?这艘船内,各个部件的功能是什么,提供什么服务(各团队基于什么目标在做交互或者说提供服务)?你所在的组件的目标是什么?你在组件内,为了整体组件的目标,你被安排的目标是什么?应该是什么?将这些思考完后,就能对自己的责任,和自己所在部门的架构有更清晰的认识。
本次XX项目的目标用户:内部:看各种产品关键性能指标的老板们;外部:看XX大屏数据的用户。
组织形式
第二步就是定下参与到业务数仓建模的数仓人员的组织形式。在整体上,需要定下一个主R负责排期、划分工作和拍板做决定;在工作环节的具体执行上,则可以是要么明确指定某个人负责,要么田忌赛马式地两个人一同完成,再互相review以查缺补漏并得到从不同视角考虑的设计。当然,后者花费的时间更多,要视工期紧要程度来定。最后还有参与到业务数仓的形式,目前我们是以咨询顾问的形式BP到业务的,主要负责建模方案的设计以及教授建模方法,优点是避免了陷在代码落地的各种繁琐细节中,缺点是负责代码落地的业务侧数据研发不反馈,我们就无法获得各种设计时没法留意到的业务细节。因此要建立起在业务侧数据研发眼中的权威,让业务侧有问题时倾向于找我们解决和定夺,并建立定时review工作进度的同步机制(比如每周三固定周会同步各方工作),保证能常态化地维护业务知识库。
如何在业务侧数据研发中树立起权威?我认为有两个方法,一个是在业务调研后给出具体到每张表的足够详细且具有可行性的排期(这需要主R对业务情况的了解达到很高的程度),该排期不仅给业务侧研发信心,让他们相信按照这个排期的分工去落实,就可以在可预见地未来里见到项目的产出,也能给领导信心,让领导每周定时review排期的更新就能知道项目的进度(让领导不至于对重要项目缺少掌控感)。排期可以按照阶段性成果的产出时间去划分成几个里程碑(milestone),将注意力放在里程碑的产出的按时交付上(见下表1),当然详细的排期计划也是要给出的(参考下表2)。还有就是宣贯(培训)维度建模方法论,并提供业务设计以证明基于维度建模理论产出的大数据架构可以如何解决业务侧建模数仓的诸多问题,让业务侧能意识到维度建模理论的优势。
时间节点 | 交付 | 阶段性成果 |
---|---|---|
2021.11.01 - 2021.11.08 | 完成数据调研 | |
2021.11.09 - 2021.11.18 | 完成数仓规划 | 数仓规划完成一期设计 |
阶段 | 数据域 | 业务过程 | 层级 | 时间节点 | 研发投入 | 优先级 | 进度状态 | 交付说明 | 备注说明 | 人力安排 |
---|---|---|---|---|---|---|---|---|---|---|
数据调研 | xx域 | xxx | DWD | 2021.11.15 | 3人天 | P0 | 40% | 业务梳理与需求分析的文档产出 | 小红 |
数据调研
这里包括两个环节,业务调研和需求分析。
业务调研
最有效率的方法莫过于请相关的业务人员来介绍具体的业务,但是一般需要我们介入的新业务总是处于最繁忙的时候,或者可能存在业务团队和数仓团队不在一个地方的情况,因此得做好全靠自己摸索的准备。
前期了解业务可以通过两个抓手来获取关键信息,一个是组织架构,一个是业务过程。
梳理组织架构,即梳理出为本次项目服务的员工的所属组织,便于划分工作和边界,既可以梳理出上一节提到的核心用户,也能明晰我们的问题应该找哪些同事解决。要和经常沟通的同事混熟,方面后面交流。下图即为数据共享中心的组织架构图举例:
业务过程的梳理则可以有两种思路:
问题驱动式
基于3个问题去寻找相关资料并完善对整体业务流程的建模
- 此业务分别有哪些产品
- 产品分别产生什么数据?
- 数据是怎么产生的?数据在什么情况下会更新?
全流程闭环式
基于全部业务流程整体分析,把控对业务的理解
- 业务环节都有哪些?(这里包括不产生数据及线下环节,重点是要完整、全面,不仅包括核心流程,也包括核心流程中的物料的供给)
- 环节间的关系流转情况(不同环节怎么串联,环节所需要的材料如何供应)
- 每个环节有哪些人员参与,如何参与(环节中的人)
- 如何衡量环节中业务情况的好和坏(后续抽象到指标)
在业务调研环节,要求我们产出所有不可拆分的最细粒度的业务过程,但不是每个业务过程都将被使用,存在部分业务过程没数据落库或没数分关心,这时候是否有必要去赋予一个事实,并在后续的流程为此建事实表(如果建成则会是个无事实事实表)就成了个问题。对于此类问题,可以视分析需求决定是否要把此类事实隐藏,或者合并到其他事实,如果未来分析需求变化的话,再把需要的事实从合并的事实拆分出来。合并多个业务过程时,可以考察哪些业务过程触发了业务库产生/更新一条事务,满足条件则落事实。可以基于此把所有业务过程划分成若干个事实,把这些事实之前发生的不产生度量的业务过程,都归成该事实的中间状态或附属属性(同Kimball书中提到的有里程碑概念的周期性快照事实表)。此外,大部分不产生事务的业务过程的性能分析的需求,都可以使用埋点表来满足需求。
如图,在调研完业务过程后,我们可以产生一个直观描述业务流转的泳道图(图1),以及描述业务内各个实体间是否有关联的气泡图(图2)。
此外,还推荐在这一环节收集该业务下的词根及其含义,该工作可以被复用到后面的“数据标准”环节。
同时还推荐维护一个问题日志,在调研或设计中遇到的每个问题都会记录到问题日志里,缓存够一定数量时集中找对应研发请教一次。此处问的问题也要推敲,如何用最少的问题得到最多的信息。问题可以分为多个类别,业务问题,源系统数据问题,表设计问题,云云。
作图工具推荐:Process On, Drawio, EdrawMax(收费),Visio(Win端,收费)
需求分析
此处在Kimball方法论中即是通过和业务代表对接,理解业务目标,梳理关键性能指标,基于指标去反推还有哪些数仓需要的数据没有采集,哪些数据应该优先提供等等。在梳理指标含义及对应数据源时,不应该太过钻牛角尖(特别是当相当部分指标不需要马上兑现时),只要能梳理出90%以上的指标是就可以进入下一步了,因为存在一些指标是超前定义、未来可能取消或者更改口径的情况,且我们后面还有一个确定指标的流程,这一步做得太细就和下一步有重复性工作了,且因为做这一步时对业务的理解不一定有后面具体设计时细,可能当前的工作成果无法流转到后面去使用。所以,不要花太多的时间。
可以以此为表头,收集所有业务现有的关键性能指标,基于指标去理解业务和反推建模设计:
指标所属数据域 | 指标对应业务行为 | 指标汇总分层 | 衡量性能 | 指标名称 | 指标含义 | 指标类型(原子/派生/复合) | 度量/原子指标 | 数据源(表) | 数据源是否接入Hive |
---|---|---|---|---|---|---|---|---|---|
XX域 | XXX | 整体级 | 规模类 | / | / | 派生 | / | / | Y |
下面是指标的部分划分分类:
指标汇总分层
整体级 | 从整体上统计,比如全部学校,全部老师 |
---|---|
功能级 | 针对某个功能统计全部包含该功能的数据 |
单实体级 | 指标统计到每个实体上 |
指标统计关键性能
规模类 | 统计某维度下的量级 |
---|---|
质量类 | 衡量业务过程或产品的无问题概率 |
时效类 | 对某些业务过程来说时效是比较有竞争力的指标 |
精确类 | 统计某些业务过程(多是自动化类流程)的结果是否精确 |
指标类型划分
度量 | 事实自带的属性 |
---|---|
原子 | 不加修饰词的count,sum... |
派生 | 加修饰词的原子指标 |
复合 | 由多个指标做四则运算得到 |
整体规划
整体规划的主要步骤是先纵向划分再横向分层,这两个步骤如一张网般,能产生大数据设计最核心的架构图(见该环节最后的架构图)。纵向划分即数据域划分,并依次产生总线矩阵;横向分层即划分DWD、DWS等,并回答各业务行为应该保存何种粒度(哪一层落表),对应的表名是什么等问题。梳理总线矩阵时可以分析每一行以测试是否为业务过程定义好相关的候选维度,同时也能分析每个列,考虑某一维度需要跨多个业务过程并保持一致性。
数据域划分
设计数据域以及划分业务行为到数据域时,要把所有业务行为都列出,哪怕暂时用不到或该业务行为还没落数据,也要写出来,方便未来做扩展。如何划分数据域,可以把所有业务过程和实体都列出来,尝试按照业务共同点给他们分类,即取业务过程所能被归类的“类”的最大公约数作为数据域名称,分成最好控制在单业务8个以内的大类。使用高度概括性的名词来命令数据域,保证扩展性。
一致性维度和事实
当我们梳理一致性维度时,存在一部分维度属于“公共类”(同数据治理里的“参考数据”),既不属于任何数据域,也不产生于任何业务行为,或因业务行为而更新属性,例子比如地区信息,这是国家规定的。
除此之外,当我们在调研业务库表时,可能发现有些维度只作为业务记录的属性而存在,这意味着获取此类维度只能一遍遍从事实记录中解析,源系统没有一个专门的维表或系统存储该维度数据。我们无法预测维度的变更,没有规则去约束维度值,当然,业务数仓也无法抵御维度剧烈变更或出错带来的风险。作为有前瞻视野的建模专家,我们有义务去建议和推动业务侧建立相应系统来维护此类维度的录入和更新。
有时候可能会难以界定一个实体应该归到维度还是事实,比如教育业务的“班级”,作为一个相比其他业务过程缓慢变化(一般一个学期才会有大变化)的事实,却跨了太多业务过程(源系统多个事务的表带有班级属性,诸如班级考试明细);如果作为事实,则会触碰到“事实跨多个数据域”的问题,因班级本身几乎不产生变更的业务过程,自身的创建或录入行为可以等同于维表中加入一条,我们决定把班级归为维度。另一个例子是“作业”,它有对应的业务行为:作业生产,该业务行为基本不产生任务度量(或者产生的度量即是任务本身:作业id),且该业务行为对应的指标也基本只有算该实体的uv,同时可以从源系统的表看到,该实体跨了多个业务过程。所以,我们是该把它当成事实去建立事实表(XX生产)还是当成维度,建立维表?从建模规范上看,似乎应该是事实表,从使用和对外推广的理解方面,应该是维表。对这个值得商榷的问题,团队内沟通的结论如下:如果因为任务跨多个表则认为应该建维表,那么“学生作答作业”这种产生大量事实记录的也应该建一个维表,虽然跨多个表,但学生作答作业仍旧是事实,且多是以事实外键的形式跨多个表的。所以我们可以把每个唯一的作答id当做各个表的一个杂项维度去理解,当分析时需要我们基于作业分组去计算指标时,可以认为是基于某个杂项维度汇总;至于如何去理解各表包含这些“事实”,可以认为是A事实表关联B事实表后作为附属属性带上的,因为多个事实表的关联是没有问题的。
关于维度,有个问题是,存在父子关系的两个维度是否有必要拆分成两个维表?比如年级维度和学段维度,年级维度能唯一确定学段维度。这个问题其实就是个物理模型选星型模型还是雪花模型的问题,如果认为这两个维度都是捆绑着使用的,则可以退化粗粒度的维度,否则长远来看雪花模型扩展性较强。
当一致性维度和业务过程梳理好后,便可以开始做总线矩阵。做总线矩阵时,对一个事实跨哪些一致性维度,可能存在冲突的地方即:
业务表带有属性A | 业务表不带有属性A | |
---|---|---|
你认为应该带属性A | 无异议 | 有冲突 |
你认为不应该带属性A | 有冲突 | 无异议 |
这个时候不知道该业务是否应该带上属性A。业务侧是从业务的角度去建模,我们是从分析的角度去建模(我们的视角可能具有前瞻性),自顶向下和自底向上可能存在冲突。经讨论,此种情况应该和业务侧RD具体讨论,如果有助于我们分析或减少关联的工作量,可以推动业务侧去加字段。
确定指标
该环节要梳理出每个数据域的所有原子指标、派生指标,用于支持后面维度建模时的详细设计和表结构定义。我们可以复用“需求分析”环节的指标列表,区别是加上了修饰词和维度以支持DWS表结构的定义。指标的新模板见下:
指标名称 | 指标定义 | 指标类型 | 原子指标 | 时间周期 | 修饰词 | 维度 | |
---|---|---|---|---|---|---|---|
1 | 当日XXYY数 | 派生指标 | YY数 | d | XX | aa, bb, cc |
当我们设计沉淀公共指标的DWS表时,也需要考虑的是指标的计算口径是否通用,指标是否可复用,如果回答是是的话,我们倾向于把指标放到DWS层,而不是面向具体应用或需求的ADS层,哪怕这个指标就属于某个需求(此时在ADS层我们只对DWS层的指标做简单的拼接)。有的时候我们并不清楚该指标的计算口径是否通用,这个时候建模专家的经验就发挥作用了,如果建模专家倾向于该指标会是个通用指标,则把指标的计算结果下沉到DWS层,如果建模专家没法确定,则将计算过程放到ADS层处理,即使后面被证明该指标被多处复用,我们也可以在不改变表结构的情况下修改处理逻辑。
横向分层
该环节要梳理出每层都分别落下哪些表,以及,这些表该怎么命名。表在命名时,除了遵守规范外,还得考虑,表名能说明表的粒度,因为dwd层可能存在最细粒度事实表,以及聚集性事实表,累积快照事实表等。然后表中的业务行为,最好用名词(noun)而不是动词(verb),这样听着更合理。
除了第一次读取ODS表并落DWD层,其他时候不再建议读ODS表。
DWD层的表是否都从最细粒度的明细表开始产生数据?即,假如同一事实有两个明细DWD表,是否总是粗粒度的表依赖细粒度的?答案是取决于源系统业务表。源系统的业务表是最能反应业务过程的,有时候可能反常理地,源系统侧的业务表就是粗粒度的,细粒度的信息则以嵌套字段的格式保存在记录中,比如作业作答表,表中有嵌套字段以列表形式记录每道题的回答情况。这种情况,是否意味着我们应该在DWD最底层把嵌套字段拆开并平铺,改变业务侧表的粒度?不是的,我们DWD层首先要满足的是:还原业务过程,然后才是更好地支持大数据侧分析需求。更勿论,有些嵌套信息拆分后,是无法通过简单聚合或退化维度就能再还原回去的。
同一个事实,是否应该在DWD层固化不同粒度的明细表?这个可以基于我们的分析需求来决定,比如假设我们为某教育事业建模业务数仓,有个作业业务,它的粒度可以到每道题,也可以到整份作业。如果我们上一个需求分析环节发现有不少到整份作业粒度的指标,那么为了避免在DWS层计算这类指标时重复地汇总大量题粒度的数据,把这类数据“预聚合”到DWD层落表无疑是更好的选择。而且因为源系统数据库遵循三范式一般都会有这两种粒度的表。
最后一点,描述实体之间关系的桥接表应该归到事实表还是维表?可以这么判断,如果该实体间的映射关系有个“绑定”的业务过程,则可以认为是包含事实的事实表,如果没有,或者在业务出现前天然存在,比如省市关系,则可以归到维表。
在纵向划分和横向分层完成后,我们可以产出整体规划图(类似这样的):
数据标准
该环节梳理所有会用到(包括将会用到)的词根,整理成数据字典以保证我们对指标和维度的命令是一致的,并维护数仓内的同名同义性和异名义异性。
在英文选词的时候,第一个要满足的要求是达意,即看了这个词就能知道是什么业务/实体;第二是够简单,能满足公司内英语水平不一的研发都能一眼明白词根的含义;如果是老业务重构,已经有一些约定俗成的词根了,则延续使用旧词根。业务过程的字段名建议用实体+动作名词,比如任务发布是"task publish"。即使针对某个实体可能就一个业务过程,也不要在建表的时候把动作的主语给省略,避免后面该实体增加业务行为时不好扩展的问题。
为了满足同名同义性,很多源系统的表没什么问题的字段,在数仓侧都得重新命名。比如type字段,在不同事实表中对于的枚举值即使一样,枚举值对应的含义也是差之千里的,因此要改名为xx_type。一般都是“事实实体名+属性名”的改法,如果是一致性维度则一般没有这个问题。
多事务事实表的“多事务”如何命名,如果全部列出来太长,且难以归纳的话,可以尝试“造词”(对外人而言肯定难理解,因此你要同步到数据字典上),比如登录注册两个事务合并的表用“dwd_xx_reglog_xx”来表示,取了注册regist的"re"以及登录login的"log"。
维度建模
该环节在表都明确的情况下补充表结构,并完成表的详细设计。
当有个表的生成逻辑涉及3个以上表且不只是简单的union时,落个详细的模型设计图(如下),在开发前先在团队内review设计图,确保理解一致以及各方面都考虑到了。相比代码review,图的可视性更强,降低理解成本,能让人review时不会陷入到代码细节中而总能有对整体的把握。后续迭代时也同步更新模型设计图。
当全部表的设计都完成时,可以维护一个血缘图来标识数据流向,不用多精准描述所有依赖关系,只要能表示主数据(即left join时在左边的表)的流向就可以了。血缘图可以帮助新人和外人快速理解数仓的数据流向。