AppEngine上ACL的高效组成员身份测试



我正在为数据存储中的对象创建访问控制列表。每个ACL条目都可以有一个允许访问相应条目的所有用户id的列表。然后,我查询用户可以访问的实体列表将非常简单:

select * from ACL where accessors = {userId} and searchTerms >= {search}

问题是,在达到索引条目限制之前,它只能支持2500个用户,当然,将ACL条目与许多用户放在一起会非常昂贵,因为许多索引条目都需要更改。

因此,我考虑添加一个允许访问实体的用户组列表。这可能会大大减少每个ACL条目所需的索引条目数量,但查询时间会变长,因为我必须查询用户所在的每个可能的组:

select * from ACL where accessors = {userId} and searchTerms >= {search}
for (GroupId id : theSetOfGroupsTheUserBelongsTo) {
    select * from ACL where accessingGroups = {id} and searchTerms >= {search}
}
mergeAllTheseResultsTogether()

这将需要很长时间,页面浏览难度大得多,等等。

有人能推荐一种从ACL中获取实体列表的方法吗?该方法不会限制访问用户的数量?

编辑以获取更多详细信息:

我正在对一所学校使用的一长串学术主题进行搜索和排序。其中一些主题是由管理员创建的,应该是学校范围内的。其他则是由教师创建的,可能只与这些教师相关。我想创建一个类似谷歌文档列表的集合层次结构,将每个主题视为一个文档。searchTerms字段将是主题名称中的单词列表——没有太多内部文本可供搜索。每个主题将至少在一个集合(组织的"根"集合)中,并且可能在多达10-20个其他集合中,所有集合都由不同的人管理。理想情况下,文档可能出现的集合数量没有上限。我在这里的困难是生成一个特定用户至少可以读取访问的所有实体的列表-谷歌文档中的类似视图将是"所有项目"视图。

假设您的文档和组权限的更改频率(或时间关键性)低于用户查询,我建议这样做(这就是我解决类似问题的方法):

在ACL中,包括字段

  • 访问者<--所有可以访问文档的用户标识
  • 访问者数量<--每当更改该字段时,存储访问者的长度
  • searchTerms

ACL的key_name类似于"indexed_document_id||index_num"

密钥中的index_num允许您潜在地有多个实体存储用户列表,以防用户列表超过5000(列表中项目的数据存储限制),或者无论您希望在列表中有多少,以降低加载一个用户的成本(尽管您不需要经常这样做)。

不要忘记,要访问的文档应该是索引实体的父级。通过这种方式,您可以执行select __key__查询,而不是select *查询(这避免了必须反序列化访问器和searchTerms字段)。您可以搜索并返回实体的parent(),而无需访问任何字段。更多关于这个和其他gae搜索设计的博客文章。遗憾的是,这个区块帖子并没有像我们这样涵盖ACL索引。

免责声明:我现在遇到了这个设计的问题,因为用户可以访问什么文档取决于他们是否关注该用户。这意味着,如果他们关注或取消关注,可能会有大量现有文档需要添加/删除用户。如果你是这样的话,那么如果你遵循我的技术,你可能会和我陷入同一个困境。我目前计划通过在后台更新旧文档的索引来处理这个问题。其他人回答这个问题可能会有一个解决方案——如果没有,我可以把它作为一个单独的问题发布。

此数据结构上的操作分析:

添加索引文档:

  1. 对于每个有权访问文档的组,创建一个实体,该实体包括访问者字段中可以访问文档的所有用户
  2. 如果一个字段中容纳的实体太多,则创建更多实体并递增index_num值(使用分片计数器)

O(n*m),其中n是用户数,m是搜索查询数

查询索引文档:

  1. select __key__ from ACL where accessors = {userid} and searchTerms >= {search}(尽管我不确定你为什么要做">="实际上,在我的查询中,它总是"=")
  2. 从这些关键帧中获取所有父关键帧
  3. 筛选出重复项
  4. 获取那些父文档

O(n+m),其中n是用户数量,m是搜索项数量——这很快。它使用两个索引的Z字形合并联接(一个用于访问器,一个用于搜索项)。这假设gae索引扫描是线性的。对于"="查询,它们可能是对数的,但我不了解它们索引的设计,也没有做过任何测试来验证。还要注意,您不需要加载索引实体的任何属性。

为用户添加对特定文档的访问权限

  1. 检查用户是否已具有访问权限:select __key__ from ACL where accessor = {userid} and parent = {key(document)}
  2. 如果没有,则添加:select * from ACL where parent = {key(document)} and numberOfAccessors < {5000 (or whatever your max is)} limit 1
  3. 将{userid}附加到访问者并放入实体

O(n),其中n是有权访问文档的人数。

删除用户对特定文档的访问权限

  1. select * from ACL where accessor = {userid} and parent = {key(document)}
  2. 从访问者中删除{userid}并放入实体

O(n),其中n是有权访问文档的人数。

压缩索引

如果你做了很多删除操作,你就必须偶尔做一次。不确定检测这种情况的最佳方法。

  1. 要了解是否有任何内容需要为特定文档进行压缩:select * from ACL where parent = {key(document)} and numberOfAccessors < {2500 (or half wahtever your max is)}
  2. 对于其中的每一对:删除一个,将访问器附加到另一个

O(n),其中n是有权访问文档的人数

最新更新