Google App Engine Datastore 中最有效的一对多关系是什么?

16
抱歉如果这个问题太简单了,我只上了九年级。我正在尝试学习NoSQL数据库设计。我想设计一个谷歌数据存储模型,最小化读/写次数。
以下是关于博客帖子和评论的玩具示例,呈一对多关系。哪种方法更有效——在StructuredProperty中存储所有评论,还是在Comment模型中使用KeyProperty?
再次强调,目标是将对数据存储区的读/写次数最小化。您可以做出以下假设: - 评论不会独立于其相应的博客文章被检索。(我怀疑这使得StructuredProperty最可取。) - 评论需要按日期、评分、作者等进行排序。(数据存储区中的子属性无法索引,因此可能会影响性能?) - 创建后可能会编辑(甚至删除)博客帖子和评论。
使用StructuredProperty:
from google.appengine.ext import ndb

class Comment(ndb.Model):
    various properties...

class BlogPost(ndb.Model):
    comments = ndb.StructuredProperty(Comment, repeated=True)
    various other properties...

使用 KeyProperty:

from google.appengine.ext import ndb

class BlogPost(ndb.Model):
    various properties...

class Comment(ndb.Model):
    blogPost = ndb.KeyProperty(kind=BlogPost)
    various other properties...

如果有其他与最小化对数据存储的读写次数相关的有效表示一对多关系的方案,请随意提出。

谢谢。


考虑一下如何解决评论和博客文章的总大小超过1MB的问题。这种情况可能发生吗?如果可能发生,而且您没有一个好的解决方案来处理它,那么从纯功能角度来看,您甚至不需要使用包含两者的单个实体。 - Tim Hoffman
另一种选择可能是仅存储博客文章中所有评论的键。然后,您可以使用单个ndb.get_multi(keys)检索所有评论,但这将允许更多的评论,并且如果仍然超过1MB,则可以退回到逐个检索评论。 - Tim Hoffman
3个回答

14

我可能理解有误,但据我所知StructuredProperty就是实体内的属性,但具备子属性。

这意味着读取BlogPost及其所有评论只需一次读取操作。因此,在渲染页面时,整个页面只需要一个读取操作。

每次写操作的成本也更便宜。您只需要一次读取操作来获取BlogPost,只要不更新任何索引属性,那么只需一次写入操作即可。

在从数据存储中读取实体之后,您可以自己处理评论的排序问题。

由于多个用户都会修改相同的实体,因此您将不得不使用事务来同步评论的更新/编辑,以确保一个评论不会覆盖另一个评论。如果每个人都在同时对同一篇博客文章进行评论和编辑,则可能会遇到无法解决的问题。

尽管优化成本可以带来好处,但您将遇到1MB的最大实体大小限制。这将限制您可以为每篇博客文章存储的评论数量。

选择KeyProperty会更加昂贵。

您将需要一次读取操作来获取博客文章,再加上1个查询和1个小型读取操作来获取每个评论。

每个评论都是一个新的实体,因此至少需要4个写入操作。如果您还要为排序创建索引,则成本将更高。

好处是,您可以无限制地为每篇博客文章添加评论,无需担心同步新评论。您可能需要关注编辑评论的同步性,但如果将编辑限制为创建者,则这应该不会成为问题。您也不必自己进行排序。

这是成本与功能之间的权衡。


3

如何处理:

from google.appengine.ext import ndb

class Comment(ndb.Model):
    various properties...

class BlogPost(ndb.Model):
    comments = ndb.KeyProperty(Comment, repeated=True)
    various other properties...

这种方式可以让您在每篇博客文章中存储最多5000个评论(重复属性的最大数量),而不受每篇博客文章大小的限制。您不需要查询来获取评论的博客,只需要执行ndb.get_multi(blog_post.comments)即可。对于此操作,您可以尝试依赖ndb的memcache。当然,这取决于您的使用情况是否是一个好的假设。


1

当使用重复的StructuredProperty时,请注意以下警告:

如果您有超过100-1000个值,请勿使用重复属性。(1000可能已经太多了。)它们不是为这种用途而设计的。

请参见GAE ndb设计、性能和重复属性的使用中Guido的回答。

因此,虽然您可能不会遇到StructuredProperty的1 MB实体限制,但您可能很容易达到建议的最大值100-1000。


那么还有什么替代方案吗?就像问题中使用的KeyProperty一样吗?或者有更好的方法吗? - Ajedi32
如果KeyProperty的值在100-1000之间,那么它可以工作,但是如果你有更多的值,我建议重新考虑你的数据模型和所需的功能。在博客示例中,将评论存储为单个JSONProperty也可以工作。这样,您只需要更新/读取1个实体(BlogPost),并更新其JSONProperty以获取评论。这类似于StructuredProperty解决方案,但没有100-1000值的限制。当然,如果实体大于1 MB,这种方法就行不通了(除非您将其分片成多个实体...),但这可能适用于您的用例。 - David Stack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接