👨🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:详解SpringCloud微服务技术栈:DSL查询ES文档高级语法、相关性算分数学原理总结
📚订阅专栏:微服务技术全家桶
希望文章对你们有所帮助
这一部分学习我觉得也还是挺重要的,而且是开发过程中经常会遇到的需求,把这些DSL语句了解清楚是很重要的。
ElasticSearch搜索结果处理
- 排序
- 分页
- 高亮
排序
ElasticSearch本身就带有排序,支持对搜索的结果进行排序,默认根据相关度算分(_score)排序,分数越高排名越靠前。
但是很多时候我们可能需要对价格、日期等进行排序,因此我们也可以自己设定排序的规则,而不是将其加入进行相关度算分。
常见的排序字段类型有简单类型的、地理坐标类型的,分别进行举例:
1、对酒店数据按照用户评价降序排序,评价相同的按照价格升序排序:
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"score": "desc"
},
{
"price": "asc"
}
]
}
2、对酒店数据按照到某位置坐标的距离进行升序排序
GET /hotel/_search
{
"query":{
"match_all": {}
},
"sort": [
{
"_geo_distance": {
"location": {
"lat": 31.034661,
"lon": 121
},
"order": "asc",
"unit": "km"
}
}
]
}
分页
ElasticSearch默认情况下只返回10条数据,而如果要查询更多数据就需要修改分页参数。ElasticSearch通过修改from(分页开始的位置,默认为0)、size参数(期望获取的文档总数)来控制要返回的分页结果:
GET /hotel/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"price": {
"order": "asc"
}
}
],
"from": 0,
"size": 10
}
如果想看第二页,那就把from的值赋为10即可。
其实这种分页的效果跟MySQL很像,但是其底层是有很大的区别的,因为ES因为底层是倒排索引,并不像MySQL那样容易做分页,所以ES的分页实际上是逻辑分页。
例如,当我们要获取990-1000的数据,实际上会先进行排序并获取1000条数据,然后截取990-1000条文档。
底层数据结构决定了这一点,并没有办法改变,在单点进行这种操作的时候没有关系,但是当ElasticSearch是集群部署的时候(ES是分布式的),就会将所有文档进行拆分,放到不同的ES上,称为分片,这时候没办法从所有的集群中获取到这前1000条数据。
简单来说,在某个分片上的前1000条文档,放在所有的文档中很可能不是前1000,一种解决方式是从所有分片中获取前1000条文档做聚合,再重新排序并选取出前1000名。
但是如果搜索页数过深或者结果集越大,对内存、CPU消耗也大,因此ES设置了结果集的查询上限为10000。如此的话,我们应该尽量从业务层面就不要超出这个查询的上限。
而针对深度分页,ES也提供了解决方案:
search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。
高亮
高亮即在搜索结果中把搜索关键字突出显示,例如百度的搜索。
能够实现这样的搜索后高亮肯定不是前端代码去做的,做这件事的就是服务器端,具体来说就是ElasticSearch。
底层原理:
1、将搜索结果的关键字用标签标记出来
2、在页面中给标签添加CSS样式
例如,我们现在需要搜索所有文档中的信息中带着“如家”的酒店,那匹配的字段直接使用all即可,但是ES的搜索默认搜索的字段要与高亮的字段一致,只需要将require_field_match置为false即可:
GET /hotel/_search
{
"query": {
"match": {
"all": "如家"
}
},
"highlight": {
"fields": {
"name": {
"require_field_match": "false"
}
}
}
}
需要注意的是,上述代码中的"name"可以写为:
"name":{
"pre_tags": "<em>", # 标记高亮字段的前置标签
"post_tags": "</em>" # 标记高亮字段的后置标签
}
而默认就是用这个标签实现的高亮。