仅供自己记录使用,不做知道


ES查询踩坑

  • 前言
  • 一、背景和问题描述
  • 二、排查过程
  • 1.ES-mapping创建
  • 2.数据查询
  • 问题解决
  • 结论



前言

本文主要是记录在使用ES过程中中文查词的那些坑


一、背景和问题描述

要求:需要使用ES查询一段长文本,改文本中的一定的词语比例出现在doc中,该doc的内容就需要被查出
结果:使用ik_smart中文分词器分词后系统无法匹配出哪怕是100%相同的结果

二、排查过程

1.ES-mapping创建

1.创建indice PUT indice_example
2.创建对应的type和mapping 
  POST /indice_example/type_1/_mapping
 { "title": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 5000
              }
            }
          }
          }
 3.插入数据(此处只是举例说明)
 PUT //indice_example/type_1/_id:0001
 {"title":"支持公共福利事业,设立100个左右的消防栓"}

2.数据查询

由于是基于文字匹配且需要分词,此处我们使用MATCH作为查询方式,结合bool查询匹配更多条件,后续会单独出文章简述不同的查询方式以及其所使用的场景:

GET /indice_example/type_1/_search
{
  "query": {
    "bool": {
      "must": [{
          "match": {
            "title": {
              "query": "支持公共福利事业,设立100个",
              "operator": "or",
              "analyzer": "ik_smart",
              "prefix_length": 0,
              "max_expansions": 50,
              "minimum_should_match": "80%",
              "fuzzy_transpositions": true,
              "lenient": false,
              "zero_terms_query": "NONE",
              "auto_generate_synonyms_phrase_query": true,
              "boost": 1
            }
          }
        }]
      }
      }
      }
      此处查询结果为空,做了诸多查询,都无效

注意,此处有一个参数为 minimum_should_match,此参数较为重要

比如 “minimum_should_match”:3 ,原文解释是:Indicates a fixed value regardless of the number of optional clauses.
这里要说明一下为什么是optional clauses(翻译为可选的子句)
对于minimum_should_match设置值:

1.minimum_should_match:“3”

无论可选子句的数量如何,都表示固定值.

2.minimum_should_match:“-2”

表示可选子句的总数减去此数字应该是必需的。

3.minimum_should_match:“75%”

表示最少匹配的子句个数,例如有五个可选子句,最少的匹配个数为5*75%=3.75.向下取整为3,这就表示五个子句最少要匹配其中三个才能查到.

4.minimum_should_match:“-25%”

和上面的类似,只是计算方式不一样,假如也是五个子句,5*25%=1.25,向下取整为1,5最少匹配个数为5-1=4.

5.minimum_should_match:“3<90%”

表示如果可选子句的数量等于(或小于)设置的值,则它们都是必需的,但如果它大于设置的值,则适用规范。在这个例子中:如果有1到3个子句,则它们都是必需的,但是对于4个或更多子句,只需要90%的匹配度.

GET /indice_example/type_1/_search
{
  "query": {
    "bool": {
      "must": [{
          "match": {
            "title": {
              "query": "支持公共福利事业,设立100个",
              "operator": "or",
              "analyzer": "standard",
              "prefix_length": 0,
              "max_expansions": 50,
              "minimum_should_match": "80%",
              "fuzzy_transpositions": true,
              "lenient": false,
              "zero_terms_query": "NONE",
              "auto_generate_synonyms_phrase_query": true,
              "boost": 1
            }
          }
        }]
      }
      }
      }
      此时有数据

问题解决

ES在type为text创建和数据写入是会针对写入的文本开始分词,分词结束后创建倒排索引存储
如果不指定分词器,ES会使用默认的分词器 standard处理,standard针对中文是单个字单个字的分词
在查询过程中,如果未指定分词器,使用的也会是standard的(其实如果此处不写,ES会默认的使用Mapping创建锁设置的分词器)
如果重新指定了分词器,会导致分词后无法命中


结论

在ES做中文类查询时,如果需要特定的分词策略,要求此时在Mapping创建阶段就指定出来,否则后续会造成分词不统一无法命中的
并且,一点mapping创建了,也无法去修改分词器,此处需要慎重对待