IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Elasticsearch分页查询实现 -> 正文阅读

[大数据]Elasticsearch分页查询实现

一、Elasticsearch三种分页技术

1. from + size分页性能低

最原始的分页方式,每一页数据都需要把前面的数据都查出来排序后计算出from和size。很明显,存在深分页的问题,查询的页面数越大返回数据的速度越慢。适用于少量数据分页查询。

By default, you cannot use from and size to page through more than 10,000 hits. This limit is a safeguard set by the index.max_result_window index setting. If you need to page through more than 10,000 hits, use the search_after parameter instead.

2. scroll滚动搜索

scroll是推荐的查询大量数据的分页方式,可以解决深分页的问题。缺点是:需要维护context,太多scroll查询会导致Elasticsearch性能下降,另外scroll查询涉及的segement在context过期之前是不能merge的。

其查询步骤如下:

  • 提交一个scroll查询请求,Elasticsearch会初始化一个context,相当于给这个查询结果生成一个快照。scroll参数代表保持本次查询的context一分钟。该查询会返回一个_scroll_id。
POST /twitter/_search?scroll=1m
{
    "size": 100,
    "query": {
        "match" : {
            "title" : "elasticsearch"
        }
    }
}
  • 利用上面的_scroll_id查询第一页的数据,以下查询也会返回一个_scroll_id,大多时候会和之前的_scroll_id相同,但也会变化,推荐使用每次新返回的_scroll_id查询下一页的数据。scroll参数表示重置之前的scroll为1分钟,防止在数据查询完之前context过期。
GET /_search/scroll 
{
    "scroll" : "1m", 
    "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==" 
}

3. search_after

search_after性能高,主要用于实时数据查询;缺点是实现复杂,需要有一个全局唯一的字段,连续分页的时每一次查询都需要上次查询的结果;适用于需海量数据的分页的场景

search_after的分页实现需要借助于sort,查询步骤如下:

  • 查询第一页数据时不需要指定search_after,只需要编写一个普通的query+sort+size的语句即可
  • 查询第二页时需要query+sort+size+search_after,search_after的值等于第一页最后一个document的sort的值
  • 反复执行第二步直到hit的数量为0,说明所有页的数据已经拉取完
// 第一页查询
GET /_search
{
  "size": 10000,
  "query": {
    "match" : {
      "user.id" : "elkbee"
    }
  },
  "sort": [ 
        {"date": "asc"},
        {"id_copy": "asc"}
   ]
}
// 其他页查询
GET /_search
{
  "size": 10000,
  "query": {
    "match" : {
      "user.id" : "elkbee"
    }
  },
  "search_after": [1463538857, "654323"],
  "sort": [ 
        {"date": "asc"},
        {"id_copy": "asc"}
   ]
}

使用search_after需要注意:

  • 默认情况下search_after不能保证查询结果一致性,即分页查询过程中有refresh发生(如document写入或者删除),会导致分页之间数据不一致,不像scroll查询每次从数据快照读取数据,和关系型数据库中的幻读相似。
  • sort中的字段需要保证全局唯一,Elasticsearch不推荐使用_id作为排序字段,因为他没有开启doc value,这样Elasticsearch在排序时需要把所有的值加载到内存中排序。Elasticsearch建议新增加一个field,其值是_id的拷贝,但是开启了doc_value,作为排序字段。
  • 需要设置from为-1或者0。
  • search_after 不能随意的切换到任意的页面。

二、Springboot利用scroll返回大数据集

Elasticsearch has a scroll API for getting big result set in chunks. This is internally used by Spring Data Elasticsearch to provide the implementations of the SearchHitsIterator SearchOperations.searchForStream(Query query, Class clazz, IndexCoordinates index) method.

IndexCoordinates index = IndexCoordinates.of("sample-index");

SearchQuery searchQuery = new NativeSearchQueryBuilder()
  .withQuery(matchAllQuery())
  .withFields("message")
  .withPageable(PageRequest.of(0, 10))
  .build();

SearchHitsIterator<SampleEntity> stream = elasticsearchTemplate.searchForStream(searchQuery, SampleEntity.class, index);

List<SampleEntity> sampleEntities = new ArrayList<>();
while (stream.hasNext()) {
  sampleEntities.add(stream.next());
}

stream.close();

There are no methods in the SearchOperations API to access the scroll id, if it should be necessary to access this, the following methods of the ElasticsearchRestTemplate can be used:

@Autowired ElasticsearchRestTemplate template;

IndexCoordinates index = IndexCoordinates.of("sample-index");

SearchQuery searchQuery = new NativeSearchQueryBuilder()
  .withQuery(matchAllQuery())
  .withFields("message")
  .withPageable(PageRequest.of(0, 10))
  .build();

SearchScrollHits<SampleEntity> scroll = template.searchScrollStart(1000, searchQuery, SampleEntity.class, index);

String scrollId = scroll.getScrollId();
List<SampleEntity> sampleEntities = new ArrayList<>();
while (scroll.hasSearchHits()) {
  sampleEntities.addAll(scroll.getSearchHits());
  scrollId = scroll.getScrollId();
  scroll = template.searchScrollContinue(scrollId, 1000, SampleEntity.class);
}
template.searchScrollClear(scrollId);

To use the Scroll API with repository methods, the return type must defined as Stream in the Elasticsearch Repository. The implementation of the method will then use the scroll methods from the ElasticsearchTemplate.

interface SampleEntityRepository extends Repository<SampleEntity, String> {
    Stream<SampleEntity> findBy();
}
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-11-28 11:22:04  更:2021-11-28 11:23:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:30:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码