详解SpringCloud微服务技术栈:ElasticSearch搜索结果处理(排序、分页、高亮)

👨‍🎓作者简介:一位大四、研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>" # 标记高亮字段的后置标签
}

而默认就是用这个标签实现的高亮。

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布布要成为最负责的男人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值