适用于稀疏用户配置文件的适当数据库设计

时间:2016-06-27 15:30:59

标签: mongodb database-design hbase impala database

我想有效地存储和查询用户数据。用户由唯一的UUID标识,并且可以具有数百个不同属性的值(所有布尔值,数字或字符串)。但是,对于大多数用户而言,已知属性的数量非常有限,因此大多数值为空。此外,一些属性本质上是分层的(例如,女性(是 - 否) - >喜欢_用户(是 - 否) - > likes_red_heels(是 - 否))。有1亿不同的用户,并且经常添加新的可能属性。

我正在考虑3个选项:关系表结构(例如Impala),键值存储(例如HBase)和基于JSON的数据库(例如MongoDB)。

目前的重点是执行查询(例如,有多少用户是男性,30岁以上和中国人?)

我期待您的推荐!

1 个答案:

答案 0 :(得分:1)

我可以与类似的用例分享我的经验。我们使用HBase存储了数千个这样的属性。请注意,在我们的示例中,属性值始终为true / false / null。 Null意味着我们不能果断地判断它是虚假还是真实。

目标是

  • 为复杂的布尔表达式运行大规模聚合。例如,给我所有女性用户的聚合(计数)以及喜欢2个日期之间的高跟鞋的用户。
  • 允许对样本运行聚合以上,因为在大多数情况下,样本给了我们公平的趋势指示(非常快)
  • 能够添加属性
  • 最小化存储空间,从而缩短扫描时间

我们将所有属性编码为位图数据结构。每个属性都有唯一的偏移值(位图中的位置)。如果设置了一个位,则用户是女性或喜欢的高跟鞋。为了处理null,我们为每个用户存储了一个额外的位图。如果第一个位图中的位为false,那么我们检查第二个位图中的相同位置以查看它是否为真。如果第二个位图设置了位,我们将其视为null。

BitMap本身将占地面积减少了一个数量级。您还可以使用像Roaring Bit Maps这样的稀疏位图结构来减少存储并提高效率。

在位图(字节数组)中查找一点是一个恒定时间操作。然后我们使用HBase协处理器来执行聚合。客户端将传递布尔表达式,如

att1 && att2 && (att3 || att4)

客户端还会传递表达式中每个属性的偏移量。这使得协处理器能够基于偏移来扫描过滤行的位。

我们的行键设计基于用户ID的SHA1。这是

<FIRST 2 BYTES of SHA1><DD-MM-YYYY><40 bytes of SHA1>

这允许我们使用HBase的模糊行过滤器

  • 从可能的256个分片(前2个字节)中扫描样本
  • 扫描日期范围

我已经针对大约6000个没有稀疏位图的属性和具有稀疏位图的大约15000个属性测试了这种方法。在某些情况下,可以在位图中模拟数字属性(显然不是连续值)。

我们希望处理4-5亿用户,并且每个用户被建模大约3次(平均),因此存储了大约150亿个这样的事件(userid - date - 建模属性集)。我们还支持执行不同计数的功能,因为相同的用户可能在不同的日期有不同的建模属性。

我们在Map / Reduce中执行了所有编码,并使用HBase批量加载功能来执行极快的加载。

这种设计的优点之一是,由于我们在HDFS中保留了所有编码数据的副本,因此我们可以编写一个自定义Hive / Impala / Spark UDF来执行过滤/评估以通过SQL进行查询。此外,HDFS中的副本可以保留更长的时间(比HBase中保存的时间长)作为冷层。

我们也考虑过Apache Phoenix,但我们没有选择那个,因为我们想同时支持100个表达式的聚合,而不是一次支持一个表达式。

我希望这会有所帮助。