【问题标题】:Exact Sub-String Match | ElasticSearch精确子串匹配 |弹性搜索
【发布时间】:2020-03-06 20:00:19
【问题描述】:

我们正在将搜索策略从数据库迁移到 ElasticSearch。在此期间,我们需要保留部分搜索类似于以下 SQL 查询的字段的现有功能(包括空格):

SELECT *
  FROM customer
 WHERE customer_id LIKE '%0995%';

话虽如此,我已经阅读了多篇与 ES 相关的文章并实现了上述功能。在上述练习之后,我想出了以下内容:

  1. 我阅读的大部分文章都推荐使用 nGram 分析器/过滤器;因此以下是映射和设置的样子:

注意: customer_id 字段的最大长度为 VARCHAR2(100)。

{
   "customer-index":{
      "aliases":{
      },
      "mappings":{
         "customer":{
            "properties":{
               "customerName":{
                  "type":"text",
                  "fields":{
                     "keyword":{
                        "type":"keyword",
                        "ignore_above":256
                     }
                  }
               },
               "customerId":{
                  "type":"text",
                  "fields":{
                     "keyword":{
                        "type":"keyword",
                        "ignore_above":256
                     }
                  },
                  "analyzer":"substring_analyzer"
               }
            }
         }
      },
      "settings":{
         "index":{
            "number_of_shards":"3",
            "provided_name":"customer-index",
            "creation_date":"1573333835055",
            "analysis":{
               "filter":{
                  "substring":{
                     "type":"ngram",
                     "min_gram":"3",
                     "max_gram":"100"
                  }
               },
               "analyzer":{
                  "substring_analyzer":{
                     "filter":[
                        "lowercase",
                        "substring"
                     ],
                     "type":"custom",
                     "tokenizer":"standard"
                  }
               }
            },
            "number_of_replicas":"1",
            "uuid":"XXXXXXXXXXXXXXXXX",
            "version":{
               "created":"5061699"
            }
         }
      }
   }
}

查询数据的请求如下所示:

{
  "from": 0,
  "size": 10,
  "sort": [
    {
      "name.keyword": {
        "missing": "_first",
        "order": "asc"
      }
    }
  ],
  "query": {
    "bool": {
      "filter": [
        {
          "query_string": {
            "query": "0995",
            "fields": [
              "customer_id"
            ],
            "analyzer": "substring_analyzer"
          }
        }
      ]
    }
  }
}

话虽如此,这里有几个查询/问题:

  1. 假设有 3 条记录带有 customer_id:

0009950011214, 0009900011214, 0009920011214

当我搜索“0995”时。理想情况下,我期待只获得 customer_id: 0009950011214。

但是我将所有三个记录都作为结果集的一部分,我相信这是由于 nGram 分析器及其拆分字符串的方式(注意:minGram:3 和 maxGram:100)。将 maxGram 设置为 100 是为了完全匹配。

我应该如何解决这个问题?

  1. 这就引出了我的第二点。对这种需求使用 nGram 分析器是最有效的策略吗?我担心的是 minGram = 3 和 maxGram = 100 的内存利用率。有没有更好的方法来实现相同的?

P.S:我在 NEST 5.5 上。

【问题讨论】:

    标签: elasticsearch nest


    【解决方案1】:

    在您的 customerID 字段中,您可以传递 "search_analyzer": "standard"。然后在您的搜索查询中删除"analyzer": "substring_analyzer" 行。

    这将确保搜索到的 customerID 不会被标记为 nGrams 并按原样进行搜索,而 customerIDs 则作为 nGrams 进行索引。 我相信这就是您试图从 SQL 查询中复制的功能。

    【讨论】:

    • 感谢 Archit 的回复。但是在进行推荐的更改后,没有返回任何结果;用于部分搜索。
    • 您可以尝试在查询中进行简单匹配而不是 filter:query_string。此外,在您发布的查询中,customerID 的拼写与映射中的字段不同。
    【解决方案2】:

    从映射中我可以看到字段 customerId 是文本/关键字字段。(Difference between keyword and text in ElasticSearch) 因此,您可以使用如下所示的正则表达式过滤器进行搜索,例如您给出的 sql 查询,试试这个 -

    {
     "query": {
        "constant_score": {
          "filter": {
            "bool": {
              "must": [
                {
                  "regexp": {
                                "customerId": {
                                  "value": ".*0995.*",
                                  "flags": "ALL"
                                }
                              }
                }
              ]
            }
          }
        }
      }
    }
    

    注意正则表达式值中的“.”。 ..* 与包含搜索相同 ~(..) 与不包含相同 您还可以在搜索词的开头或结尾附加“.*”以执行 Ends-with 和 Starts-with 类型的搜索。参考-https://www.elastic.co/guide/en/elasticsearch/reference/6.4/query-dsl-regexp-query.html

    【讨论】:

    • 感谢 Soumitra 的回复。与 nGram 相比,您对使用正则表达式过滤器的性能影响的看法只有一个问题。
    • 使用标记器会使索引大小变大,因为您将值分解为标记并存储它们,但是当您使用正则表达式过滤器时不需要发生这样的事情(参考 - stackoverflow.com/questions/17927728/…)但是,除此之外,我不确定在使用令牌或使用正则表达式时搜索查询是否会执行得更快。
    猜你喜欢
    • 1970-01-01
    • 2017-01-09
    • 2015-08-02
    • 2018-08-02
    • 2015-10-07
    • 1970-01-01
    • 2014-08-18
    • 2012-02-01
    • 1970-01-01
    相关资源
    最近更新 更多