【问题标题】:How to perform fast exact-match searches in elasticsearch如何在弹性搜索中执行快速精确匹配搜索
【发布时间】:2015-07-01 16:15:11
【问题描述】:

假设我在用户/数据中有一个用户对象:

{"_id": 123, "name": "Bob"}

并且用户有多个宠物,宠物文档如下所示:

{"_id": 1423, "owner": 123, "type": "cat", "name": "Prince McNugget"}
{"_id": 1830, "owner": 123, "type": "dog", "name": "Tarley"}

在弹性搜索中执行快速(即索引)搜索以查找所有者为 123 的所有宠物文档的正确方法是什么(或什么是好的选择)?

我已阅读“完全匹配”问题的答案,该问题建议使用字段为“not_analyzed”的映射,但我假设“not_analyzed”字段未编入索引,因此数据库必须执行类似于全表扫描的操作(我在这里与 SQL 进行比较)才能得出结果。这对我来说是不可接受的 - 我需要它是一个索引搜索。

【问题讨论】:

  • 这将是一个索引搜索。我相信未分析意味着该值未标记化并以多种方式存储索引(例如“new york”->“new”和“york”)。
  • 这对您有用吗?如果它对您有用,您应该接受答案,如果您想了解更多信息,请发表评论。
  • 我有点脱离弹性搜索游戏了,我没有时间在一个我不再需要解决的问题上来回折腾。下次我使用弹性搜索时,我可能会回到这里

标签: elasticsearch


【解决方案1】:

您可以在宠物上使用term queryhttp://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-term-query.html

{
  "query": {
    "term" : { "owner" : 123 }
  }
}

在 ES 中,除非您配置不对其进行索引,否则所有内容都会被索引,因此默认情况下应该很快。

编辑:“not_analyzed”正如 mcollin 解释的那样。它只是告诉 ES 不要分析数据(保留我们传递的数据),除非你指定 "index" : "no",否则它仍然会被索引。

【讨论】:

    【解决方案2】:

    我会假设“not_analyzed”的字段没有被索引

    这是一个很容易做出的假设,但也是一个错误的假设。在 ES 中,'not_analyzed' 表示该字段中的数据未拆分为标记(分析)。数据仍然被大量索引。

    在 ES 中搜索最快的方法是使用filters。从第一个查询 DSL 页面:

    过滤器非常方便,因为它们的执行性能比普通查询好一个数量级,因为不执行评分并且它们会自动缓存。

    由于过滤器要快得多,所以最快的查询几乎总是过滤后的查询:

    {
        "query": {
            "filtered": {
                "query": { 'match_all' : { } },
                "filter": {
                    { "term": { "owner": 123 }}
                }
            }
        }
    }
    

    Filtered Query 页面所述,过滤查询的默认查询是match_all,因此该查询可以进一步缩短为:

    {
        "query": {
            "filtered": {
                "filter": {
                    { "term": { "owner": 123 }}
                }
            }
        }
    }
    

    过滤器的限制是它们是布尔值。文档要么完全匹配过滤器,要么不匹配。为提高性能,建议尽可能使用过滤器进行约束,然后使用查询进行进一步匹配。

    我已经构建了一个查询构建器,它解析 HTML 表单,然后提交搜索参数。构建器检查每个搜索参数中的通配符(? 或 *),如果存在,则使用通配符查询。如果没有,它会添加一个过滤器。我提供 UI 按钮,使用户可以通过单击数据轻松执行精确搜索。当他们使用这些时,搜索会命中过滤器并且速度很快。他们还可以输入string* 并在等待几毫秒后得到他们想要的。

    这是我的查询生成器的通用 sn-p:

    var filters = [], queries = [];
    var searchVal = ..., searchField = ...;
    
    var getWild = function (field, val, boost) {
        var wc = { wildcard: { } };
        wc.wildcard[field] = { value: val, boost: (boost || 1) };
        return wc;
    };
    
    if (searchVal) {
        if (/\*|\?/.test(searchVal)) {
            queries.push(getWild(searchField, searchVal);
        }
        else {
            filters.push({ term: {searchField: searchVal}});
        }
    }
    

    我使用And 过滤器来约束所有完全匹配(日期范围、uid 约束等),然后将其余查询作为filtered -> bool 查询。它运行得非常好,而且我的包含 133,000,000 个文档的小型 3 节点 ES 集群已经足够快了。

    【讨论】:

    • 关于过滤器的信息很棒!
    • 考虑到它是“如何在 elasticsearch 中执行快速精确匹配搜索”问题的正确答案,您还需要什么答案才能接受它?
    • 我想尝试一下并确保它有效。鉴于我不再使用 ES,我不确定什么时候可以使用它。
    • 如果它得到大量的赞成票,我可能也会接受它
    【解决方案3】:

    对于您的用例,es 的relational features 很有趣。这些允许查询,例如has_parent,您可以在其中搜索确切的ID。除此之外,提到的term query 是正确的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-09
      • 2020-03-06
      • 2015-08-02
      • 1970-01-01
      • 2019-02-11
      • 2013-08-15
      • 2014-08-18
      • 2017-08-30
      相关资源
      最近更新 更多