elasticsearch 实战三部曲之三:搜索操作
欢迎访问我的 GitHub
这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
本文是《elasticsearch 实战三部曲》的终篇,作为 elasticsearch 的核心功能,搜索的重要性不言而喻,今天的实战都会围绕搜索展开;
环境信息
本次实战用到的 elasticsearch 版本是 6.5.4,安装在 Ubuntu 16.04.5 LTS,客户端工具是 postman6.6.1;
如果您需要搭建 elasticsearch 环境,请参考《Linux环境快速搭建elasticsearch6.5.4集群和Head插件》;
基本情况介绍
本次实战的 elasticsearch 环境以及搭建完毕,是由两个机器搭建的集群,并且 elasticsearch-head 也搭建完成:
一号机器,IP 地址:192.168.119.152;
二号机器:IP 地址:192.168.119.153;
elasticsearch-head 安装在一号机器,访问地址:http://192.168.119.152:9100
已经建立了索引 englishbooks,对应的数据如下所示,请用批量命令导入到 elasticsearch:
相关的文档是批量导入的,关于文档数据和批量操作的细节请参考《elasticsearch实战三部曲之二:文档操作》;
books 索引的文档内容在 head 中展示如下图:
数据格式说明
为了便于和读者沟通,我们来约定一下如何在文章中表达请求和响应的信息:
假设通过 Postman 工具向服务器发送一个 PUT 类型的请求,地址是:http://192.168.119.152:9200/test001/article/1
请求的内容是 JSON 格式的,内容如下:
对于上面的请求,我在文章中就以如下格式描述:
读者您看到上述内容,就可以在 postman 中发起 PUT 请求,地址是"test001/article/1"前面加上您的服务器地址,内容是上面的 JSON;
本文中的文档内容暂不涉及中文
文中数据都是英文的,避免在因分词器的分词问题导致搜索不到对应的中文结果,分词器相关的知识会在另一篇文章中详细介绍;
查看所有数据
上述查询返回索引 books 的所有记录,并且文档得分收是 1;
您可以将请求的整个 JSON 删除,只用 books/_search 这个 URL 来试试,也能得到所有数据,这是 match_all 的简写;
数字字段的精确匹配
查询价格等于 549 的记录:
得到结果:
请求参数中使用了 constant_score 后,查询将以非评分模式来执行 term,并以一作为统一评分;
查看分词效果
text 类型的字段会被分词后构建倒排索引,来看看 title 字段的值为"Core Java"时的分词效果:
响应如下所示,"Core Java"被分"core"和"java"两个词,也就是说我们以词项"core"或"java"搜索 title 字段都能收到对应文档:
需要注意的是分词后的结果都是小写,这是分词器的处理结果;
词项查询(term query)
前面我们查看分词效果发现"Core Java"被分"core"和"java"两个词,现在就以"java"为关键词搜索一下试试:
结果如下,title 中有 java 关键词的两个文档都被搜到:
分词查询(match query)
term query 的特点是将输入的内容作为一个词项来用,例如以下的查询是没有结果的:
上述查询没有结果的原因,是因为"core java"被当做一个词项去查询了,而 title 的分词结果中只有"core"、"java"这些分词过的词项,并没有一个叫做"core java"的词项,所以搜不到结果;
如果输入的查询条件"core java"也被做一次分词处理,再把处理结果"core"和"java"用来搜索,应该就能得到结果了,match query 就是用来对输入条件做分词处理的,如下:
搜索结果如下,包含了 java 的两条记录都被查出来了:
如果我们的本意是只要"Core Java"的匹配结果,上面的结果显然是不符合要求的,此时可以给查询条件加个**"operator":"and"**属性,就会查询匹配了所有关键词的文档,注意 json 的结构略有变化,以前 title 的属性是搜索条件,现在变成了一个 json 对象,里面的 query 属性是原来的搜索条件:
这次的搜索结果就是同时匹配了"core"和"java"两个词项的记录了(为什么 core 和 java 是小写? 因为"Core Java"被分词后改为了小写,再去搜索的):
match_phrase 搜索
match_phrase 搜索和前面的 match 搜索相似,并且有以下两个特点:
分词后的所有词项都要匹配上,也就是前面的**"operator":"and"**属性的效果;
分析后的词项顺序要和搜索字段的顺序一致,才能匹配上;
上述查询可以搜索到结果,但如果将"Core Java"改成"Java Core"就搜不到结果了,但是 match query 用"Java Core"是可以搜到结果的;
match_phrase_prefix 搜索
match_phrase_prefix 的功能和前面的 match_phrase 类似,不过 match_phrase_prefix 支持最后一个词项做前缀匹配,如下所示,"Core J"这个搜索条件用 match_phrase 是搜不到结果的,但是 match_phrase_prefix 可以,因为"J"可以作为前缀和"Java"匹配:
multi_match 搜素
multi_match 是在 match 的基础上支持多字段搜索,以下查询就是用"1986"和"deep"这两个词项,同时搜索 title 和 description 两个字段:
响应如下,可见 title 和 description 中含有词项"1986"或者"deep"的文档都被返回了:
terms query
terms 是 term 查询的升级,用来查询多个词项:
响应如下,title 中含有 deep 和 core 的文档都被查到:
范围查询
range query 是范围查询,例如查询 publish_time 在"2016-01-01"到"2016-12-31"之间的文档:
篇幅所限,此处略去返回结果;
exists query
exists query 返回的是字段中至少有一个非空值的文档:
前缀查询
用于查询某个字段是否以给定前缀开始:
以上请求可以查到 title 字段为"Core Java"的文档:
通配符查询
以下查询,可以搜到 title 字段中含有"core"的文档,另外需要注意的是,"?"匹配一个字符,"*"匹配零个或者多个字符:
正则表达式
使用属性 regexp 可以进行正则表达式查询,例如查找 description 字段带有 4 位数字的分词的文档:
查找结果如下,description 字段中带有数字 1986:
模糊查询(fuzzy query)
fuzzy 是通过计算词项与文档的编辑距离来得到结果的,例如查找 description 字段还有分词"1986"的时候,不小心输入了"1987",通过 fuzzy 查询也能得到结果,只是得分变低了,请求内容如下所示:
搜索到的文档如下所示,得分只有 0.5942837,低于用"1986"查询的 0.79237825:
需要注意的是,fuzzy 查询时消耗资源较大;
复合查询
常用到的复合查询是 bool query,可以用下表中的条件组合查询:
以下条件,搜索的是 title 中带有 java,但是不包含 core 的文档:
得到的文档中,带有 core 词项的已经被过滤了:
脚本查询
可用脚本进行查询,如下是查询价格大于 100 的所有文档:
得到的结果只有 price 大于 500 的文档:
指定排序字段
默认的排序方式是按照评分来排序的(也就是相关度排序),可以用 sort 属性来设置排序字段,下面的请求指定了按照 price 字段降序排序:
得到结果:
以上就是常用的搜索操作了,至此,《elasticsearch 实战三部曲》系列就全部完成,三篇文章列举的是一些常用的基本操作,希望能帮助读者您快速熟悉 elasticsearch,后面咱们再一起深入实战;
欢迎关注 InfoQ:程序员欣宸
版权声明: 本文为 InfoQ 作者【程序员欣宸】的原创文章。
原文链接:【http://xie.infoq.cn/article/3ea8ebedb20d345a9844b4a7e】。文章转载请联系作者。
评论