【发布时间】:2013-04-10 22:54:54
【问题描述】:
我的团队正在使用 GAE (Java) 编写一个应用程序,这让我质疑 BigTable 等面向对象数据库中实体关系建模(特别是多对多)的可扩展性。
在 App Engine 数据存储区(请参阅Entity Relationships in JDO)中建模无主的一对多和多对多关系的首选解决方案似乎是键列表。然而,谷歌警告:
“实现多对多有一些限制 这样的关系。首先,您必须显式检索值 在存储列表的集合一侧,因为所有你 可用的是 Key 对象。另一个更重要的是你 想要避免存储过大的键列表..."
谈到过大的键列表,如果您尝试以这种方式建模并假设您为每个键存储一个 Long ,那么每个实体的限制为 1MB 的理论最大数量每个实体的关系约为 130k。对于一个主要优势是可扩展性的平台来说,实际上并没有那么多关系。所以现在我们正在研究可能需要超过 130k 关系的分片实体。
文章 Modeling Entity Relationships 概述了另一种方法(关系模型),作为 AppEngine 开发人员资源中掌握数据存储系列的一部分。然而,即使在这里谷歌警告关系模型的性能:
“但是,您需要非常小心,因为遍历 集合的连接将需要对数据存储进行更多调用。 仅在您真正需要时才使用这种多对多关系 这样做,并注意您的应用程序的性能。”
所以现在你在问:'为什么每个实体需要超过 13 万个关系?'很高兴你问。让我们以一个拥有 100 万用户的 CMS 应用程序为例(嘿,我能做梦吗?!)
用户可以上传内容并与以下人员共享: 1.公开 2. 个人 3. 团体 4.任意组合
现在有人登录并导航到仪表板,该仪表板显示来自他们在任何组中连接的人的新上传。此仪表板应包括公共内容,以及专门与此用户或此用户所属的组共享的内容。还不错吧?让我们深入研究一下。
public class Content {
private Long id;
private Long authorId;
private List<Long> sharedWith; //can be individual ids or group ids
}
现在,我的查询以获取允许 id 看到的所有内容可能如下所示:
List<Long> idsThatGiveMeAccess = new ArrayList<Long>();
idsThatGiveMeAccess.add(myId);
idsThatGiveMeAccess.add(publicId); //Let's say that sharing with 0L makes it public
for (Group g : groupsImIn)
idsThatGiveMeAccess.add(g.getId());
List<Long> authorIdsThatIWantToSee = new ArrayList<Long>();
//Add a bunch of authorIds
Query q = new Query("Content")
.addFilter("authorId", Query.FilterOperator.IN, authorIdsThatIWantToSee)
.addFilter("sharedWith", Query.FilterOperator.IN, idsThatGiveMeAccess);
显然我已经违反了几条规则。也就是说,使用两个 IN 过滤器会炸毁。即使是任何尺寸接近我们正在谈论的极限的单个 IN 过滤器也会爆炸。除此之外,假设我想限制和翻阅结果......不,不!如果您使用 IN 过滤器,则不能这样做。我想不出任何方法可以在单个查询中执行此操作 - 这意味着如果没有大量的读取时间处理和管理多个游标,您将无法对其进行分页。
以下是我能想到的用于执行此操作的工具:非规范化、分片或关系实体。然而,即使有了这些概念,我也看不出如何以可扩展的方式对这些数据进行建模。显然这是可能的。谷歌和其他公司一直在这样做。我只是看不出怎么做。 任何人都可以阐明如何对此建模或向我指出任何基于 NoSQL DB 的 cms 样式访问控制的好资源吗?
【问题讨论】:
标签: java google-app-engine entity-relationship data-modeling bigtable