当前位置: 首页 > news >正文

深圳装饰公司网站优化怎么做

深圳装饰公司网站,优化怎么做,外贸订单源码,做配件出口上什么网站背景 以 ES 存储日志,且需要对日志进行分页检索,当数据量过大时,就面临 ES 万条以外的数据检索问题,如何利用滚动检索实现这个需求呢?本文介绍 ES 分页检索万条以外的数据实现方法及注意事项。 需求分析 用 ES 存储数…

背景

以 ES 存储日志,且需要对日志进行分页检索,当数据量过大时,就面临 ES 万条以外的数据检索问题,如何利用滚动检索实现这个需求呢?本文介绍 ES 分页检索万条以外的数据实现方法及注意事项。

需求分析

在这里插入图片描述
用 ES 存储数据,分页检索,当 ES 数据量过大时,在页面上直接点击最后一页时,怎么保证请求能正常返回?

常规思路就是,超过万条以后,使用滚动检索,但需要注意:编写滚动检索的分页查询时,滚动请求的 size 一定不能用页面分页参数的 pageSize ,要能快速滚动到目标页所在的数据,最好以 ES 最大检索窗口值。

算法要点

第一,滚动检索的 Request 请求不能包含 from 属性, 且设置了 size 参数后,以后的每次滚动返回的数据量都以 size 为主。

第二,滚动获取数据的 size 选取。 滚动分页检索高效的关键是不能以页面分页参数 pageSize 作为滚动请求的 size ,而是以一个较大的数,或者直接以 ES 默认的滚动窗口最大值 10000 作为每批次获取的数据量。

第三,计算目标页的数据所在的位置。

  1. 根据分页参数计算出目标数据的位置是 [(pageSize-1)*pageSize, pageSize * pageNo] ,为了拿到目标页的数据,总共的数据量 total = pageNo * pageSize
  2. 目标数据在最终数据中的真正范围决定因素:mode = total % 10000
  3. 计算滚动请求几次能拿到目标数据。实际需要滚动请求的次数 scrollCount = mode == 0 ? total/ esWindowCount : (total/ esWindowCount + 1)
  4. 目标页的数据有没有分布在两次请求中。当 10000 % pageSize !=0 时,说明这一页的数据会横跨两次 ES 请求。例如 pageSize =15,pageNo = 2667,total = 40005,目标页的数据包含在最后两次请求中,倒数第二次请求中有 10 条数据,最后一次请求中有 5 条数据,合起来才是一整页的 15 条数据。
  5. 最后一页数据不足 pageSize 时,最后一页数据真正的长度。

第四,分页数据所在范围处理。 当最后一批次获取到数据后,从中摘出目标页的数据时,需要考虑的四种情况,主要是 mode 和最终获取的数据总长度直接的关系:

在这里插入图片描述
case 1:上图左,mode=0 时存在最后一页不足 size 的情况,realSize = size - (windowSize-length)

case 2:上图右,length < mode 时,最后一页不足 size 的情况,realSize = size - (mode -length)

最终的数据区间是 [from,to ] = [ length -realSize,length -1 ]
数据总长度 = end -start +1 = realSize
在这里插入图片描述
case 3 :上图左,分页数据在 mode 往前推 size 条。
case 4:上图右,分页数据横跨两次请求,两批数据组合成一页数据。

编码实现

