假设我创建了一款游戏,用户可以通过在线市场提交购买和销售商品的请求。每个卖出请求都可以包含"子请求"适用于多种商品类型。每个购买请求只能满足其中一个子请求,然后父卖出请求不再有效/可用。 (如果你愿意,可以把市场动态搞砸了,但请耐心等待......)
我希望汇总这些数据,以便开始了解和分析趋势。为了论证,让我们假设市场中有足够的行动,我无法有效地存储和/或查询原始的交易级数据,所以我必须使用聚合。
每个卖出请求都会生成一个大致如下的日志条目:
{
sellRequestID: 123,
userID: 456,
timestamp: 1449043403,
country: "United States",
goods: [ "eggs", "beef", "chicken" ]
}
购买请求可能会生成大致如下的日志条目:
{
buyRequestID: 987,
sellRequestID: 123,
userID: 789,
timestamp: 1449043408,
good: "eggs"
}
我希望能够回答以下问题:
假设我有相对标准的维度表:
users countries goods
----- --------- -----
456 John Smith 1 United States 1 eggs
789 Jane Doe 2 Canada 2 beef
... ... . ... 3 chicken
可以回答我的第一个问题的表格可能如下:
Date CountryID Total Requests
2015-12-01 1 1,000,000
2015-12-01 2 200,000
...
可以回答我的第二个问题和第三个问题的表格可能如下:
Date CountryID GoodID Total Requests
2015-12-01 1 1 600,000
2015-12-01 1 2 300,000
2015-12-01 1 3 400,000
...
是否有设计允许我在一张表中回答所有问题?我考虑过几种可能性,并且正在寻找任何实践经验或建议。
如果我使用上面的第二个模式,我最终会在尝试回答问题1时夸大父请求的数量,并且会失去“重复数据删除”的能力。那些父请求很重要。
一种方法可能是使用如下的模式:
Date CountryID GoodID Parent Requests Child Requests
如果我这样做,为了避免先前情景中的通货膨胀,我需要"分数"父请求 - 例如包含三个商品的请求仍然会在三行中向子请求列添加1,但会向父请求聚合添加1/3。类似地,具有两个商品的请求将在其两行中向父请求列添加1/2。所以我可能有以下数据:
Date CountryID GoodID Parent Requests Child Requests
2015-12-01 1 1 1/3 1
2015-12-01 1 2 5/6 2
2015-12-01 1 3 5/6 2
现在我对父请求(忽略goodID)列的聚合将总和到预期的2个请求,但我仍然能够理解在2个父请求中,我有机会一次购买鸡蛋,牛肉两次,和鸡两次。
这种分数方法有什么缺点吗?我是不是想尝试一些不应该用鞋角的东西?提前谢谢。
答案 0 :(得分:1)
本身并不是一个简单的答案,而是一些想法。
1)您的方法的缺点是父请求中的分数将是半加性的,因此您需要仔细控制聚合该列的任何查询。这可能看起来微不足道,但是当您添加维度或者最终用户社区可能增长时,它可以踢你的屁股。如果你走这条路线,你可能想要用更加注重业务的东西替换名称“父请求”和“子请求”。您可以与您的用户讨论这个问题。关闭袖口,我可能会尝试用“请求”替换“子请求”,因为它直接应用于自然键,并且可能用“Good_to_Request_Ratio”替换“父请求”。 (我已经不喜欢了。)
2)正确索引,加权桥表可以提供解决方案。但它还有更多行。在这种情况下,您添加一个桥接到Good维度的“请求”维度。
3)我不理解用一个事实表回答所有问题的要求。表格设计必须首先满足功能和非功能分析要求。国家/日期谷物的一个表格和国家/日期/好的另一个表格是好的,特别是当细粒度的“请求”度量是半加性的并且不会与粗粒度相加时。