概要

本篇从介绍搜索分页为起点,简单阐述分页式数据搜索与原有集中式数据搜索思维方式的差异,就分页问题对deep paging问题的现象进行分析,最后介绍分页式系统top N的案例。

搜索分页语法

Elasticsearch中search语法有from和size两个参数用来实现分页的效果:

  • size:显示应该返回的结果数量,默认是10。
  • from:显示查询数据的偏移量,即应该跳过的初始结果数量,默认是0。

from和size这两个参数的含义和MySql使用limit关键字分页的参数含义是一样的。

举几个示例,查询第1-3页的请求:

GET /music/children/_search?size=10
GET /music/children/_search?size=10&from=10
GET /music/children/_search?size=10&from=20

分布式数据与集中式数据的差异

集中式数据存储方式,从最早的单体应用模式,到早期的SOA服务模式,那时存储大多数都是采用集中式数据存储,数据落地到mysql等关系型数据中,有支持读写分离,部署了多台数据库实例实现主-从结构的本质上也还是集中式存储。

在单数据库或主从数据库中,执行分页查询,统计排序等思路相对清晰,毕竟数据都完完整整地放在一起,直接挑一台实例搞就是了,可能就是容量有上限,出结果慢一些而已。

关系型数据库使用分布式数据存储的经典方案是分库分表,同一张表的数据,用一定的路由逻辑,拆分在不同的数据库实例里存储,此时做数据统计,就不能只关注一个实例了。

分布式数据存储方式,搜索思路就开始有了细微的改变,比如说Elasticsearch,索引的数据是拆分存储在各个shard里的,每个shard可能散布在ES集群的各个node上,这种情况下,做查询,统计分析等操作,虽然ES已经封装好了技术细节,我们仍然需要明白这是一个分布式储存的查询方案。

个人认为,分布式数据与集中式数据的处理差异,虽然在关系型数据库或ES方面,已经有成熟的框架对其进行封装,但使用者还是需要从思维上去理解分布式带来的改变,这样才能得到正确的结果。

deep paging问题

deep paging简单来说叫深度分页,就是搜索得特别深,显示第好几百页的数据。为什么说deep paging是有问题的?

我们假定索引内有20000条数据,存储在5个shard里,发送一个有条件和指定排序字段的查询请求,如果我要取第1页的数据,那么每个shard都取10条数据,汇总到Coordinate Node里,共50条,Coordinate Node对这50条数据再进行排序,滤掉后面的40条数据,只取最前面的

10条,返回给客户端。

如果是第1000页呢?

按老套路每个shard取10000-10010条,汇总到Coordinate Node里,还是50条,最后返回给客户端?

这么做就错啦,分布式数据不是这么查的,第1000页,在每个shard中不是取第10000-10010条,而是取前面10010,5个shard共取50050条给Coordinate Node,Coordinate Node汇总数据完成排序等操作后再取第10000-10010条,返回客户端10条数据。

费了这么大劲收集到50050条数据,实际给客户端的就10条,丢掉50040条数据,好费内存。

如果第10000页呢?这结果不忍直视

如果一个索引的分片数越多,需要汇总的数据就会成倍增长 ,可以看到分布式系统对结果排序分布的成本随深度呈指数上升,最重要的两个影响维度是分页深度和shard数量。这种重量级的查询,极有可能拖垮整个Elasticsearch集群,所以说搜索引擎对任何查询都不要返回超过1000个结果。

引申top N问题模型

deep paging的问题,通过优化搜索关键词,控制分页深度,问题能得到一定的改善,那top N问题如如何解决呢?

聚合查询中,经常能遇到查询最XX的10条记录这种分析需求,这种就是top N问题模型。

完美解决的场景

我们先举个熟悉的案例:统计播放量最高的10首的英文儿歌。

document数据结构:

{
"_index": "music",
"_type": "children",
"_id": "2",
"_version": 6,
"found": true,
"_source": {
"name": "wake me, shark me",
"content": "don't let me sleep too late, gonna get up brightly early in the morning",
"language": "english",
"length": "55",
"likes": 0
}
}

