0

我的团队正在使用 GAE (Java) 编写一个应用程序,这让我质疑 BigTable 等面向对象数据库中实体关系建模(特别是多对多)的可扩展性。

在 App Engine 数据存储区中建模无主的一对多和多对多关系的首选解决方案(请参阅JDO 中的实体关系)似乎是键列表。然而,谷歌警告:

“以这种方式实现多对多关系有一些限制。首先,您必须显式检索存储列表的集合一侧的值,因为所有可用的都是 Key 对象。另一个更重要的是你想避免存储过大的键列表......”

说到过大的键列表,如果您尝试以这种方式建模并假设您为每个键存储一个 Long ,那么每个实体的限制为 1MB,每个实体的理论最大关系数约为 130k。对于一个主要优势是可扩展性的平台来说,实际上并没有那么多关系。所以现在我们正在研究可能需要超过 130k 关系的分片实体。

作为 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
}

现在,我获取允许查看的所有内容的查询可能如下所示:

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 式访问控制的良好资源吗?

4

1 回答 1

1

将 id 列表存储为属性不会扩展。为什么不简单地为每个新关系存储一个新对象?(就像在 sql 中一样)。该对象将为您的 cms 存储两个属性:共享项目的 ID 和用户 ID。如果它与 1000 个用户共享,您将拥有其中的 1000 个。为给定用户查询它是微不足道的。列出给定项目的权限或用户与他们共享的内容列表也很容易。

于 2013-04-18T02:40:14.927 回答