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


117

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

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

  1. 将它们嵌入到用户对象中(看起来很没用)
  2. 创建并维护一个user_id:comments包含每个注释键列表的值[comment:34,comment:197等...],以便我可以根据需要获取它们。

不过,考虑第二个例子,你很快就会碰壁,当你用它来追踪其他事情,比如所谓的“active_comments”可能含有30000000点的ID在这使得它的关键花费TON查询每个页面只知道最近的一些活动评论。由于许多页面可能会尝试同时更新它,因此也很容易出现竞争情况

如何在NoSQL数据库中跟踪如下所示的关系?

  • 用户的所有评论
  • 所有活动评论
  • 所有标有[关键字]的帖子
  • 俱乐部中的所有学生-或学生所在的所有俱乐部

还是我在想这个错误?


在NoSQL数据库中没有一种方法可以做到这一点,这个问题有点像问我将如何跟踪C程序中的关系。
stonemetal

3
哇,那我想关于NoSQL取代RDBMS的炒作是不可能的。
Xeoncross 2010年

11
是的,NoSQL绝对被夸大了。我并不是说新技术在适当的情况下没有用,但认为它们会代替RDBMS却是荒谬的。参见en.wikipedia.org/wiki/Hype_cycle
Bill Karwin,2010年

1
您是否不仅拥有“用户”的集合和评论的集合。然后,每个注释就像一个“作者”属性,其值是对用户ID的引用?
CodeFinity

Answers:


186

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

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

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

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

可能有人认为NoSQL数据库为您进行防止异常的辛苦工作会很棒。有一个范式可以做到这一点-关系范式。


20
“如果需要以关系方式使用数据,则不应使用NoSQL解决方案。”-那么其他运行NoSQL的人如何摆脱它呢?首次设计应用程序时,如何得知查询数据的所有方式?福克斯例如,我可能希望最近的评论,用户评论,按标签的意见,对于一个给定发表评论,评论标记为垃圾邮件,主动评论,评分最高的评论,等等
Xeoncross

14
确实-NoSQL的倡导者喜欢声称没有“它只是工作”这样的东西。您可以为关系数据建模预先进行一堆分析,或者针对优先级最高的查询先进行一堆分析,或者在发现项目的哪些部分时在整个项目中进行大量的重构。之前没有得到足够的分析。
Bill Karwin 2010年

1
如果我们冗余存储数据,应该如何更新?例如,更改他的名字,然后他写了一些评论。他的名字已经在用户集合中更改,但是如何更改注释集合中所有冗余存储的名称?
Mohammad Kermani

3
@ M98,嗯,您已经发现此策略的弱点。您必须了解所有需要更新的位置,然后在应用程序中编写代码以在更新任何一个位置时更新所有位置。祝好运!
比尔·卡温

2
对于非规范化的关系数据库,存在相同的问题。
比尔·卡温

5

长沙发数据库方法建议在映射阶段发出适当的东西类,并在reduce中对其进行汇总。因此,您可以映射所有注释并1为给定用户发出,然后仅打印出来。但是,这将需要大量磁盘存储,才能在ouchDB中构建所有可跟踪数据的持久视图。顺便说一句,他们也有关于关系的Wiki页面:http : //wiki.apache.org/couchdb/EntityRelationship

另一方面,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。您需要查看特定的实现并自己进行测试。

在Column存储之前提到过,看起来很适合关系..但这全都取决于您的A,C和P需求;)如果您不需要A并且少于Peta字节,则直接保留它,继续使用MySql或Postgres。

祝好运


1
Riak最近发布了v1.0,该版本在使用LevelDB后端时增加了对二级索引的支持。非常有价值的功能。
乔恩·L.

4
  1. user:userid:comments是一种合理的方法-将其视为SQL中的列索引的等效项,并增加了您不能查询未索引列的要求。

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

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

  4. 更多相同的内容-可能是俱乐部的列表,作为学生的财产,以及该字段上的索引以获取俱乐部的所有成员


因此,基本上所有内容都只需要列表?似乎应该有一种比手动跟踪ID字符串更复杂的方法。首先,您只能走得更远,直到它们变得有用为止。再说一次,NoSQL技术的主要子项目(MongoDB,CouchDB,Membase等)都是新项目,所以也许我只需要给他们更多的时间来提出一种更好的跟踪关系的方法。
Xeoncross 2010年

如果您使用NoSQL(又称为非关系数据存储),则需要停止以关系术语思考。平台之间使用的方法会有所不同,但是必须管理索引的基本思想是相当普遍的。您提供的关系示例在NoSQL中以两种不同的方式建模:1)存储-与SQL不同,列可以具有多个/复杂值,因此子对象只是父对象的一部分。2)搜索-长列表实际上是可搜索性的要求,这意味着要建立索引-您可以使用简单的自定义列表或更完整的搜索引擎。
汤姆·克拉克森

2

你有

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.