这个需求ES处理起来得心应手,有下面几个原因:

  • 一个document只会存在于一个shard中
  • 每个document数据里中有播放数量的统计值

有这上面几点的保证,查询时ES就可以放心大胆地在每个shard取播放数最高的前10条数据,Coordinate Node汇总的数据也就50条,此时性能非常高。

不宜直接查询的场景

上一小节依赖document的预先设计和shard存储数据的特性,避免了全索引扫描,性能特别高,假设系统中针对每天的播放点击,都有一个播放日志记录,记录着歌曲ID,点击人,点击时间,收听时长,时长百分比(与完整歌曲的百分比,有听到一半就退出不听了的,这个值就是50%),该document的数据示例:

{
"_index": "playlog-20191121",
"_type": "music",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"music_id": 1,
"listener": "tony wang",
"listen_date": "2019-11-21 15:35:00",
"music_length": 52,
"isten_percentage": 0.95
}
}

假设歌曲总量200万条,每天的播放日志1亿条,日志索引每天建立一个,primary shard数量为10,命名格式playlog-yyyyMMdd,需求是搜索当天的播放排行榜,取排名前10的记录。

如果直接统计,就只能硬扛了,基本过程如下:

  1. 每个shard根据music_id做分组统计,理论上单shard数量量最多200万条。
  2. Coordinate Node收集10个shard的数据,进行合并,数据处理量上限2000万条,最后合并成200万条。
  3. 从这200万条数据取前面10条,返回给客户端。

这个过程绝对是重量级,如果每次都实时统计的话,ES集群的压力可想而知。

改进方案
  1. 播放功能增加数据更新逻辑

    预先增加按日期统计的索引数据结构,每次有用户点击播放时,额外发送一条更新消息将其数据更新,查询时直接从统计的索引里出结果,避免每次查询。

  2. 定时任务统计数据

    数据统计的需求,可以用定时任务进行计算,将计算结果存储起来,通过降低实时性,来避免全索引扫描计算的压力。

简单对比:

  • 相同点:都是以空间换时间的做法,避免全索引扫描。
  • 不同点:前者通过更改业务实现逻辑,增加数据级联更新,有一定的业务耦合性;后者将实时计算变定时任务,灵活性较高,与业务耦合性低,但实时性差。
补充一点

良好的数据结构设计可以很大程度地降低ES查询压力,提高实时查询的性能,但有一点需要接受:考虑得再周全的设计,也难适应千变万化的需求;需求变更是无法避免的,没有一劳永逸的方案。

小结

本篇从分页查询入手,阐述了deep paging的问题原因,并顺带将自己对分布式系统与集中式系统处理的思维差异做了简单描述,最后引申了top N场景的问题,上面提到的改进方案,只是针对比较简单的场景,实际生产要面临的情况肯定更复杂,比如采用分布式计算组件storm来解决top N 问题的,这里当做是抛砖引玉,欢迎各位分享自己的看法。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区

