【问题标题】:ElasticSearch content ACL Filtering performanceElasticSearch 内容 ACL 过滤性能
【发布时间】:2015-12-22 23:29:16
【问题描述】:

以下是我的内容模型。

文档与定义有权访问文档的主体的用户和组 acl 相关联。 文档本身是一堆元数据和一个大型内容主体(从 pdfs/docs 等中提取)。

执行搜索的用户必须仅限于他/她有权访问的文档集(由文档上的 acl 定义)。由于用户 acls 或用户所属的组,他/她可以访问文档。 文档上的组成员身份和 acl 在本质上都是高度瞬态的,这意味着用户的组成员身份经常发生变化,文档本身的 ACL 也是如此。

方法 1 将文档上的 acl 及其元数据存储为非存储字段。将 ACL 中的组扩展到单个用户(因为 acl 可以是一个组)。 在查询时,将过滤器附加到用户查询,该过滤器将执行布尔过滤器以仅包含 acl 字段中具有用户 ID 的文档

"filter" : {
        "query" : {
            "term": {
                "acls": "1234"
            }
        }
      }

我看到这种方法的问题是,尽管文档元数据/内容没有改变,但文档需要重新索引。

每次用户的组成员更改时
每次文档上的 ACL 更改(文档的权限更改)

我假设这将导致大量的段创建和合并,尤其是因为文档正文(文档的字段之一)是一个相当大的文本部分。

方法 2: 这是对方法1的修改。当更新与acl严格相关时,这种方法试图限制文档上的更新。

而不是在元数据上定义 acl。这种方法需要创建多种类型

文档索引中

Document (with metadata & text body) as a parent

id
text


userschild Document (parent id & user acls only). This document will exist for each parent

id
parentid
useracls



groupschild Document (parent id & group acls only). This document will exist for each parent with group acls

id
parentid
groupacls

用户索引中 系统中每个用户的条目及其关联的组

User
   id
   groups

这里的想法是更新现在本地化到不同的 ElasticSearch 实体。 在用户 acl 更改的情况下,只会更新用户子文档(避免对父文档进行潜在的昂贵更新)。 如果组 acl 更改,则只会更新 groupschild 文档(再次避免对父文档进行潜在的昂贵更新)。 如果用户组成员再次更改,则只会更新二级索引(避免更新父文档)。

查询本身如下所示。

   "filter" : {
            "query" : {
               "bool": {
                 "should": [
                   {
                      "has_child": {
                        "type": "userschild",
                        "query": {
                          "term": {
                            "users": "1234"
                          }
                        }
                      }
                    },{
                      "has_child": {
                        "type": "groupschild",
                        "query": {
                        "terms" : {
                          "groups" : {
                            "index" : "users",
                            "type" : "user",
                            "id" : "1234",
                            "path" : "groups"
                          }
                        }
                      }
                      }
                    }
                 ]
               }
            }
          }

由于所涉及的查询的性质,我对它的可扩展性存有疑问。它涉及两个术语查询,其中一个必须从单独的索引构建。我正在考虑使用启用了 docvalues 的字段来改进术语查找。

方法 2 会扩展吗?我担心的是 has_child 查询及其可扩展性。

有人可以澄清我在这方面的理解吗?

【问题讨论】:

  • 如果您的客户端/应用程序知道 user_id,它是否也知道搜索者属于哪些组?给定搜索者的 user_id 和组,为什么不只过滤 matching group ACLmatching user ACL
  • 原因是用户可能属于 1000 到 10000 个组,这会使组评估成为查询期间的瓶颈,并且一直是问题
  • 确保您阅读了Practical Considerations for Parent-Child。涉及性能和内存考虑(因此水平可扩展性限制)。您是否必须在 Elastic 中管理您的 ACL?或者您可以在外部管理它们并直接引用文档上的主要群体(和个人用户)吗?
  • 存储 acls 将允许在执行查询(而不是后过滤)的同时过滤文档并保持分面和页数不变。在我们的系统中,应用的 ACL 可以是用户/组或两者兼而有之。我已阅读父子文档。我们的用例表明,如果我们将 acl 拆分为 group-child 和 user-child,则父子比例将为 1 比 1,或者每个父节点可能有 2 个子节点。大量的 acl 更新是我们希望将 acl 更新分离到子文档并避免每次仅 acl 更改时都重新索引整个文档的原因

