BI的数据模型就是通过关系相互连接的一组表。这组表里面有事实表、维度表,通过关系把他们连在一起。
两个不同表之间存在以下3种关系类型:一对一(1 : 1),一对多(1 : N),多对多(N : N)。
1:1 & 1:N很容易理解,但N:N就复杂多了,理解起来没那么直观。
N:N关系的基础理论来自于集合论。在集合论中,可以将实体看作集合,实体之间的关系可以看作集合之间的关系。N:N关系可以通过两个集合之间的笛卡尔积来表示。
笛卡尔积:
指由两个集合中的每个元素组成的每一对有序元素构成的集合。例如,S={1, 2},T={a, b},则它们的笛卡尔积为{(1,a),(1,b),(2,a),(2,b)}。这个集合中每个元素都是一个有序对,表示S和T之间的所有可能的对应关系。因此,通过两个集合之间的笛卡尔积,可以表示两个集合之间的多对多关系。
在数据建模中,N:N关系的建模,我们天然的认为会发生数据膨胀,导致多条重复数据出现,最终会影响统计结果。这么认为其实没错,SQL中多对多的JOIN连接,确实会导致数据膨胀。为了避免这个问题,常规的做法就是使用桥表,将N:N转化为两个1:N后再进行join连接,这个处理方法也通用于BI的N:N关系处理。
23年4月份,FineBI 发布了“主题模型”功能,除了让数据准备更简单、多表分析更高效外,还能更加友好的支持 N:N 计算场景。可以说是大大的减少了N:N场景的计算准备工作量,但随之而来的就是高度抽象的合并&计算逻辑,大大的增加了理解成本。
能够深度理解主题模型计算原理的人可能会使用后发出惊呼:wow,太棒了!
不能够理解主题模型计算原理的人,可能就会“想用却不敢用”,因为搞不清楚用了之后哪里会暴雷。
所以今天想拆解下FineBI的N:N计算步骤,把抽象的计算过程具体化一些,便于大家理解。
我们通过一个案例来看:
需求背景:
BYD是一家日用品仓储超市,主要经营纸巾、洗衣液等相关产品,每年2月、6月、7月和11月是超市的固定大促月,基本可以享受全年最低价,另外,为了方便顾客,超市提供一项寄存服务,比如,7月付款买10箱纸巾(预售单),后续用到的月份再来提货,用几箱提货几箱即可,也允许一笔订单提多个预售单的货(提货单),对那些家中存在空间有限的顾客来说,这是一项完美的服务。所以每到大促月,很多顾客会选择寄存。
Tom是这家连锁超市的运营经理,近期他在分析经营数据的时候发现,超市预售的业绩越来越高,就想了解下预售提货的数据,所以向数据部提了如下需求:
1、2023年超市每月的预售件数、提货件数是多少,还有多少未提?
2、哪些会员还未提货完成,分别还有多少未提件数?
这个需求听起来很简单,但如果深入了解业务过程,你就不会认为简单了。
最大的障碍点在于:超市允许一笔订单多次提货,也允许一笔订单提多个预售单的货。
什么意思呢?翻译成关系就是:
一笔预售订单多次提货 ,即1笔预售单,对应多个提货单(1:N),这个简单
一笔提货单提多个预售单的货 即 1笔提货单,对应多个预售单(1:N),这个简单
但是,关键是但是,算未提得合在一起看,然后。。。就成了N:N。就不简单了。
不过幸好,FineBI6.0的主题模型支持N:N,我们来看看这个需求怎么通过主题模型实现~
弹出【选择数据】框,将Excel数据导入。
数据如下,
预售单:
提货单:
P.S.为了便于理解,数据做了简化处理,但请注意预售单的「订单ID」是存在重复的,提货单表内的「关联预售单号」也是存在重复的。
模型视图内,关系选择N:N,连接依据选用预售表的「订单ID」以及提货表的「关联预售单号」
1. 计算每月的未提数量,添加计算字段,未提数量 = SUM_AGG(销售数量)-SUM_AGG(提货数量)
2. 然后将预售表的「订单日期」拖入维度栏,将预售表的「销售数量」、提货表的「提货数量」、上一步的计算字段「未提数量」拖入指标栏即可。
3. ok了,如此简单,算对了没有?敢不敢用?
回到Part1的数据仔细看看,算一下。发现没错!
怎么样?惊喜么?
4. 继续算每个会员还有多少未提。
继续验证下数据对不对,可以放大图片,口算下结果。
完美!!
5. 到这里,Tom的这个需求就完成了,一切都很完美。
然而,当我们想进一步知道每个会员是什么产品没提货的时候,异常出现了。下图红框的部分,客户实际上是没有提货数据的,然の,此处却有计数。
为什么会有计数?
答:这个模型的合并依据是预售表的「订单ID」以及提货表的「关联预售单号」,而且分析维度是站在预售表的角度看的。模型在用连接字段合并的时候,优先保证预售表的数据完整,而后开始调用「订单ID」这个连接条件,如果出现一笔订单中多个单品,数据就会出错。比如下图:
6. 怎么办呢?
答:联合关联,多字段合为一个字段来唯一标识一行记录。就是把合并依据从预售表的「订单ID」以及提货表的「关联预售单号」,调整为预售表的「订单ID+产品ID」以及提货表的「关联预售单号+产品ID」,在数据处理阶段新增列合并订单ID和产品ID即可。
合并界面如下:
模型的连接关系字段调整为合并后的字段
计算结果:
一切又回到了完美!
为了方便理解,我们拆解下计算步骤,把抽象的计算过程稍微具象化一点。依每月未提件数的组件举例:
每月的预售数量、提货数量、未提数量结果如下:
主题模型的计算过程:
1. 识别分析字段和关联字段
此例中分析字段为预售表中的「年月」
关联字段为预售表的「订单ID」、提货表的「关联预售单号」。
2. 计算预售表中每月的预售数量,分析维度为「年月」、「订单ID」,聚合结果为SUM(预售数量)
3. 计算提货表中每月的提货数量,分析维度为「关联预售单号」,聚合结果为SUM(提货数量)
4. 依据预售表的「订单ID」、提货表的「关联预售单号」关联字段合并
5. 依据「年月」进行聚合。
比如,2月有两笔订单,计算这两笔订单的合计预售件数,提货件数。其它月份依次类推。
小结
FineBI的主题模型合并逻辑:
-
只有分析字段和关联字段参与模型的合并计算
-
先聚合,再合并
如果类比到SQL的JOIN连接,这个计算过程就是通过两个子查询得到的:聚合的子查询a JOIN 聚合的子查询b。
相比较来说,FineBI通过主题模型实现还更便捷呢!
拿例子去练手吧,多换几个分析字段观察下计算结果。会对主题模型的合并逻辑理解的更深刻。
好了,今天就酱紫,回见~
|