Elasticsearch系列---搜索分页和deep paging问题的更多相关文章

  1. ES 25 - Elasticsearch的分页查询及其深分页问题 (deep paging)

    目录 1 分页查询方法 2 分页查询的deep paging问题 1 分页查询方法 在GET请求中拼接from和size参数 // 查询10条数据, 默认从第0条数据开始 GET book_shop/ ...

  2. 36.分页及deep paging

    主要知识点 1.es分页 2.deep paging     一.es分页语法 size,from 这两个关键字 GET /_search?size=10 指定每页10条数据 GET /_search ...

  3. Elasticsearch系列---搜索执行过程及scroll游标查询

    概要 本篇主要介绍一下分布式环境中搜索的两阶段执行过程. 两阶段搜索过程 回顾我们之前的CRUD操作,因为只对单个文档进行处理,文档的唯一性很容易确定,并且很容易知道是此文档在哪个node,哪个sha ...

  4. ElasticSearch(十五) _search api 分页搜索及deep paging性能问题

    1.分页搜索 语法: size,from GET /_search?size=10 GET /_search?size=10&from=0 GET /_search?size=10&f ...

  5. 游标 深度分页 deep paging

    Solr Deep Paging(solr 深分页) - ickes的专栏 - CSDN博客 https://blog.csdn.net/xl_ickes/article/details/427725 ...

  6. ElasticSearch7.3学习(十九)---- deep paging

    1.什么是deep paging 根据相关度评分倒排序,所以分页过深,协调节点会将大量数据聚合分析. 2.deep paging 性能问题 1消耗网络带宽,因为所搜过深的话,各 shard 要把数据传 ...

  7. SAP UI 搜索分页技术

    搜索分页技术往往和另一个术语Lazy Loading(懒加载)联系起来.今天由Jerry首先介绍S/4HANA,CRM Fiori和S4CRM应用里的UI搜索分页的实现原理.后半部分由SAP成都研究院 ...

  8. S/4HANA和CRM Fiori应用的搜索分页实现

    在我的博客Paging Implementation in S/4HANA for Customer Management 我介绍了S/4HANA for Customer Management里采用 ...

  9. ElasticSearch入门-搜索(java api)

    ElasticSearch入门-搜索(java api) package com.qlyd.searchhelper; import java.util.Map; import net.sf.json ...

随机推荐

  1. opencv 2 Opencv数据结构与基本绘图

    基础图像容器Mat Mat 是一个类,又两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法不同,矩阵可以是不同的维数)的指针.矩阵头的尺 ...

  2. 新闻实时分析系统Hive与HBase集成进行数据分析

    (一)Hive 概述 (二)Hive在Hadoop生态圈中的位置 (三)Hive 架构设计 (四)Hive 的优点及应用场景 (五)Hive 的下载和安装部署 1.Hive 下载 Apache版本的H ...

  3. SpringMVC参数绑定学习总结【前后端数据参数传递】

    目录 1. 绑定机制 2. 支持的数据类型 3. 参数请求中文乱码解决 4.自定义类型转换器 5.最后参数绑定学习小结 SpringMVC作为Controller层(等价servlet和struts中 ...

  4. 最小生成树(Kruskal)

    题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz 输入输出格式 输入格式: 第一行包含两个整数N.M,表示该图共有N个结点和M条无向边.(N<=5000,M<= ...

  5. Chapter 02—Creating a dataset(Part1)

    一. 数据集 1. 在R语言中,进行数据分析的第一步是创建一个包含待研究数据并且符合要求的数据集. · 选择装数据的数据结构 · 把数据装入数据结构中 2. 理解数据集 (1)数据集通常是矩形的数据列 ...

  6. EF分页查询

    /// <summary> /// 分页查询 + 条件查询 + 排序 /// </summary> /// <typeparam name="Tkey" ...

  7. 免费试用 | 多模 NoSQL 服务GeminiDB for Cassandra 全球首发

    PS:多模NoSQL服务GeminiDB重磅公测,免费体验,参与公测还有华为AI音响好礼相送~ 7月5日,华为云多模 NoSQL 服务GeminiDB for Cassandra正式对外定向邀测.华为 ...

  8. 基于webpack实现多html页面开发框架一 准备工作

    本系列主要介绍如何基于webpack实现多html页面开发框架,这里不讲webpack的基本概念,废话不多说,直奔主题! 前置条件: 1.安装node环境,自己去官网下载安装 2.新建文件夹webpa ...

  9. 转:使用JSR-303进行校验 @Valid

    一.在SringMVC中使用 使用注解 1.准备校验时使用的JAR validation-api-1.0.0.GA.jar:JDK的接口: hibernate-validator-4.2.0.Fina ...

  10. window安装jboss服务器

    window安装jboss服务器 1.下载jboss服务器 地址:http://download.jboss.org/jbossas/7.1/jboss-as-7.1.1.Final/jboss-as ...