写点什么

es 笔记三之 term,match,match_phrase 等查询方法介绍

作者:Hunter熊
  • 2023-07-01
    北京
  • 本文字数:3396 字

    阅读完需:约 11 分钟

es笔记三之term,match,match_phrase 等查询方法介绍

本文首发于公众号:Hunter 后端

原文链接:es笔记三之term,match,match_phrase 等查询方法介绍


首先介绍一下在 es 里有两种存储字符串的字段类型,一个是 keyword,一个是 text。


keyword 在存储数据的时候是作为一个整体存储的,不会对其进行分词处理


text 存储数据的时候会对字符串进行分词处理,然后存储。


而对于查询方法, term 是精确查询,match 是模糊查询。


接下来我们用几个例子,来分别表达下这两种类型的字段,使用 term,match,match_phrase 等搜索的情况。


  1. 测试搜索 keyword

  2. 测试搜索 text

  3. match 的其他用法

  4. multi-match 搜索


首先我们创建这样一个 index 和下面几条数据:


PUT /exam
PUT /exam/_mapping{ "properties": { "address": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "name": { "type": "keyword" } }}
复制代码


我们创建了 name 字段为 keyword,address 字段是 text,接下来我们先创建几条数据来测试 keyword 字段类型的搜索。

1、测试搜索 keyword

写入数据:


PUT /exam/_doc/1{    "name" : "hunter x",    "address": "i study english"}
PUT /exam/_doc/2{ "name" : "python x", "address": "this is python x"}
PUT /exam/_doc/3{ "name" : "hunter python", "address": "i live in china"}
PUT /exam/_doc/4{ "name" : "hunter java", "address": "read a book"}
PUT /exam/_doc/5{ "name" : "java golang python", "address": "you can get a good job"}
PUT /exam/_doc/6{ "name" : "js python", "address": "wanna go out to play"}
复制代码


name 字段类型为 keyword,所以它存储的时候是以整体来存储的。


接下来介绍这几种查询方式查询 name 字段的操作。


term


精确查找,对于搜索的内容也是直接整体查找,也就是说搜索什么内容就查询什么内容。


比如对于我们写入的 id=2 的数据,要想查 name='python x' 的数据,就需要查询的字符串和结果完全匹配才可返回,比如下面的操作操作:


GET /exam/_search{  "query": {    "term": {      "name": {        "value": "python x"      }    }  }}
复制代码


match


match 的操作是将搜索的内容进行分词后再查询,比如我们 match 的参数是 python x,那么分词后的结果是 pythonx,但是 keyword 类型的字段数据不会分词,所以也需要能够完全匹配才能查询得到,所以这里就会去查找 name 字段里只包含了 python 和 x 的数据。


GET /exam/_search{  "query": {    "match": {      "name": "python x"    }  }}
复制代码

2、测试搜索 text

前面的 keyword 类型的字段搜索需要把握的是完全一样就行,而对于 text 字段的搜索,text 字段的内容在写入 es 时本身会被分词处理,所以搜索 text 的处理并不完全一样。


在这里,我么用的 address 字段是 text 类型,我们还是用前面的示例作为演示。


term


term 的搜索是不分词的,搜索给定字符串的全部内容,比如对于我们插入的 id=4 的那条数据,address 的内容是 read a book,它被分词为三个,read、a、book,所以我们使用 term 方法搜索下面三个都可以搜到这条数据:


GET /exam/_search{"query": {"term": {"address": "read"}}}
GET /exam/_search{"term": {"address": "a"}}
GET /exam/_search{"term": {"address": "book"}}
复制代码


但是,如果我们 address 后面的值如下这种就搜索不到了,因为 term 操作并不会给搜索的内容进行分词,而是作为一个整体进行搜索:


GET /exam/_search{"query": {"term": {"address": "read a"}}}
GET /exam/_search{"query": {"term": {"address": "a book"}}}
GET /exam/_search{"query": {"term": {"address": "read a book"}}}
复制代码


但是还有一种情况,那就是对于搜索的 text 字段后加上 .keyword 字段的操作,这个相当于将 address 不分词进行搜索,将 address 这个字段看作是一个 keyword 来操作,可以理解成是使用 term 来搜索 keyword 字段,就是上一个类型的操作。


所以下面的这个操作就是可以搜索到 address='read a book' 的数据


GET /exam/_search{"query": {"term": {"address.keyword": "read a book"}}}
复制代码


match


