Elasticsearch搜索英文或数字时必须写全怎么办?如何实现模糊搜索?

Elasticsearch搜索英文或数字时必须写全怎么办?如何实现模糊搜索?

一、面临问题

用户在商品查询场景下,通过es查询时,用中文能很好查询到数据,英文或数字必须要写全才能查询到

例:存在商品为:opp0 reno4se 5G全网通智能拍照手机65W闪充正品
1:查询"oppo"可以
2:查询"opp"不行
3:查询"reno"不行
4:查询"reno4se"可以

二、原因

当前的索引为

GET good_test_index
{
    "aliases":{

    },
    "mappings":{
        "dynamic":"false",
        "properties":{
            "create_time":{
                "type":"date"
            },
            "id":{
                "type":"keyword"
            },
            "name":{
                "type":"text",
                "fields":{
                    "keyword":{
                        "type":"keyword",
                        "ignore_above":256
                    }
                }
            }
        }
    }
}

索引中name字段,未指定分词器

搜集资料和测试,发现当没有指定分词器时,es默认的分词器为standard分词器

官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/8.0/analysis-standard-tokenizer.html

该分词器基于Unicode 文本分段算法,去除空格和标点符号等,但对于连续的英文,则不会分词,从而导致对其不能模糊搜索

POST _analyze

{
    "analyzer":"standard",
    "text":"测试分词-reno4se"
}
{
    "tokens":[
        {
            "token":"测",
            "start_offset":0,
            "end_offset":1,
            "type":"<IDEOGRAPHIC>",
            "position":0
        },
        {
            "token":"试",
            "start_offset":1,
            "end_offset":2,
            "type":"<IDEOGRAPHIC>",
            "position":1
        },
        {
            "token":"分",
            "start_offset":2,
            "end_offset":3,
            "type":"<IDEOGRAPHIC>",
            "position":2
        },
        {
            "token":"词",
            "start_offset":3,
            "end_offset":4,
            "type":"<IDEOGRAPHIC>",
            "position":3
        },
        {
            "token":"reno4se",
            "start_offset":5,
            "end_offset":12,
            "type":"<ALPHANUM>",
            "position":4
        }
    ]
}

其中中文是单个拆分,故使用中文搜索时没有该问题,但英文搜索由于分词的原因只有输入完整才能匹配

三、es支持的模糊搜索

1. match_phrase

match_phrase query 首先会把 query 内容分词,分词器可以自定义,同时文档还要满足以下两个条件才会被搜索到:

  1. 分词后所有词项都要出现在该字段中(相当于 and 操作)。
  2. 字段中的词项顺序要一致。

2. wildcard:通配符模糊查询

?匹配任意字符

*匹配0个或多个字符

使用wildcard相当于SQL的like,前后都可以拼接*,表示匹配0到多个任意字符加.keyword是要匹配完整的词

GET /test_idx/_search
{
    "size":20,
    "from":0,
    "query":{
        "bool":{
            "should":[
                {
                    "wildcard":{
                        "form_name":"*very*"
                    }
                }
            ]
        }
    }
}

Wildcard 性能会比较慢。如非必要,尽量避免在开头加通配符 ? 或者 *,这样会明显降低查询性能

3. fuzzy

fuzzy搜索技术 通过编辑距离自动将拼写错误的搜索文本,进行纠正,纠正以后去尝试匹配索引中的数据

编辑距离又称 Levenshtein 距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。fuzzy 查询就是通过计算词项与文档的编辑距离来得到结果的。

但是使用 fuzzy 查询需要消耗的资源比较大,查询效率不高,适用于需要模糊查询的场景。

举例如下,使用fuzzy就行百度一样,你输入个“邓子棋”,也能把“邓紫棋”查出来,有一定的纠错能力

4. 正则

虽然正则很好用,但是在实际使用 regexp 搜索时,我们必须记住如下的事项:

  • 避免通配符在前面,比如上面的 .*work。可能以避免使用前导通配符的方式对数据建立索引
  • 通常,使用正则表达式可能会很昂贵
{
    "query":{
        "regexp":{
            "name":"[a-z]*"
        }
    }
}

四、解决问题

从上述可知,wildcard、正则和fuzzy,对于当前场景存在查询效率差的问题,无法采用。

可采用了基于分词器ngram定义自定义分词器,来更好的解决该问题

官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/8.0/analysis-ngram-tokenizer.html

该分词器基于n-ngram,将文本逐字拆分,比如张3w5,会被拆分成张,张3,张3w,3,3w等

可以很好的应对用户模糊搜索的需求


PUT /good_test_index
{
  "settings": {
        "index.max_ngram_diff":10,
        "analysis": {
          "analyzer": {
            "trigram_analyzer": {
              "tokenizer": "trigram_tokenizer",
               "filter":[
                        "lowercase"
                    ]
            }
          },
          "tokenizer": {
            "trigram_tokenizer": {
              "type": "ngram",
              "min_gram": 1,
              "max_gram": 3,
              "token_chars": [
                "letter",
                "digit",
                "punctuation",
                "symbol"
              ]
            }
          }
        }
      },
  "mappings": {
    "properties": {
      "create_time":{
           "type":"date"
      },
      "id":{
            "type":"keyword"
       },
      "name":{
        "type": "text",
        "analyzer": "trigram_tokenizer"
      }
    }
  }
}

再尝试查询发现能正常通过英文数字进行模糊查询了

咨询方案 预约演示                        
(1)
研发专家-道长生研发专家-道长生
上一篇 2024年6月6日 下午4:24
下一篇 2024年6月13日 上午10:57

相关推荐