你如何跟踪NoSQL中的记录关系?

时间:2010-11-08 18:31:28

标签: nosql database-relations

我试图找出NoSQL KVP或Document数据库中的外键和索引的等价物。由于没有关键表(添加标记两个对象之间关系的键),我真的很难过如何能够以对普通网页有用的方式检索数据。

假设我有一个用户,该用户在整个网站上留下了很多评论。我能想到跟踪用户评论的唯一方法是

  1. 将它们嵌入用户对象(这似乎毫无用处)
  2. 创建并维护一个user_id:comments值,其中包含每个注释的键列表[注释:34,注释:197等等],以便我可以根据需要获取它们。
  3. 然而,采用第二个例子,当你用它来追踪其他东西时,你很快就会碰到一堵砖墙,例如一个名为“active_comments”的密钥,它可能包含3000万个ID,因为它成本为TON 查询每个页面只是为了了解最近的一些活跃评论。它也很容易出现竞争条件,因为很多页面可能会同时尝试更新它。

    如何在NoSQL数据库中跟踪以下关系?

    • 所有用户的评论
    • 所有有效评论
    • 所有标有[keyword]
    • 的帖子
    • 俱乐部的所有学生 - 或所有俱乐部的学生都在

    或者我是否错误地考虑了这个问题?

5 个答案:

答案 0 :(得分:158)

如何以“NoSQL方式”存储多对多关联的所有答案都会减少到同样的效果:冗余地存储数据。

在NoSQL中,您不会根据数据实体之间的关系设计数据库。您可以根据要对其运行的查询来设计数据库。使用与用于非规范化关系数据库相同的标准:如果数据具有内聚性更重要(考虑以逗号分隔的列表而不是规范化表格中的值),那么就这样做。

但是这不可避免地优化了一种类型的查询(例如,任何用户对给定文章的评论),代价是其他类型的查询(给定用户对任何文章的评论)。如果您的应用程序需要同等优化两种类型的查询,则不应该非规范化。同样,如果您需要以关系方式使用数据,则不应使用NoSQL解决方案。

非规范化和冗余存在风险,冗余数据集将彼此不同步。这称为异常。使用规范化关系数据库时,RDBMS可以防止异常。在非规范化数据库或NoSQL中,您有责任编写应用程序代码以防止出现异常。

有人可能会认为,对于NoSQL数据库来说,做一些防止异常的艰苦工作会很棒。有一种范式可以做到这一点 - 关系范式。

答案 1 :(得分:4)

  1. user:userid:comments是一种合理的方法 - 将其视为SQL中列索引的等价物,并增加了对无索引列进行查询的要求。

  2. 这是您需要考虑您的要求的地方。一个包含3000万个项目的列表并不是不合理的,因为它很慢,但因为用它做任何事都是不切实际的。如果您真正的要求是显示一些最近的注释,那么最好保留一个非常短的列表,只要添加注释就会更新 - 请记住NoSQL没有规范化要求。竞争条件是基本键值存储中的列表的问题,但通常您的平台正确支持列表,您可以使用锁执行某些操作,或者您实际上并不关心更新失败。

  3. 与用户评论相同 - 创建索引关键字:posts

  4. 更多相同 - 可能是一个俱乐部列表作为学生的财产,以及该领域的索引,以获得俱乐部的所有成员

答案 2 :(得分:4)

couchDB方法建议在map阶段发出适当类别的东西,并将其汇总为reduce ..因此,您可以映射所有注释并为给定用户发出1,然后仅打印出来。然而,需要大量磁盘存储来构建couchDB中所有可跟踪数据的持久视图。顺便说一下,他们还有关于人际关系的维基页面:http://wiki.apache.org/couchdb/EntityRelationship

另一方面,Riak拥有建立关系的工具。这是链接。您可以将链接(此处注释)文档的地址输入到“根”文档(此处为用户文档)。它有一个技巧。如果它是分布式的,则可以在许多位置一次修改它。它会导致冲突,因此巨大的矢量时钟树:/ ..不是那么糟糕,不太好。

Riak还有另一个'机制'。它有2层密钥名称空间,所以称为桶和密钥。因此,对于学生的例子,如果我们有俱乐部A,B和C以及学生StudentX,StudentY,您可以遵循以下惯例:

{ Key = {ClubA, StudentX}, Value = true }, 
{ Key = {ClubB, StudentX}, Value = true }, 
{ Key = {ClubA, StudentY}, Value = true }

并阅读关系只是给定存储桶中的列表键。那有什么不对吗?这很慢。列表桶从未成为riak的优先事项。越来越好了。顺便说一句。你不浪费内存,因为这个例子{true}可以链接到StudentX或Y的单个完整配置文件(这里不存在冲突)。

如你所见NoSQL!= NoSQL。您需要查看具体的实现并自行测试。

之前提到列存储看起来非常适合关系..但这一切都取决于你的A和C和P的需要;)如果你不需要A并且你有少于Peta字节就离开它,继续使用MySql或Postgres。

祝你好运

答案 3 :(得分:1)

你有

"user": {
    "userid": "unique value",
    "category": "student",
    "metainfo": "yada yada yada",
    "clubs": ["archery", "kendo"]
}

"comments": {
    "commentid": "unique value",
    "pageid": "unique value",
    "post-time": "ISO Date",
    "userid": "OP id -> THIS IS IMPORTANT"
}

"page": {
    "pageid": "unique value",
    "post-time": "ISO Date",
    "op-id": "user id",
    "tag": ["abc", "zxcv", "qwer"]
}

在关系数据库中,正常的做法是以一对多关系来规范化数据。这与你在NoSQL数据库中所做的一样。只需索引您将获取信息的字段。

例如,您的重要索引是

  • Comment.UserID
  • Comment.PageID
  • Comment.PostTime
  • Page.Tag []

如果您使用的是NosDB (A .NET based NoSQL Database with SQL support),则您的查询就像

 SELECT * FROM Comments WHERE userid = ‘That user’;

 SELECT * FROM Comments WHERE pageid = ‘That user’;

 SELECT * FROM Comments WHERE post-time > DateTime('2016, 1, 1');

 SELECT * FROM Page WHERE tag = 'kendo'

检查其SQL cheat sheet或文档中支持的所有查询类型。

答案 4 :(得分:-1)

尽管,在这种情况下最好使用RDBMS代替NoSQL,但一种可行的解决方案是维护其他节点或集合以管理映射和索引。以额外的集合/节点和处理的形式可能会产生额外的成本,但是它将提供易于维护的解决方案并避免数据冗余。