Elasticsearch使用正则表达式匹配中文字符串结果为空集 es正则表达式查不到结果

问题描述

在我测试es数据库正则表达式的语法时,发现中文字符串始终识别不到,找到可以识别的表达式是.* 这让我百思不得其解

原因分析

究其原因:其实离不开elasticsearch数据库的原理——倒排列表,什么意思呢?假设我们存储一句话,那么,es数据库中的分词器会对这句话进行分词,然后将这些Token存入倒排列表。

  • 举个例子来说,对于*“我真的好美丽”*这句话来说,分词器会将它识别为什么呢?

    • 其实与分词器的选择有关,对于ES默认的分词器,会识别成下面这种格式

      {
              
              
          "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": "美",
                  "start_offset": 4,
                  "end_offset": 5,
                  "type": "<IDEOGRAPHIC>",
                  "position": 4
              },
              {
              
              
                  "token": "丽",
                  "start_offset": 5,
                  "end_offset": 6,
                  "type": "<IDEOGRAPHIC>",
                  "position": 5
              }
          ]
      }
      

      你会发现,居然全是一个一个的单字!

  • 而有了分词,es便将这些token做成了倒排列表,当你用正则表达式的文法严格搜索“我真的好美丽"时,会发现得到的结果是空集, 为什么这样答案可能你已经猜到了:因为正则表达式的文法过于严格,它严格地去匹配符合其文法规则的字符串,但是,es数据库的倒排索引中只有一个个的中文单字,找了一圈,它说,我没有找到这样的一句话,于是返回了空集。

问题解决

需要重建一个索引(数据库),并且在建立时指定使用的分词器

PUT website
{
    
    
    "mappings": {
    
    
            "properties": {
    
    
                "user_id": {
    
     "type": "text" ,
                            "analyzer": "ik_max_word" , //对应 IK 的 ik_max_word 和 ik_smart 两种分词策略 也可以不写,不写则默认
                            "search_analyzer": "standard" //查询时使用的分词器
                           },
            	  "name": {
    
    
                    "type": "text",
                    "analyzer": "english"
                },
                "age": {
    
     "type": "integer" },
                "sex": {
    
     "type": "keyword" },
                "birthday": {
    
    
                    "type": "date", 
                    "format": "strict_date_optional_time||epoch_millis"
                },
                "address": {
    
    
                    "type": "text",
                    "index": false         // 不分词
                }
            }
    }
}

这样,我们更换了一种分词器ik_max_word,我们来看一下它对这句话的分词结果

{
    
    
    "tokens": [
        {
    
    
            "token": "我",
            "start_offset": 0,
            "end_offset": 1,
            "type": "CN_CHAR",
            "position": 0
        },
        {
    
    
            "token": "真的",
            "start_offset": 1,
            "end_offset": 3,
            "type": "CN_WORD",
            "position": 1
        },
        {
    
    
            "token": "好美",
            "start_offset": 3,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 2
        },
        {
    
    
            "token": "美丽",
            "start_offset": 4,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 3
        }
    ]
}

有朋友可能会问:你这样也解决不了我们的需求呀? 这不是还没有我们要求的完整字段吗?

确实如此,所以就要求我们去寻找适合的分词方法,甚至自己来构造

对于本例而言,我们可以使用sample分词器,它是ES原生的分词器,不会将任何的中文字符拆开,因此可以满足我们的需求。

扫描二维码关注公众号,回复: 16982382 查看本文章

推荐阅读:

  1. 了解分词器是什么,有哪些分词器
  2. 映射mapping是什么

猜你喜欢

转载自blog.csdn.net/Zilong0128/article/details/120954153