文章目录
一、搜索辅助功能
1.1、指定返回的字段
考虑到性能问题,需要对搜索结果进行"瘦身"------指定返回的字段。在ES中,可以通过_source
子句可以设定返回结果的字段。_source
指向一个JSON数组,数组中的元素是希望返回的字段名称。
bash
GET /hotel/_search
{
"_source":["title","city"],
"query":{
"term":{
"city":{
"value":"成都"
}
}
}
}
1.2、结果计数
为提升搜索体验,需要给前端传递搜索匹配结果的文档条数,即需要对搜索结果进行计数。针对这个需求,ES提供了_count
API功能,在该API中,用户提供query子句用于结果匹配,ES会返回匹配的文档条数。下面的DSL功能会返回城市为"成都"的酒店个数:
bash
GET /hotel/_count
{
"query":{
"term":{
"city":{
"value":"成都"
}
}
}
}
返回结果为:
bash
{
"_count":3,
"_shards":{
...
}
}
1.3、结果分页
在实际的搜索应用中,分页是必不可少的功能。用户可以通过from 和size 来设置搜索位置和每页显示的文档数量,from表示查询结果的起始下标,默认值为0 ,size表示从起始下标开始返回的文档个数,默认值为10。例如:
bash
GET /hotel/_search
{
"from":0,
"size":20,
"query":{
"term":{
"city":{
"value":"成都"
}
}
}
}
在默认情况下,用户最多可以取得10000个文档,如果请求超过该值,ES会返回报错信息。如果确实需要返回多于10000条数据,可以适当调整max_result_window的值:
bash
PUT /hotel/_settings
{
"index":{
"max_result_window":20000
}
}
注意,如果将配置修改的很大,一定要有足够的硬件作为支撑。
二、搜索匹配功能
2.1、查询所有文档
在ES中可以使用match_all
实现查询所有文档的数据,使用match_all查询文档时,ES不对文档进行打分计算,默认情况下给每一个文档赋予1.0的得分。
bash
GET /hotel/_search
{
"_source":["title","city"],
"query":{
"match_all":{
...
}
}
}
2.2、term级别查询
2.2.1、term查询
term查询是结构化精准查询的主要查询方式,用于查询待查字段和查询值是否完全匹配,其请求形式如下:
bash
GET /hotel/_search
{
"query":{
"term":{
"${FIELD}":{
"value":"${VALUE}"
}
}
}
}
其中FIELD和VALUE分别代表字段名称和查询值,例如搜索城市为成都的酒店:
bash
GET /hotel/_search
{
"query":{
"term":{
"city":{
"value":"成都"
}
}
}
}
2.2.2、terms查询
terms
查询是term
查询的扩展形式,用于查询一个或多个值 与待查字段是否完全匹配,以下是搜索城市为"北京"或者"成都"的酒店实例:
bash
GET /hotel/_search
{
"query":{
"terms":{
"city":[
"北京",
"成都"
]
}
}
}
2.2.3、range查询
range查询用于范围查询,一般是对数值型和日期型数据的查询使用range进行范围查询时,用户可以根据需求中是否包含边界数值进行选项设置可供组合的选项如下:
- gt:大于
- lt:小于
- gte:大于或等于
- lte:小于或等于
以下为数值类型的查询示例,查询住宿价格大于300(不包含边界值)的酒店:
bash
GET /hotel/_search
{
"query":{
"range":{
"price":{
"gt":300
}
}
}
}
2.2.4、exists查询
在某些场景下,我们希望找到某个字段不为空的文档,可以使用exists搜索,字段不为空的条件有:
- 值存在且不为null
- 值不是空数组
- 值是数组,但不是[null]
例如:
bash
GET /hotel/_search
{
"query":{
"exists":{
"field":"tag" //字段名
}
}
}
2.3、布尔查询
复合搜索,顾名思义,是一种在一个搜索语句中包含一种或多种搜索子句的查询,布尔查询 是常用的复合查询。它把多个子查询组合成一个布尔表达式,这些子查询之间的逻辑关系是与,即所有子查询的结果都为true,布尔查询的结果才为真。
布尔查询支持的子查询有四种,各子查询的名称和功能如下所示:
- must:必须匹配该查询条件
- should:可以匹配该查询条件
- must_not:必须不匹配该查询条件
- filter :必须匹配过滤条件,不进行打分计算
2.3.1、must,should,must_not
这三种查询ES会将子查询与文档的匹配程度值加入到总得分里,搜索时后面都可以包含一个数组,例如:
java
GET /hotel/_search
{
"query":{
"bool":{
"must":[ // must查询,数组内可以封装各类子查询
{ // 第一个子查询:城市为成都
"term":{
"city":{
"value":"成都"
}
}
},
{ // 第二个子查询:价格>=350且价格<=450
"range":{
"price":{
"gte":350,
"lte":450
}
}
}
]
}
}
}
2.3.2、filter
filter
查询即过滤查询,该查询是布尔查询里非常独特的一种查询,其他布尔查询关注的是查询条件和文档的匹配程度,并按照匹配程度进行打分。而filter查询关注的是查询条件和文档是否匹配,不进行相关的打分计算(这可以减少不小的时间开销),但是会对部分匹配结果进行缓存。
java
GET /hotel/_search
{
"query":{
"bool":{
"filter":[ // filter查询,数组内可以封装各类子查询
{ // 第一个子查询:城市为成都
"term":{
"city":{
"value":"成都"
}
}
},
{ // 第二个子查询:价格>=350且价格<=450
"range":{
"price":{
"gte":350,
"lte":450
}
}
}
]
}
}
}
2.4、全文搜索
不同于结构化搜索,全文搜索首先对查询词进行分析,然后根据查询词的分词结果构建查询。这里所说的全文指的是文本类型数据(text类型)。结构化搜索关注的是数据是否匹配,全文搜索关注的是匹配的程;结构化搜索一般用于精确匹配,而全文搜索用于部分匹配。
2.4.1、match查询
match
查询是全文搜索的主要代表。对于最基本的match搜索来说,只要分词结果中的一个或者多个词在文档中存在即可,例如搜索金都酒店:
java
GET /hotel/_search
{
"_source":["title"], //只返回title字段
"query":{
"match":{ //匹配title字段为"金都酒店"的文档
"title":"金都酒店"
}
}
}
或者按照如下方式搜索:
java
GET /hotel/_search
{
"_source":["title"], //只返回title字段
"query":{
"match":{ //匹配title字段为"金都酒店"的文档
"title":{
"query":"金都酒店"
}
}
}
}
2.4.2、multi_match查询
有时用户需要在多个字段中查询关键词,除了使用布尔查询封装多个match查询之外,可替代的方案是使用multi_match
。可以在multi_match的query
子句中组织数据匹配规则,并在fields
子句中指定需要搜索的字段列表:
java
GET /hotel/_search
{
"_source":["title","amenities"], //匹配的关键字为"假日"
"query":{
"multi_match":{ //设置匹配的字段为title和amenities
"query":"假日",
"fields":[
"title",
"amenities"
]
}
}
}
2.4.3、match_phrase查询
match_phrase
用于匹配短语,与match查询不同的是,match_phrase用于搜索确切的短语或临近的词语。
三、按字段值排序
在默认情况下,ES对搜索结果是按照相关性降序排序的,有时需要按照某些字段的值进行升序或者降序排序。ES提供了sort
子句,可以对数据进行排序。sort子句一般是按照字段信息进行排序,不受相关性影响,而且打分步骤需要耗费一定的硬件资源和时间,因此默认情况下不对文档进行打分。
使用sort字句对字段值进行排序时,需要指定排序的字段。ES默认的是按照字段值进行升序,排序可以设置sort参数为asc
或desc
,指定按照字段值进行升序或者降序排序。
以下示例为搜索名称包含"金都"的酒店,并对酒店按照价格进行降序排列:
java
GET /hotel/_search
{
"_source":["title","price"], //只返回部分字段
"query":{ //搜索条件
"match":{
"title":"金都"
}
},
{
"sort":[ //按照价格降序排序
{
"price":{
"order":"desc"
}
}
]
}
}