Elasticsearch(es)使用termQuery()不能正确搜索到字段内的值

在Elasticsearch 7.4中,使用termQuery搜索String字段时遇到问题,无法得到预期结果。问题源于text字段的分析过程,导致分词后的数据无法精确匹配。解决方案包括利用keyword子字段进行匹配或手动修改mapping以实现不分词处理。

Elasticsearch(es)使用termQuery不能正确搜索到字段内的值

最近在使用es的过程中,发现了一个问题:使用termQuery搜索String类型的字段,无法成功匹配到对应的值。文章的前半部分是重现这个问题,想跳过看解决办法的,请直接进入后半部分。

以下所有内容基于es版本为7.4而作。

问题复现
  1. 首先构建一个索引。
    创建索引

  2. 向索引中添加4条document。
    插入数据

  3. 上图可以看出,已经成功添加了四条记录了。我们先使用match去搜索数据,可以发现搜索结果符合预期(其余两条我隐藏了,否则截图放不下)。

match

  1. 接下去使用termQuery搜索。我们对 address 字段执行termQuery,搜内容为 “杭州西湖”,预期结果应该能搜到 id = 3, address="杭州西湖"的那条记录。但是结果如下,搜索结果为空。

    term

原因分析

为什么会发生上面的这种情况呢?

text & keyword

首先我们看下当前的index的信息
info

我们可以看到,在没有设置mapping的情况下,es自动帮我们识别了插入数据的类型,address被识别成了text类型,且附带了keyword的子字段。

关于textkeyword的区别,我抄了段官网的说法

Text field type
A field to index full-text values, such as the body of an email or the description of a product. These fields are analyzed, that is they are passed through an analyzer to convert the string into a list of individual terms before being indexed. The analysis process allows Elasticsearch to search for individual words within each full text field. Text fields are not used for sorting and seldom used for aggregations (although the significant text aggregation is a notable exception).

If you need to index structured content such as email addresses, hostnames, status codes, or tags, it is likely that you should rather use a keyword field.

Keyword type family

Keyword fields are often used in sorting, aggregations, and term-level queries, such as term.

大致翻译一下,就是前者是分词的,可以用于文本搜索;后者是不分词的,一般就用于精准匹配。

照这么说,我们使用termQuery,搜索词为 “杭州西湖” 时,应该能搜索到id = 3, address="杭州西湖"这条数据啊。又发生了什么导致了搜索不到呢?

analyze

上面说到了address字段会被分词处理,我们看看在不指定分词器的情况下,使用默认分词器,存入数据后,会被分词处理成什么。

analyze

如图,存入中文后,每个字都会被拆开,所以我们在搜索"杭州西湖"的时候,并没有对应的数据能匹配上,自然就搜索不出结果了。此时想要搜索到,应该搜这四个字中的任意一个字,都能得到搜索结果,但得到的搜索结果并不是我们想要的精确匹配啊?如何才能在搜索中文时,精确匹配的搜索到想要的内容呢?

解决办法
方案一:不破坏es帮我们自动生成的mapping,我们使用其中的keyword去做匹配

我们上面在介绍address被识别成text类型,还说到了附带了keyword的子字段。而keyword是不会分词的,那么可以利用这个附带的keyword的子字段来实现精确匹配。

keyword term query

方案二:手动设置mapping,让我们要搜索的字段不分词处理

上面说到了未设置mapping的情况下,es自动帮我们识别了各个字段的类型,生成了mapping,其实我们也可以手动干预生成mapping这件事,我们指定address字段类型为keyword

我们是否可以更新刚才这个 indexmapping来实现我们要的目的呢?官网给出了这样的回答

Update the mapping of a field

Except for supported mapping parameters, you can’t change the mapping or field type of an existing field. Changing an existing field could invalidate data that’s already indexed.

If you need to change the mapping of a field in a data stream’s backing indices, see Change mappings and settings for a data stream.

If you need to change the mapping of a field in other indices, create a new index with the correct mapping and reindex your data into that index.

Renaming a field would invalidate data already indexed under the old field name. Instead, add an alias field to create an alternate field name.

也就是说,对于已经存在的mapping,是无法直接更改的,我们应该新建一个index并设置好mapping
set mapping

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值