搜索辅助功能
- 指定返回的字段 考虑到性能问题,需要对搜索结果进行瘦身,指定返回的字段,在ES中,通过_source子句可以设定返回结果的字段,_source指向一个JSON数组,数组中的元素是希望会字段名称。
get /hotel/_search
{
"_source":["title","city"], //设定只返回title和city字段
"query":{
"term":{
"city":{
"value":"北京"
}
}
}}
- 结果计数
get /hotel/_count
{
"query":{
"term":{
"city":{
"value":"北京"}}
}
}
3.结果分页 默认情况下ES返回前10个搜索匹配的文档,用户可以通过设置form和size来定义搜索位置和每页显示的文档数量。
GET /hotel/_search {
"from": 0, //设置搜索的起始位置
"size": 20, //设置搜索返回的文档个数
"query": { //搜索条件
"term": { "city": { "value": "北京" } } }
}
默认情况下用户可以取得最多10000个文档,如果超过该值,ES将会报错。如果要返回多于该值的数据,可以修改max_result_window的值:
put /hotel/_settings{
"index":{
"max_result_window":20000
}
}
作为一个分布式搜索引擎,一个ES索引的数据分布在多个分片中,而这些分片又分配在不同的节点上。一个带有分页的搜索请求往往会跨越多个分片,每个分片必须在内存中构建一个长度为from+size的、按照得分排序的有序队列,用以存储命中的文档。然后这些分片对应的队列数据都会传递给协调节点,协调节点将各个队列的数据进行汇总,需要提供一个长度为number_of_shards*(from+size)的队列用以进行全局排序,然后再按照用户的请求从from位置开始查找,找到size个文档后进行返回。 基于上述原理,ES不适合深翻页。什么是深翻页呢?简而言之就是请求的from值很大。假设在一个3个分片的索引中进行搜索请求,参数from和size的值分别为1000和10
当深翻页的请求过多时会增加各个分片所在节点的内存和CPU消耗。尤其是协调节点,随着页码的增加和并发请求的增多,该节点需要对这些请求涉及的分片数据进行汇总和排序,过多的数据会导致协调节点资源耗尽而停止服务。
- 性能分析
GET /hotel/_search {
"profile": "true", //打开性能剖析开关
"query": { //查询条件
"match": { "title": "金都" }
}
}
- 评分分析
在使用搜索引擎时,一般都会涉及排序功能。如果用户不指定按照某个字段进行升序或者降序排列,那么ES会使用自己的打分算法对文档进行排序。有时我们需要知道某个文档具体的打分详情,以便于对搜索DSL问题展开排查。ES提供了explain功能来帮助使用者查看搜索时的匹配详情。
GET /hotel/_explain/002 {
"query": {
"match": { //搜索酒店名称匹配“金都”的文档
"title": "金都" } } }
丰富的搜索匹配功能
- 查询所有文档
GET /hotel/_search {
"_source": [ //只返回title和city字段
"title", "city" ],
"query": {
"match_all": { //查询所有文档
"boost": 2 //设定所有文档的分值为2.0
} }
}
- term级别查询
- term查询是结构化精准查询的主要查询方式,用于查询待查字段和查询值是否完全匹配,
GET /hotel/_search {
"query": {
"term": {
"price": { //搜索字段为price,字段类型为double
"value": "500" //搜索值为500
} } }
}
- terms查询
查询一个或多个值与待查字段是否完全匹配
GET /hotel/_search {
"query": {
"terms": {
"city": [ //指定查询字段为city
"北京", "天津" ]
} }
}
- range查询
用于范围查询,一般是对数值类型和日期类型数据的查询
| 标题 | |
|---|---|
| gt | 大于 |
| lt | 小于 |
| gte | 大于等于 |
| lte | 小于或等于 |
GET /hotel/_search {
"query": {
"range": { //range查询
"price": { //指定字段为price,此处包含边界值
"gte": 300,
"lte": 500 }
} }
}
- exists查询
可以用exists搜索字段不为空的条件:
- 值存在且不是null
- 值不是空数组
- 值是数组,但不是[null]
GET /hotel_1/_search {
"query": {
"exists": { //查询tag字段不为空的文档
"field": "tag"
} }
}
- 布尔查询
- must
GET /hotel/_search {
"query": {
"bool": {
"must": [ //must查询,数组内可封装各类子查询
{
//第一个子查询:城市为北京
"term": {
"city": {
"value": "北京" } } },
{ //第二个子查询:价格>=350且价格<=400
"range": {
"price": { "gte": 350, "lte": 400 } } }
]
} }
}**
-
should
-
must not
-
filter
GET /hotel/_search { "query": { "bool": { "filter": [ // filter查询,数组内可封装各类子查询 { //第一个子查询:城市为北京 "term": { "city": "北京" } }, { //第一个子查询:满房状态为否 "term": { "full_room": false } } ] } } }
- filter查询原理
在执行过滤条件时,会查询缓存中是否有字段值对应的bitse数据,位图,可以用非常紧凑的格式来表示给定范围内的连续数据,如果有对应的位图数据,则取出备用,如果没有则在es查询后将其放入缓存,并构建位图.
- constant score 查询 如果不想让检索频率TF对搜索结果排序有影响,指向过滤某个文本字段是否包含某个词,可以使用constant score将查询语句包装起来。
GET /hotel/_search {
"_source": ["amenities"],
"query": {
"constant_score": { //满足条件即打分为1
"filter": {
"match": { //查询设施中包含“停车场”的文档
"amenities": "停车场" } } } }
}
- function Score查询
当使用ES进行搜索时,命中的文档默认按照相关度进行排序。有些场景下用户需要干预该“相关度”,此时就可以使用Function Score查询。使用时,用户必须定义一个查询以及一个或多个函数,这些函数为每个文档计算一个新分数。
GET /hotel/_search {
"_source": ["title","city"],
"query": {
"function_score": {
"query": { //查询符合条件的文档
"term": {
"city": {
"value": "北京" } } },
"functions": [ //定义函数
{ //此处只定义了一个函数:随机数函数
"random_score": {} } ],
"score_mode": "sum" //最终分数是各个函数的加和值
} } }
- 全文搜索
- match查询,只要分词中的一个或多个在文档中存在即可。
- multi_match查询,多个字段中查询关键字,除了使用布尔查询封装多个match查询之外,可替代的方案时使用muti_match
GET /hotel/_search {
"_source": ["title","amenities"],
"query": {
"multi_match": { "query": "假日", //匹配关键字为“假日”
"fields": [ //设置匹配的字段为title和amenities
"title",
"amenities" ] } }
}
- match_phrase查询 用途关于匹配短语,搜索确切的短语或邻近的词语。
- 基于地理位置查询
GET /hotel/_search {
"_source": [ //只返回部分字段
"title",
"city",
"location" ],
"query": {
"geo_distance": {
"distance": "5km", //设置距离范围为5km
"location": { //设置中心点经纬度
"lat": "39.915143", //设置纬度
"lon": "116.4039" //设置经度 } } }
}
- 搜索建议
在搜索时,用户每输入一个字符,前端就需要向后端发送一次查询请求对匹配项进行查询,因此这种场景对后端响应速度的要求比较高。为了使用Completion Suggester,其对应的字段类型需要定义为completion类型。在以下示例中定义了一个酒店搜索建议的索引:
PUT /hotel_sug {
"mappings": {
"properties": {
"query_word": { //定义query_word字段,类型为completion
"type": "completion" } } }
}
GET /hotel_sug/_search {
"suggest": {
"hotel_zh_sug": { //定义搜索建议名称
"prefix": "如家", //设置搜索建议的前缀
"completion": { //设置搜索建议对应的字段名称
"field": "query_word" } } }
}
按字段值排序
- 按普通字段值排序
使用sort自居对字段进行排序时需要指定排序的字段,默认按照升序,可以设置order参数为asc或者desc
GET /hotel/_search {
"_source": [ //只返回部分字段
"title", "price" ],
"query": { //搜索条件
"match": {
"title": "金都" }
},
"sort": [ { //按照价格降序排列
"price": { "order": "desc" } }
] }
- 按照地理距离排序
GET /hotel/_search {
"_source": [ //返回部分字段
"title", "city", "location" ],
"query": {
"geo_distance": {
"distance": "5km", //设置地理范围为5km
"location": { //设置中心点坐标
"lat": "39.915143",
"lon": "116.4039" } } },
"sort": [ //设置排序逻辑
{ "_geo_distance": {
"location": { //设置排序的中心点坐标
"lat": "39.915143",
"lon": "116.4039" },
"order": "asc", //按距离由近到远进行排序
"unit": "km", //排序所使用的距离的计量单位
"distance_type": " plane " //排序所使用的距离计算算法
} } ]
}