标签: elasticsearch acl


【解决方案1】:

我认为在查询之前扩展组可能会使这过于复杂。在文档索引中保留组标识符如何?

通常,我会在两个索引中表示这一点(没有父子关系,或者根本没有任何类型的嵌套关系)。


用户索引 (示例文档)

{
  "user_id": 12345,
  "user_name": "Swami PR"
  "user_group_ids": [900, 901, 902]
}

文档索引 (示例文档)

{
  "doc_id": 98765,
  "doc_name": "Lunch Order for Tuesday - Top Secret and Confidential",
  "doc_acl_read_users": [12345, 12346, 12347],
  "doc_acl_write_users": [12345],
  "doc_acl_read_groups": [435, 620],
  "doc_acl_write_groups": []
}

用户索引可以很容易地在数据库中...您的应用只需要“Swami's”user_idgroup_ids 在查询文档时可用。

那么,当你以Swami PR查询[Top Secret]文档时,(要阅读),一定要加上:

"should": [
  {
    "term": { 
      "doc_acl_read_users": 12345
    }
  },
  {
    "terms": {
      "doc_acl_read_groups": [900, 901, 902]
    }
  },
  "minimum_should_match": 1
]

我可以在这里看到两种主要类型的更新:

  1. 用户或组在文档上更新:= 在文档索引

  2. 中重新索引一条记录
  3. 用户添加到组/从组中删除:= 在用户索引

  4. 中重新索引一条记录

带有边缘情况

  1. 用户或组已删除

好的,在这里您可能想要批量处理并重新索引所有文档 定期清理过时的用户/组标识符...但是 理论上,陈旧的用户/组标识符不会存在于 应用程序了,所以不要在索引中引起问题。

【讨论】:

  • 我们在对您刚才提到的方法进行基准测试时观察到的问题,一旦术语列表上的组数超过 1000,就会严重扩展。一旦我们在术语列表中达到大约 1000 个组,缩放就会受到巨大影响。还要注意的是,使用外部构建的术语列表的术语查询比从索引本身构建的术语列表更糟糕
  • 我们的文档是 pdfs,docs(大小 3MB ..25MB),因此在主文档上添加 acls 将导致它们每次都被重新索引以进行 acl 更新(最多 100,000 次更新/小时,跨越许多 100,000s文件)。这就是采用子文档 acl 方法以避免重新索引主文档的原因。
  • 一个典型用户属于多少个组? 1000s?文档组的更改速度为 100,000 次/小时?
  • 有多少百分比的用户属于 >1000 个组?在任何给定时间,他们的组 ACL 更改的文档百分比是多少?如果很小,您是否需要为他们优化整个系统?如果很大,那么使用 Redis 之类的东西进行后过滤是否值得额外的实施工作? (我也猜测大部分流量是由直接 User->Doc ACL 滥用产生的......也许只是强制一个仅限组的 ACL 策略会平息索引抖动)
  • 遗憾的是,没有办法平息 User->Doc ACL 滥用,因为它被其中的 10000 名客户使用。属于 1000 个组的用户的百分比是在少数 1000 个中,而不是用户的总子集(几个 100k)。但是这些用户在操作方面执行了很多操作(他们是跨一个/多个文档容器的迷你管理员)
【解决方案2】:

我已经在我的公司实施了方法#2,现在我正在研究一个图形数据库来处理 ACL。一旦我们为一个客户处理了 400 万份文档,更新和搜索查询就变得非常频繁,并且没有按预期扩展。 我建议研究图形框架来解决这个问题。

【讨论】:

    猜你喜欢
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 1970-01-01
    相关资源
    最近更新 更多