如何在 NoSQL 中跟踪记录关系?

我试图找出 NoSQL KVP 或 Document 数据库中的外键和索引的等价物。由于没有关键表(添加标记两个对象之间关系的键) ,我真的不知道如何才能检索数据的方式,将是有用的正常网页。

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

  1. 将它们嵌入到用户对象中(这似乎相当无用)
  2. 创建并维护一个 user_id:comments值,该值包含每个注释的键列表[注释: 34,注释: 197,等等..。.]这样我就可以根据需要把它们取回来。

然而,拿第二个例子来说,当你使用它来跟踪其他东西时,你很快就会碰壁,比如一个叫做“ active _ comments”的键,它可能包含3000万个 id,使它成为 一吨来查询每个页面,只是为了知道一些最近的活跃评论。它也会非常倾向于 种族条件,因为许多页面可能会尝试同时更新它。

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

  • 所有用户的评论
  • 所有积极评论
  • 所有用[关键字]标记的帖子
  • 一个俱乐部中的所有学生——或者一个学生所在的所有俱乐部

还是我想错了?

51834 次浏览
  1. User: userid: comments 是一种合理的方法——可以将其视为 SQL 中的列索引,并附加了不能对未索引的列进行查询的要求。

  2. 这就是您需要考虑需求的地方。一个拥有3000万条目的列表并不是因为速度慢而不合理,而是因为用它做任何事情都是不切实际的。如果你真正的需求是显示一些最近的评论,你最好保持一个非常短的列表,每当一个评论被添加更新-记住,NoSQL 没有规范化的要求。竞争条件对于基本键值存储中的列表来说是个问题,但是一般来说,您的平台要么正确地支持列表,要么使用锁进行处理,要么实际上不关心失败的更新。

  3. 与用户注释相同-创建一个索引关键字: post

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

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

另一方面,Riak 有建立关系的工具。是链接。您可以将链接(此处注释)文档的地址输入到‘ root’文档(此处用户文档)。只有一个办法。如果它是分布式的,它可以在许多地方一次性修改。它将导致冲突,并因此产生巨大的向量时钟树:/。.不太好,不太好。

Riak 还有另一种“机制”。它有两层的键名空间,称为 bucket 和 key。所以,举个学生的例子,如果我们有 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。你需要看一下具体的实现,然后自己测试一下。

前面提到的 Column 商店看起来非常适合处理关系。.但这完全取决于你的 A、 C 和 P 的需求;)如果你不需要 A,而且你只有少于 Peta 的字节,那么就用 MySql 或 Postgres 吧。

祝你好运

所有关于如何以“ NoSQL 方式”存储多对多关联的答案都归结为同一个问题: 冗余地存储数据。

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

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

反规范化和冗余的风险在于冗余的数据集会彼此失去同步。这叫做 异常。使用规范化关系数据库时,关系数据库管理系统可以防止异常。在非规范化数据库或 NoSQL 中,您有责任编写应用程序代码以防止异常。

有人可能会认为,NoSQL 数据库能够为您完成预防异常的艰苦工作是非常了不起的。有一个范式可以做到这一点——关系范式。

你有

"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 数据库中也会这样做。只需索引您将用来获取信息的字段。

例如,对您来说重要的索引是

  • 注释,用户 ID
  • 评论,页码
  • 评论,邮政时间
  • 页面,标签[]

如果您正在使用 支持 SQL 的基于.NET 的 NoSQL 数据库,您的查询将类似于

 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 备忘单或文档中支持的所有查询类型。

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