本文共 5156 字,大约阅读时间需要 17 分钟。
Search API 实现了对es中存储的数据进行查询分析,endpoint为 _search
第一种是对es中所有的数据进行查询
第二种是对指定的index查询 第三种是对多个index同时查询 第四种是对指定通配符的index进行查询
操作简便,方便通过命令进行测试,仅包含部分查询语法
这种方式适合做命令行的测试
es提供的完备查询语法 Query DSL
URI Search就是通过拼接关键字来进行搜索的。
PUT test_search_index{ "settings": { "index": { "number_of_shards": "1" } }}
POST test_search_index/doc/_bulk{ "index": { "_id": "1" }}{ "username": "alfred way", "job": "java enginner", "agr": 18, "birth": "1999-1-1", "isMarried": false}{ "index": { "_id": "2" }}{ "username": "alfred", "job": "java senior and java test", "age": 29, "birth": "1989-1-1", "isMarried": true}{ "index": { "_id": "3" }}{ "username": "lee", "job": "java senior and ruby test", "age": 10, "birth": "2010-1-1", "isMarried": false}{ "index": { "_id": "4" }}{ "username": "alfred jr way", "job": "ruby test", "age": 1, "birth": "2019-1-1", "isMarried": false}
// 在所有字段中,只要包含alfred的字段的文档就返回GET test_search_index/_search?q=alfred
GET test_search_index/_search?q=alfred{ "profile": true}
一般用来做查询语句调优
// 只返回username字段包含alfred的文档GET test_search_index/_search?q=username:alfred
如果指定的关键字为下面的情况:
GET test_search_index/_search?q=username:alfred way
它表示返回username包含alfred或者所有字段匹配到way的文档,所以返回的结果和上面一样,通过查看具体查询过程可以看出来
// 需要在查询的词语上添加双引号GET test_search_index/_search?q=username:"alfred way"
// 通过添加括号表示匹配username为alfred或way字段的文档GET test_search_index/_search?q=username:(alfred way)
这个和之前指定字段查询的区别是,在查询中只会匹配username为alfred或username为way的字段,而不会做泛查询。
GET test_search_index/_search?q=username:alfred AND way
但是这样写表示返回匹配到username为alfred,泛查询全部字段匹配到way的文档。
想要返回只匹配username字段匹配到alfred和way的文档就加一个括号:
GET test_search_index/_search?q=username:(alfred AND way)
这里由于先前文档录入的时候没能体现这点的区别所以两种查询语句的结果相同,但是在实际中很大可能两种语句的查询结果是不同的。
// 返回username中不要有way但是可以由alfred的文档GET test_search_index/_search?q=username:(alfred NOT way)
然后看一下 + 的情况:
// 返回username中可以由alfred但必须有way的文档GET test_search_index/_search?q=username:(alfred +way)
可以看到最后一个文档并不符合我们的预期,因为在html中,加号被解析为空格,所以需要使用%2B代替加号
// 返回username中可以由alfred但必须有way的文档GET test_search_index/_search?q=username:(alfred %2Bway)
// 查询username包含alfred或age大于20的文档GET test_search_index/_search?q=username:alfred age:> 20
// 查询username包含alfred且age大于18的文档GET test_search_index/_search?q=username:alfred AND age:>18
// 查询birth在1980到2000之间的文档GET test_search_index/_search?q=birth:(>1980 AND <2000)
// 查询username以 alf来头的所有的文档GET test_search_index/_search?q=username:alf*
// 匹配 [a]?l.* 这个正则匹配到的所有文档GET test_search_index/_search?q=username:/[a]?l.*/
正则表达式匹配也比较吃内存,所以在文档数较多的时候应减少使用正则匹配
// 查询与alfed有N个单位偏差的文档,波浪线后边的数字表示允许偏差的个数GET test_search_index/_search?q=username:alfed~1GET test_search_index/_search?q=username:alfedGET test_search_index/_search?q=username:alfd~2
这样可以做到当用户误输入的时候也能查询到正确信息
词语查询也可以做到相似度查询:
GET test_search_index/_search?q=job:"java test"~1
这个表示允许在java test中间增加1个词语
如果是增加三个单词:
GET test_search_index/_search?q=job:"java test"~3
Request Body Search 就是将 http request body 发送到es,主要参数如下:
这是一个基于 JSON 定义的查询语言,主要包含两种类型:
字段查询:如 term、match、range等,只针对某一字段进行查询
复合查询:如bool查询等,包含一个或多个字段类查询或复合查询语句
字段类查询主要包含下面的两类:
这个语句就表示返回包含alfred或way的文档。
在前面的查询中待查询语句满足其中的一个即可,es提供了一个参数用来表示查询语句匹配关系:
这个例子中就表示必须同时包含alfred和way
还有一个参数用于控制需要匹配的单词数:
这个例子就表示:至少包含查询语句中的2个term才能匹配。
在match query流程中,汇总的分的过程是es根据内部的相关性算分算法(TF/IDF、BM25等)进行计算的。在es5.x版本后默认使用BM25算法进行相关性算分。
相关性算分是指文档与查询语句之间的相关度(relevance)。其本质是一个排序问题,就是当通过倒排索引获取到匹配的文档列表后,如何将最符合用户需求的文档排在前列。
相关性算分具有如下的重要概念:
TF/IDF算法是Lucene的经典算法,计算公式如下:
BM25算法中BM指的是BEST MATCH,25指的是迭代了25次才计算方法,是针对TF/IDF的一种优化,计算公式如下:
对字段有检索,有顺序要求,API如下:
这个例子是:匹配java和engineer关键字的文档,且java要在engineer前面。
通过slop参数控制单词间的间隔:
这样额话,就表示允许匹配的文档可以与 java engineer有一个距离的差异。这样,java senior engineer这样的字段就可以返回了。
类似于 URI search中的q参数查询:
这个例子就表示返回返回username字段中包含alfred和way的文档
这个表示查询username 和 job字段,条件是包含alfred或同时包含java和ruby
类似于query string,但是会忽略掉错误的查询语法,并且仅支持部分的查询语法。不能使用 AND,OR,NOT等关键词,使用 +代替AND, | 代替OR,- 代替 NOT。
将查询语句作为一个整体进行查询,不进行分词:
一次传入多个单词进行查询:
范围查询主要针对日期和数值类型:
Date Math是针对日期的一种更友好的计算格式:
主要的时间单位有:y(year)、M(months)、w(week)、d(days)、h(hours)、m(minutes)、s(seconds)
复合查询是指包含字段类查询或复合查询的类型,主要有以下几种:
constant_score query将其内部的查询结果文档得分都设定为1或者boost的值,多用于结合bool查询实现自定义得分:
在返回的结果中,_score的值全部为1
bool query由一个或多个bool子句组成,主要包含以下4个:
filter查询只返回符合条件的文档而不关心相关性,不进行相关性算分。es对filter有智能缓存,所以其执行效率很高。所以在执行简单查询而不考虑相关性的时候推荐使用filter代替query等。
执行结果中的_score的值为0,表示没有进行相关性算分
must指定了必须符合的条件:
must_not是指排除must_not中符合条件的文档:
should的使用有两种情况:
这个api是用于返回符合条件的文档数,endpoint为_count
过滤返回结果中_source的字段,节省网络开销: