事实和维度:动态维度 [关闭]

Posted

技术标签:

【中文标题】事实和维度:动态维度 [关闭]【英文标题】:Facts and dimensions: dynamic dimensions [closed] 【发布时间】:2022-01-15 21:20:59 【问题描述】:

(感谢这篇文章对于 SO 来说可能太高层次或太哲学了,我正处于架构规划阶段并寻求一些指导)

在使用我们的生产数据库的克隆进行分析遇到一些困难后,我试图定义一个事件事实表以及一些维度表,以使分析工作更简单。

我在计划中遇到的障碍是这个。我们有不同类别的事件,需要用不同的维度来描述它们。例如。假设我们有“帐户设置”事件类别以及“画廊”事件。

在事实表中,我可能有一个字段 eventCategory 和 eventName,其中包含上面的示例值,例如:

'EventCategory': 'Account Settings'
'EventName': 'Update Card Billing Details'

或者:

'EventCategory': 'Gallery'
'EventName': 'Create New Gallery'

在每种情况下,我都想使用不同的维度集合来描述它们。例如。对于画廊活动,我们想知道“模板”、“图像数量”、“画廊类别”,例如水果'。我们不需要帐户设置事件的这些详细信息,它们有自己独特的一组维度来描述它们。

通过我在网上找到的教科书示例,我将获得画廊事件的维度表和帐户设置事件的维度表。

我的心理障碍是这些维度是动态的而不是静态的。我想在事实表中记录事件发生时这些维度的值,而不是“现在”。例如,用户可以是试用版或付费用户。如果我有一个维度表“用户”,他们的状态当前可能是“付费”,但在以前的一些画廊活动时,他们可能已经处于试用期。

处理这个问题的“正确”方法是什么:

多个事实表,一个用于库事件,一个用于帐户设置事件? 在主要事实表的新字段中使用 json,例如'EventDetail' 包含维度表中的其他内容,除非使用 json,我们知道事件发生时维度的值,而不是现在的那些值? 我可以有一个稀疏的事实表。我将包含所有类别中每个维度的字段,如果不适用,这些字段将为空

鉴于我用来描述事件的维度是动态的,那么构建用于分析的事实表的“正确”方法是什么?我刚才看到的方式是,维度表本身必须是事实,才能捕捉这些属性随时间变化的值。

【问题讨论】:

【参考方案1】:

向任何 SQL 表添加维度始终以相同的方式完成,即添加一列。

在任何一种历史中,都没有“现在”。每个状态都有一个时间段:开始和结束。我通常将这些列命名为 AsOfUntil,因为 begin/end 经常显示为 SQL 关键字,使得列名更难扫描。通常,只需要AsOf,因为您可以自联接表以查找后续期间,并使用 NULL 表示“现在”(其中“现在”表示,截至执行查询的时间 em>)。

“用户”他们的状态目前可能是“付费”,但在之前的一些画廊活动时,他们可能已经处于试用期。

没错,所以用户的状态不仅仅是付费/试用。 付费试用从某个日期开始 AsOf,直到同一用户的更晚 AsOf 日期。

很难提供更多帮助。您的问题中有一些行话,并且是以特定领域的术语表达的。我希望通过为每个状态附加日期/时间,您可以看到自己走出森林的路。

【讨论】:

谢谢。这是有道理的,使用“AsOf”时间戳。您如何看待使用 json 字段来捕获例如某个时间点的画廊尺寸?也许这是一种“偷工减料”的方法?我的目标是数据检索的简单性和便利性。 我想你会发现 JSON,正如 F*** Pascal 喜欢说的那样,增加了复杂性而没有能力。任何可以用 JSON 表达的东西都可以用 SQL 表来表达,而只使用表可以简化问题,因为数据只有一种表示形式。 在这样的任何类型的工作中,一个无法避免的麻烦是重叠的时间段。您必须为两个实体构建 AsOf-Until 对,然后将它们加入 where a.AsOf between B.AsOf and B.Until or b.AsOf between a.AsOf and a.Until。表达起来很尴尬,想起来也很困惑,但没有办法绕过它。没有技术上的简化,这是不可避免的。【参考方案2】:

(A) 在 postgres 中管理时态数据

时态数据在许多类型的业务应用程序中是很常见的需求,但它不是 postgres 中的“内置”功能,也不是许多其他 RDBMS 中的“内置”功能。

正如@James K. Lowden 所说,您可以使用timestamp 类型的一些AsOfUntil 列,带或不带时区,或者您可以使用tsrange 或@ 类型的单个列来代替987654327@,即一系列时间戳,它会为您提供一些不错的内置功能,请参阅manual。

为了避免与同一数据的不同事件关联的时间戳范围之间的重叠,您可以使用触发器函数实现业务逻辑。 例如,对于同一用户,您可以实现以下触发函数,以便在将相应行插入到user 表,并且同一用户的现有行的范围会相应更新:

CREATE OR REPLACE FUNCTION before_insert_user ()
RETURNS trigger LANGUAGE plpgsql AS
$$
BEGIN
-- update all the existing rows (ie status) for the same user_id whose valid_ranges are valid as of now
  UPDATE user
     SET valid_range = tstzrange(lower(valid_range), Now())
   WHERE user_id = NEW.user_id
     AND valid_range @> Now() ;
-- set up the valid_range for the new row (ie the new status)
  NEW.valid_range = tstzrange(Now(), NULL) ;
END ;
$$ ;

CREATE OR REPLACE TRIGGER before_insert_user BEFORE INSERT ON user
FOR EACH ROW EXECUTE FUNCTION before_insert_user () ;

(B) 管理不同类别的不同维度

如前所述,json 可以是在同一列中存储各种维度的解决方案。

另一种解决方案可能是表inheritance 具有一些有趣的功能:

CREATE TABLE Event
( EventCategory varchar
, EventName varchar
, ValidityRange tstzrange
, primary key (EventCategory , EventName, ValidityRange )
) ;

CREATE TABLE user
( status varchar
) INHERITS Event ;

CREATE TABLE Gallery
( template varchar
, "count of images" integer
, "gallery category e.g. fruits" varchar
)  INHERITS Event ;

【讨论】:

【参考方案3】:

事实表需要定义其粒度;如果事实与该粒度不匹配,则无法将它们存储在该事实表中 => 如果您的事实具有不同的集合 if 维度,那么您需要使用不同的事实表。

关于维度变化中的值,您需要阅读Slowly changed Dimensions

【讨论】:

以上是关于事实和维度:动态维度 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

具有一对多关系的维度属性[关闭]

星型设计[关闭]

维度表和事实表的含义是啥?

我应该跟踪关系/事务数据库中缓慢变化的维度吗? [关闭]

Pytorch 错误:ValueError:图片应该是 2/3 维。有4个维度[关闭]

在维度上求和多维数组[关闭]