match,模糊匹配,在匹配前会将搜索的字符串进行分词,然后将匹配上的数据按照匹配度(在 es 里有一个 _score 字段用于表示这种匹配程度)倒序返回。


比如我们对 address 字段搜索字符串 a,会返回两条数据,id 为 4 和 5 的,因为 address 字段进行分词存储后都包含这个字符串。


GET /exam/_search{"query": {"match": {"address": "a"}}}
复制代码


或者我们搜索内容为 read a,match 搜索会先将其分词,变成 reada,然后匹配分词后包含这两个字符串一个或者两个的数据,在这里也会返回两条,一条的结果是 read a book,一条是 you can get a good job,因为这两条数据都包含字符串 a,但是因为前者分别满足了两个搜索的条件,所以前者的匹配度会更高,所以作为第一条数据返回:


GET /exam/_search{"query": {"match": {"address": "read a"}}}
复制代码


match_phrase


匹配短语,使用这个方法不加其他参数的情况下,可以看作是会匹配包含这个短语、且顺序一致的数据。


比如说对于 address="read a book" 的数据,搜索 read aa bookread a book 都可以筛选到这条数据。


GET /exam/_search{"query": {"match_phrase": {"address": "read a"}}}
GET /exam/_search{"query": {"match_phrase": {"address": "a book"}}}
GET /exam/_search{"query": {"match_phrase": {"address": "read a book"}}}
复制代码


但是如果搜索 book a,因为顺序不一致,所以下面的搜索是无法搜素到该数据的:


GET /exam/_search{"query": {"match_phrase": {"address": "book a"}}}
复制代码


但是 match_phrase 有一个 slop 参数可以用于忽略这种顺序,也就是允许搜索的关键词错位的个数,比如 'book a',分词后的 'book' 和 'a' 如果允许错位两个顺序(a 往前挪一个,book 往后挪一个,这是我理解的 slop 的操作用法),那么就可以筛选到我们这条数据,示例如下:


GET /exam/_search{  "query": {    "match_phrase": {      "address": {        "query": "book a",        "slop": 2      }    }  }}
复制代码


match_phrase_prefix


匹配前缀,比如对于 address 值为 'read a book' 的数据,我们只知道的值是 'read a bo',想要根据这个搜索词搜索完整的数据,就可以用到 match_phrase_prefix。


他的用法是这样的,先将检索词分词,然后将最后一个分词结果单独去匹配,所以这个搜索词的过程就是先根据 'read a' 的分词结果搜索到一些数据,然后根据剩下的 'bo' 去匹配满足这个前缀的数据:


GET /exam/_search{"query": {"match_phrase_prefix": {"address": "read a bo"}}}
复制代码

3、match 的其他用法

匹配分词后的全部结果

对于 match,前面我们介绍过会先将搜索的字符串分词,然后去筛选包含分词结果一至多个的结果。


比如前面介绍的搜索 'read a',会搜索出 'read a book' 以及 'you can get a good job',因为他们都包含分词的结果 'a',这种操作就类似于用 should 去对分词结果进行进一步的搜索操作,


但是如果我们想要更精确,搜索的内容必须包含分词的全部结果 'read' 和 'a',我么可以加上 operator 参数:


GET /exam/_search{  "query": {    "match": {      "address": {        "query": "read a",        "operator": "and"      }    }  }}
复制代码


这样操作结果就是筛选了包含全部搜索词分词后结果的数据。

匹配的模糊处理

我们可以通过 fuzziness 字段来打开字符模糊匹配的开关,最简单的一个例子就是比如我们搜索 'read',打字不小心打成了 'raed',这种就可以实现他的模糊匹配:


GET /exam/_search{  "query": {    "match": {      "address": {        "query": "raed a",        "operator": "and",        "fuzziness": 1      }    }  }}
复制代码

4、multi-match 搜索

前面我们的 match 参数操作的都是针对于单个字段,multi_match 则可以针对于多个字段进行 match 操作,这个需要都能匹配上搜索的关键字,使用示例如下:


GET /exam/_search{  "query": {    "multi_match": {      "query": "python",      "fields": ["name", "address"]    }  }}
复制代码


其中,fields 是一个数组,里面是需要搜索的字段。

发布于: 刚刚阅读数: 4
用户头像

Hunter熊

关注

公众号:Hunter后端 2018-09-17 加入

Python后端工程师,欢迎互相沟通交流

评论

发布
暂无评论
es笔记三之term,match,match_phrase 等查询方法介绍_elasticsearch_Hunter熊_InfoQ写作社区