确切的子字符串匹配|弹性搜索

时间:2019-11-11 05:53:52

标签: elasticsearch nest

我们正在将搜索策略从数据库迁移到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。

2 个答案:

答案 0 :(得分:0)

从映射中,我可以看到字段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

答案 1 :(得分:0)

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

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