【问题标题】:Supporting query on dynamic columns in elastic search支持对弹性搜索中的动态列的查询
【发布时间】:2016-04-06 00:36:31
【问题描述】:

我需要在弹性搜索中支持对动态(非预定义)标签的查询。假设我有一个博客文档并希望支持对不同列集的查询,即 tagTypeA=valueX & tagTypeB=ValueY 并且这些 tagTypeX 列事先不知道。这些标签中的每一个都只有一个值。用户会将这些附加数据作为 Map String::String 传递给我的 API(没有严格的模型/结构)。我还需要支持对这些标签列的聚合查询。

我正在考虑支持此功能的三种方法。

  1. 声明每个文档最多只能支持 N 种动态标签(比如 10 个),并创建内部列,例如 Tag1、Tag2 ... Tag10。现在有一个配置来维护 TagTypeA=Tag1、TagTypeB=Tag2 等的映射。在代码中,迭代输入键值对并使用键到列名的映射动态生成 ES 搜索查询。

优点:易于实施

缺点:维护映射的开销。每次加入新类型的文档/客户端/必须为现有客户端添加新字段时,都必须对此进行修改。

  1. 在 ES 中使用字符串数组创建一个未分析的字段。存储数据时,以key+"Delimiter"+value的串联格式存储。因此,如果输入映射有 TagTypeA=Good & TagTypeB=High,那么这将在 ES 中存储为 ["TagTypeA-Good","TagTypeB-High"]。当用户查询时,构造回联系的字符串并搜索它们。

优点:无需更改代码即可加入新客户端/添加或更新新字段

缺点:首先,它听起来不干净。密钥不应该有分隔符。稍后更改映射非常繁琐,因为我们必须更改所有现有字符串值的值。

  1. 不要定义任何模式,让标签的 json 键值对传递给弹性搜索 PUT 调用。对于尚未存在的任何新键,弹性搜索将自动将其添加到具有默认类型推断的索引中(使用动态模板控制,并限制所有字段名称应以特定前缀开头)。

优点:无需配置或手动连接输入。无需任何手动操作即可透明地处理任何添加的列。

缺点:我相信这会有一些缺点。但是想不出具体的东西。请建议?我能想到的一个缺点是,由于字段名称被忽略,任何一个滥用的客户端都可能膨胀索引,这可能会由于大量字段而导致整个集群崩溃,除非我们有一个手动注册和批准的工作流程这些字段存储在单独的数据库中。还有什么缺点吗?

我个人正在考虑与选项 #3 保持一致。

任何人都可以分享您对上述三种方法的看法,以及是否有更好的方法来解决这个问题。

谢谢, 哈里什

【问题讨论】:

    标签: search elasticsearch


    【解决方案1】:

    我的直觉也告诉我,选项 #3 是最可行的选项。使用动态模板来配置可能出现的新标签是一个好方法。

    由于这些总是名为 TagTypeX 的标签,因此很容易将动态模板配置为始终存储 not_analyzed 值,没有理由说“可能并不总是符合要求”,标签就是标签不应该以不同的方式搜索它们。如果是这种情况,您将需要其他字段类型。

    就我个人而言,我认为这种方法没有太多缺点。它既灵活又不断发展,不会像其他选项那样仅仅基于技术原因而混淆标签数据。

    选项 1 显然会增加太多开销,以防您有新标签,并且还会无缘无故限制标签的数量(从用户的角度来看,技术原因不是正当理由)。

    选项 2 维护起来很麻烦,而且正如您所说的那样,它并不干净。

    可能还有其他选项,但这取决于您构建查询的方式(即查询 DSL 或只是 URL 中的查询字符串查询),所以我暂时不会深入探讨。

    【讨论】:

    • 如果我强制所有键都应该以 TagType 前缀开头,那么是的,动态模板应该符合要求。如果我使用#3 选项,似乎有这个前缀限制的正确方法
    • 但是我后来意识到 #3 的另一个缺点,因为密钥现在在世界上保持开放,如果任何客户端通过每次创建新密钥来滥用,那么它会在一个下创建很多列索引,并且可能由于一个错误的客户端而导致整个集群崩溃。一种方法是预先注册每个客户允许的字段并批准它们。在每次查询时,检查密钥是否存在于这个预先注册的列表中。这将防止此问题,但需要开发和监控 UI 或工作流。您对此有何看法?有什么更好的方法吗?
    • 通过在索引中创建太多字段来破坏集群...在这种情况发生之前您还有很长的路要走。我见过包含数千个字段的文档,而 ES 不会让步。我不会太担心这个。最后,您需要问自己,关闭他正在使用的软件是否符合客户的利益。此外,如果创建的标签过多,您可以使用渗滤器发出警报,但我怀疑它是否会发生。
    • 我的另一个想法是选项 2 和 3 之间的混合,即有一个 tags: [{name,value}] 数组,因此您只需要真正创建一个字段,并且标签将填充在该数组中。但是,如果您走那条路,则数组需要为nested
    • 哦,那么如果我们谈论聚合,映射设计是最重要的,选项#3(有或没有我建议的nested 设计)显然是你唯一的选择,如果您想生成有意义的聚合数据。我建议您尝试一下,然后针对您将遇到的更具体的问题提出更具体的问题,因为这个问题是一个非常笼统的问题,因此,我认为它已得到解答。
    猜你喜欢
    • 2015-09-19
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-05
    • 2014-06-22
    • 1970-01-01
    相关资源
    最近更新 更多