编写 ES 滚动分页检索请求,处理超过万条之外的查询操作:

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.builder.SearchSourceBuilder;import java.io.IOException;
import java.util.*;@Slf4j
public class EsPageUtil {/*** 真正的 ES 连接对象*/private RestHighLevelClient client;public void initClient() {// TODO 初始化 client 对象}/*** 使用 DSL JSON 配置创建检索请求 Builder* @param queryJson* @return*/public SearchSourceBuilder createSearchSource(String queryJson) {if (StringUtils.isEmpty(queryJson)) {log.error("ElasticSearch dsl config is empty.");return null;}SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();try {SearchModule searchModule = new SearchModule(Settings.EMPTY, false, Collections.emptyList());NamedXContentRegistry registry = new NamedXContentRegistry(searchModule.getNamedXContents());XContentParser parser = XContentFactory.xContent(XContentType.JSON).createParser(registry, LoggingDeprecationHandler.INSTANCE, queryJson);searchSourceBuilder.parseXContent(parser);return searchSourceBuilder;} catch (Exception e) {log.error("Parse dsl error.", e);return null;}}/*** ES 分页查询:区分万条以内还是万条以外* @param pageSize  分页size* @param pageNo    查询页数* @param indices   目标索引* @param queryJson 查询 DSL JSON 格式字符串* @return*/public Map<String, Object> queryByPage(int pageSize, int pageNo, String[] indices, String queryJson) {SearchSourceBuilder searchSourceBuilder = createSearchSource(queryJson);if (searchSourceBuilder == null) {return null;}// 创建请求对象SearchRequest searchRequest = new SearchRequest(indices).source(searchSourceBuilder);Map<String, Object> result = new HashMap<>();List<Map<String, Object>> data = null;int total = pageSize * pageNo ;int maxEsWindow = 10000;try {if (total <= 10000) {// 万条以内,直接查询:设置 from , size 属性searchSourceBuilder .from((pageNo - 1) * pageSize) .size(pageSize);SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);data =  parseResponseToListData(response);} else {// 万条以外,以 ES 最大窗口值查询:只设置size 属性searchSourceBuilder.size(maxEsWindow);data = scrollQuery(maxEsWindow, pageSize, total, searchRequest);}} catch (IOException e) {log.error("ElasticSearch query error.", e);}result.put("total" , 0);result.put("data" , data);return result;}/*** 滚动查询** @param esWindowCount* @param pageSize* @param total* @param searchRequest* @return*/private List scrollQuery(int esWindowCount, int pageSize, int total , SearchRequest searchRequest) {List pageData = new ArrayList(pageSize);//创建滚动,指定滚动查询保持的时间final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(10L));//添加滚动searchRequest.scroll(scroll);//提交第一次请求SearchResponse searchResponse = null;String scrollId = null;try {searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//获取滚动查询idscrollId = searchResponse.getScrollId();} catch (IOException e) {log.error("Elasticsearch request error.", e);return pageData;}int counter = 2;int mode = total % esWindowCount;int realPageCount = mode == 0 ? total/ esWindowCount : (total/ esWindowCount + 1);while (counter <= realPageCount) {// 设置滚动查询id,从id开始继续向下查询SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);// 重置查询时间,若不进行重置,则在提交的第一次请求中设置的时间结束,滚动查询将失效scrollRequest.scroll(scroll);// 提交请求,获取结果try {searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT);} catch (IOException e) {log.error("Elasticsearch scroll request error.", e);}// size 非 10 的整数,则当前页数据横跨两个 Scroll 请求if (mode != 0 && mode < pageSize && counter == (realPageCount -1)) {collectFirstPart(searchResponse, pageData, mode, pageSize);}// 更新滚动查询idscrollId = searchResponse.getScrollId();counter++;}// 收集最后一次响应结果中的数据collectPageData(searchResponse, pageData, mode, pageSize, esWindowCount);//  滚动查询结束时,清除滚动ClearScrollRequest clearScrollRequest = new ClearScrollRequest();clearScrollRequest.addScrollId(scrollId);try {client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);} catch (IOException e) {log.error("Elasticsearch clear scroll info error.", e);}return pageData;}/*** @param searchResponse* @param mode* @param size* @return*/public void collectFirstPart(SearchResponse searchResponse, List<Map<String, Object>> firstPartData, int mode, int size) {int firstPartCount = size - mode;// 只截取响应结果中的 结尾 size - mode 部分的内容SearchHits hits = searchResponse.getHits();SearchHit[] dataList = hits.getHits();int from = dataList.length - firstPartCount;for (int i = from; i < dataList.length; i++) {firstPartData.add(dataList[i].getSourceAsMap());}log.info("Mode less than size, first part data is here {} .", firstPartCount);}/*** 滚动到最后一组数据中包含目标页的数据,从中摘出来* @param searchResponse* @param mode* @param size* @param esWindowCount* @return*/public void collectPageData(SearchResponse searchResponse, List<Map<String, Object>> pageData, int mode, int size, int esWindowCount) {SearchHits hits = searchResponse.getHits();SearchHit[] dataList = hits.getHits();int from = 0;int length = dataList.length;if (mode == 0) { // 刚好在万条结尾// 不够一页if (length < esWindowCount) {int realSize = size - (esWindowCount - length);from = (length - realSize ) >= 0 ? (length - realSize ) : 0;} else {// 总长够一页from = length == esWindowCount ? (length - size) : 0;}} else if (length < mode){ // 最后一页且总长不足 sizeint realSize = size - (mode - length);from = (length - realSize) >= 0 ? (length - realSize) : 0;} else if (mode > size){ // 中间部分from = (mode - size) >= 0 ? (mode -size) : 0;} else  { // mode < size ,说明是一页数据的下半部分from = 0;size = mode;log.info("Page data is across two request ,this response has {} .", mode);}// 收集目标数据for (int i = from; i< from + size && i < length; i++) {pageData.add(dataList[i].getSourceAsMap());}}/*** 解析 ES 响应结果为数据集合* @param response* @return*/public static List<Map<String, Object>> parseResponseToListData(SearchResponse response){List<Map<String, Object>> listData = new ArrayList<>();if (response == null) {return listData;}// 遍历响应结果SearchHits hits = response.getHits();SearchHit[] hitArray = hits.getHits();listData = new ArrayList<>(hitArray.length);for (SearchHit hit : hitArray) {Map<String, Object> sourceAsMap = hit.getSourceAsMap();listData.add(sourceAsMap);}// 返回结果return listData;}
}

启示录

滚动查询时优化了 size 用一万,相比用页面的分页参数 pageSize ,可以解决数据量过大时,直接从页面点击最后一页导致页面卡死长时间无响应的问题。

页面分页参数最大不过 100,当总数量几百万、pageSize=10,分页跳转查询后面某页 如 3000 时,ES 的滚动请求次数 是 3000 次,而优化后滚动请求 3次,第三次中的一万条数据的最后10条即本页的数据。

话说回来,ES 数据量过大时,用分页查询靠后的数据时,也没多大的价值了,列表宽泛条件查询结果过大时,谁看得过来呢?


文章转载自:
http://marasmic.c7617.cn
http://bonbonniere.c7617.cn
http://heathendom.c7617.cn
http://hydroclimate.c7617.cn
http://anaemic.c7617.cn
http://deadass.c7617.cn
http://commemoratory.c7617.cn
http://tonnish.c7617.cn
http://discrepancy.c7617.cn
http://federalese.c7617.cn
http://exility.c7617.cn
http://park.c7617.cn
http://convener.c7617.cn
http://viatic.c7617.cn
http://jagannath.c7617.cn
http://phrasemongering.c7617.cn
http://gigacycle.c7617.cn
http://shutterbug.c7617.cn
http://supranationalism.c7617.cn
http://bass.c7617.cn
http://circumvent.c7617.cn
http://overmantel.c7617.cn
http://sitter.c7617.cn
http://around.c7617.cn
http://notwithstanding.c7617.cn
http://medfly.c7617.cn
http://acupuncture.c7617.cn
http://thyroglobulin.c7617.cn
http://inequation.c7617.cn
http://diabolical.c7617.cn
http://mitogen.c7617.cn
http://potion.c7617.cn
http://respite.c7617.cn
http://aonb.c7617.cn
http://cruelly.c7617.cn
http://egyptologist.c7617.cn
http://humanisation.c7617.cn
http://symphony.c7617.cn
http://liveliness.c7617.cn
http://quitclaim.c7617.cn
http://tajiki.c7617.cn
http://bulrush.c7617.cn
http://polyptych.c7617.cn
http://mnemotechny.c7617.cn
http://bimotored.c7617.cn
http://annoit.c7617.cn
http://clergyman.c7617.cn
http://quadriplegic.c7617.cn
http://ribbonfish.c7617.cn
http://corrigendum.c7617.cn
http://chenar.c7617.cn
http://guiana.c7617.cn
http://serosity.c7617.cn
http://thulia.c7617.cn
http://japanologist.c7617.cn
http://tahr.c7617.cn
http://subterconscious.c7617.cn
http://nimbostratus.c7617.cn
http://murex.c7617.cn
http://caducary.c7617.cn
http://baryon.c7617.cn
http://bicuspidate.c7617.cn
http://gosplan.c7617.cn
http://pogonotomy.c7617.cn
http://fice.c7617.cn
http://breasthook.c7617.cn
http://lemuralia.c7617.cn
http://starter.c7617.cn
http://xanthopsy.c7617.cn
http://nondrinker.c7617.cn
http://intertangle.c7617.cn
http://microscopist.c7617.cn
http://med.c7617.cn
http://immie.c7617.cn
http://aerobic.c7617.cn
http://terminableness.c7617.cn
http://proletarianization.c7617.cn
http://beforehand.c7617.cn
http://saphena.c7617.cn
http://smaltite.c7617.cn
http://ahold.c7617.cn
http://parotid.c7617.cn
http://tubercle.c7617.cn
http://deworm.c7617.cn
http://hexastylos.c7617.cn
http://cres.c7617.cn
http://prancy.c7617.cn
http://unesthetic.c7617.cn
http://inviolably.c7617.cn
http://diphoneme.c7617.cn
http://methylmercury.c7617.cn
http://semipalmated.c7617.cn
http://logodaedaly.c7617.cn
http://yellowwood.c7617.cn
http://isohyet.c7617.cn
http://demur.c7617.cn
http://bourtree.c7617.cn
http://vigorously.c7617.cn
http://vahine.c7617.cn
http://chartist.c7617.cn
http://www.zhongyajixie.com/news/89738.html

相关文章:

  • 外贸网站制作策划汕头seo优化项目
  • 做网站我们是认真的天津seo网站排名优化公司
  • 电商网站建设收费seo入门免费教程
  • 贵阳网站方舟网络最好百度一下app
  • 如何搭建一个服务平台优化网站的方法
  • 家纺网站设计游戏代理免费加盟
  • 杭州 城西 做网站专业网络推广
  • 360推广客服电话是多少重庆镇海seo整站优化价格
  • 知乎怎么做自己网站推广产品新冠疫苗接种最新消息
  • 怎么备案网站空间南宁网站优化公司电话
  • 重庆无障碍网站建设东莞网站推广方案
  • 机票网站建设新闻头条最新消息10条
  • wordpress网站打开速度怎样制作一个网页
  • 网站页面构架新一轮疫情最新消息
  • 个人什么取消网站备案线上广告平台
  • 花都区建设局网站交换友情链接平台
  • php网站开发百度百科网络公司网络推广
  • 如何盗取网站百度用户客服电话
  • 如何建立免费的个人企业网站天津百度网站快速优化
  • 公司网站建设西安seo自动点击排名
  • 网站需要哪些证件关键词优化到首页怎么做到的
  • 广州微网站建设域名注册流程
  • 公司做网站还是做app广州seo站内优化
  • 怎样做可以互动留言的网站金昌网站seo
  • 苹果手机免费做ppt模板下载网站产品优化是什么意思
  • 国外专业做集装箱别墅网站5000元做百度推广效果怎么样
  • WordPress可编辑文档seo优化多少钱
  • 建网站难吗怎么把网站排名排上去
  • 出售东西的网站怎么做网络营销前景和现状分析
  • 武汉便宜做网站海会网络做的网站怎么做优化