ElasticSearch分页查询性能及封装实现

Es的分页方式

from+size

最基本的分页方式,类似于SQL中的Limit语法:

//查询年龄在12到32之间的前15条数据
{"query":{"bool":{"must":{"range":{"user_age":{"gte":12,"lte":32}}}}},"sort":{"user_age":{"order":"desc"}}"from":0,"size":15
}

 与Limit一样,from+size分页是通过设置from参数来指定返回结果的起始位置,而size参数来指定返回结果的数量。这里的页码在程序中需要额外进行处理一下,因为from是从0开始的,而size代表返回的条数,使用时需要对页码参数进行 :

from = (pageNo - 1) * pageSize 

 原理

 Es的查询过程如上图,即一个查询请求,在集群环境下是会被协调到各个节点中,最终落到对应索引的分片上,由每个分片进行查询,最终将数据回给主节点进行汇总。而使用from+size的分页,每个分片的处理则是这样的:

  • 搜索请求通常跨越多个分片,每个分片必须将其请求的命中内容以及任何先前页面的命中内容加载到内存中。
  • 对于翻页较深的页面或大量结果,这些操作会显著增加内存和 CPU 使用率,从而导致性能下降或节点故障。

例如,from=10000,size=10,需要将10010 条数据加载到内存,这通常意味着需要从多个分片中收集数据,然后在协调节点上进行合并和排序,然后经过后台处理后返回了最后 10条我们想要的数据。这个过程随着数据量的增加而变得更加复杂和资源密集,那也就意味着,越往后翻页(也就是深度翻页)需要加载的数据量越大,势必会越耗费 CPU + 内存资源,响应也会越慢。

性能

默认情况下,from+size 的限制是 10000,这意味着 from 参数加上 size 参数的值不能超过 10000,这是为了避免大数据量的召回导致性能低下。如果你尝试进行深度分页,超过了这个限制,Elasticsearch 会抛出错误,提示结果窗口太大。

为了解决这个问题,可以通过调整 index.max_result_window 的值来增加这个限制,但这通常不推荐,因为它会增加内存和 CPU 使用率,可能导致性能下降或节点故障

超出from+size限制报错:

"root_cause": [{"type": "illegal_argument_exception","reason": "Result window is too large, from + size must be less than or equal to: [10000] but was [10001]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting."}],"type": "search_phase_execution_exception",

scroll分页

原理

当发起一个带有 scroll 参数的搜索请求时,Elasticsearch 的分片会为这次搜索创建一个上下文,然后各分片基于快照数据进行相应的查询,每轮查询结束后,会记录一个scrollId,将这批结果以及对应的scrollId返回给客户端。

此时客户端根据返回的scrollId再次发起查询,此时Es服务端会根据该scrollId,找到所属的上下文,并基于上次查询的结果的尾段进行继续查询,相比from+size的每次查询都需要重复大数据量的召回,scroll查询有效的避免了召回操作。减少了CPU、IO的消耗。

性能

相比from+size的重复大批量数据召回消耗CPU和IO,Scroll是更友好且适合大数据量的深度查询(不受制于max_result_window),但是Scroll提高性能的代价是牺牲实时性;当开始一个 scroll session 时,Elasticsearch 会创建一个索引的快照(上下文中),这个快照代表了初始化搜索请求时的索引状态。在 scroll session 的生命周期内,即使索引发生了变化(如新增、删除或更新文档),这些变化也不会反映在后续的滚动查询中。

同时,快照、上下文维护的存在必然导致需要更多的内存来支撑

官方文档强调:不再建议使用scroll API进行深度分页。如果要分页检索超过 Top 10,000+ 结果时,推荐使用:PIT + search_after。

search_after分页

原理

search_after 是 Elasticsearch 5.0 以上版本提供的一种分页查询机制,用于解决深度分页的性能问题。它通过维护一个实时游标来避免传统 from+size 分页方式在处理大量数据时的性能损耗,也不需要像 scroll API 那样创建和维护一个历史快照,从而减少了资源的占用。

search_after进行查询时,必须指定排序字段,它使用上一次查询的最后一个文档的排序值来获取下一页数据。不同于scroll基于快照的查询,search_after是基于实时的数据,不需要维护一个很大的快照。 

性能

search_after 是一种无状态的分页方式,它不需要维护搜索上下文,因此不会占用额外的资源。每次请求都会根据上一次请求的最后一个文档的排序值来获取下一页数据,这样可以避免大量的内存消耗。search_after 提供了更好的实时性,因为它每次请求都会反映索引的最新状态。这意味着在查询过程中如果有数据的更新,这些变化会反映在分页结果中

场景及优缺点汇总

基于RestHighLevelClient的实现

RestHighLevelClient 是 Elasticsearch 的高级 Java 客户端,它提供了一套简单易用的 API 来与 Elasticsearch 服务器进行交互。

RestHighLevelClient位于org.elasticsearch.client包下,常用功能包括:

方法名称入参使用样例备注
createIndexclientRestHighLevelClient 实例, indexName: 索引名称createIndex(client, "my_index");创建索引 
deleteIndexclientRestHighLevelClient 实例, indexName: 索引名称deleteIndex(client, "my_index");删除索引 
indexrequestIndexRequest 对象client.index(request, RequestOptions.DEFAULT);插入数据 
getrequestGetRequest 对象client.get(request, RequestOptions.DEFAULT);根据ID获取数据 
updaterequestUpdateRequest 对象client.update(request, RequestOptions.DEFAULT);更新数据 
deleterequestDeleteRequest 对象client.delete(request, RequestOptions.DEFAULT);根据ID删除数据 
searchrequestSearchRequest 对象client.search(request, RequestOptions.DEFAULT);搜索数据 
scrollrequestSearchScrollRequest 对象client.scroll(request, RequestOptions.DEFAULT);滚动搜索 
clearScrollrequestClearScrollRequest 对象client.clearScroll(request, RequestOptions.DEFAULT);清除滚动ID 
bulkrequestBulkRequest 对象client.bulk(request, RequestOptions.DEFAULT);批量操作 
countrequestCountRequest 对象client.count(request, RequestOptions.DEFAULT);计数查询 
existsrequestGetRequest 对象client.exists(request, RequestOptions.DEFAULT);检查文档是否存在 
updateByQueryrequestUpdateByQueryRequest 对象client.updateByQuery(request, RequestOptions.DEFAULT);根据查询更新数据 
deleteByQueryrequestDeleteByQueryRequest 对象client.deleteByQuery(request, RequestOptions.DEFAULT);根据查询删除数据 

其中 BulkRequest 、GetRequest 等参数,均为ActionRequest的子类,具体使用方式可以参考下文。

其中DSL语法可配合org.elasticsearch.search.builder包中的Builder来进行构建,eg:

 public void test(){SearchSourceBuilder searchBody = new SearchSourceBuilder().from(0).size(10).query(QueryBuilders.boolQuery().filter(QueryBuilders.termQuery("user_name","张三")).must(QueryBuilders.termQuery("age",12))).sort("id", SortOrder.DESC).fetchSource(Arrays.asList("id","name","age").toArray(new String[0]),new String[0]).aggregation(AggregationBuilders.terms("Test").field("className").size(15));}

form+size分页

定义es数据实体类 DocBaseEntity<T>类:

@Data
public class DocBaseEntity<T> implements Serializable {private String _index;private String _type;private String _id;private T datas;public DocBaseEntity(SearchHit data) {this._index = data.getIndex();this._type = data.getType();this._id = data.getId();}public DocBaseEntity(JSONObject jsonHits){this._index = jsonHits.getStr("_index");this._type = jsonHits.getStr("_type");this._id = jsonHits.getStr("_id");}public T getDatas(){return datas;}}

查询返回实体类SearchResult<T>

@Data
public class SearchResult<T> implements Serializable {private int total;private List<DocBaseEntity<T>> source = new ArrayList<>();private JSONObject aggregations;public void addData(DocBaseEntity<T> obj){source.add(obj);}public List<T> getDatas(){return source.stream().map(DocBaseEntity::getDatas).collect(Collectors.toList());}public void addDatas(List<DocBaseEntity<T>> objs){source.addAll(objs);}public void setTotal(Object total){this.total = Integer.parseInt(String.valueOf(total));}public JSONObject toJSONObject(){return JSONUtil.parseObj(this,true);}}

定义查询接口ElasticSearchActuator


public interface ElasticSearchActuator {/*** from+size 分页查询* @param indexName 索引名称* @param searchSourceBuilder 查询条件* @param pageNo 页码* @param pageSize 每页数量* @param resultObj 具体目标对象* @return SearchResult*/<T> SearchResult<T> fromSizeSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,Class<T> resultObj);}

 from+size分页实现

@Component
@Slf4j
public class ElasticSearchActuatorImpl implements ElasticSearchActuator {//restHighLevelClient客户端Configure相关单独编写,这里不再复述@Autowirdprivate RestHighLevelClient restHighLevelClient;private final static Integer MAX_RESULT_WINDOW = 10000;  @Overridepublic <T> SearchResult<T> fromSizeSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,Class<T> resultObj){SearchResult<T> resultMap = new SearchResult<T>();//提前规避超出长度的情况if( from+size >= MAX_RESULT_WINDOW){log.error("XXXXXXX")//其他操作return null;}//分页参数处理int from = (pageNo - 1) * pageSize;searchSourceBuilder.from(from).size(pageSize);SearchRequest searchRequest = new SearchRequest(indexName);searchRequest.source(SearchSourceBuilder );SearchResponse response = executSearch(searchRequest);if(null != response){return  createSearchResult(searchResp,resultObj);}return resultMap;}/*** 执行查询*//*** 执行查询*/private SearchResponse executSearch(SearchRequest searchRequest)     {SearchResponse searchResponse = null;try{searchResponse = restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);}catch(Exception e){//异常处理}return searchResponse;}/*** 构建目标结果* @param response 返回参数* @param resultObj 类对象* @param <T>* @return*/private <T> SearchResult<T> createSearchResult(SearchResponse response,Class<T> resultObj){SearchResult<T> resultMap = new SearchResult<>();SearchHit[] datas = response.getHits().getHits();for(SearchHit data:datas){DocBaseEntity<T> temp = new DocBaseEntity<>(data);temp.setDatas(JSONUtil.toBean(JSONUtil.parseObj(data.getSourceAsMap()),resultObj));resultMap.addData(temp);}resultMap.setTotal(response.getHits().getTotalHits().value);return resultMap;}}

scroll分页

SearchResult<T>补充scrollId值:

@Data
public class SearchResult<T> implements Serializable {private int total;//scrollIdprivate String scrollId;private List<DocBaseEntity<T>> source = new ArrayList<>();private JSONObject aggregations;public void addData(DocBaseEntity<T> obj){source.add(obj);}public List<T> getDatas(){return source.stream().map(DocBaseEntity::getDatas).collect(Collectors.toList());}public void addDatas(List<DocBaseEntity<T>> objs){source.addAll(objs);}public void setTotal(Object total){this.total = Integer.parseInt(String.valueOf(total));}public JSONObject toJSONObject(){return JSONUtil.parseObj(this,true);}}

继续定义查询接口ElasticSearchActuator


public interface ElasticSearchActuator {/*** from+size 分页查询* @param indexName 索引名称* @param searchSourceBuilder 查询条件* @param pageNo 页码* @param pageSize 每页数量* @param resultObj 具体目标对象* @return SearchResult*/<T> SearchResult<T> fromSizeSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,Class<T> resultObj);/*** 滚动分页查询* @param indexName 索引* @param searchSourceBuilder 查询体* @param pageNo 页码* @param pageSize 每页条数* @param scrollId 滚动ID* @param resultObj 目标对象* @return SearchResult* @param <T> T*/<T> SearchResult<T> scrollSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,String scrollId,Class<T> resultObj);}

实现类:

@Component
@Slf4j
public class ElasticSearchActuatorImpl implements ElasticSearchActuator {//restHighLevelClient客户端Configure相关单独编写,这里不再复述@Autowirdprivate RestHighLevelClient restHighLevelClient;private final static Integer MAX_RESULT_WINDOW = 10000;  @Overridepublic <T> SearchResult<T> fromSizeSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,Class<T> resultObj){//……省略from+size查询}@Overridepublic <T> SearchResult<T> scrollSearchElasticSearchDatas(String indexName, SearchSourceBuilder searchSourceBuilder, int pageNo, int pageSize, String scrollId, Class<T> resultObj) throws IOException {SearchRequest searchRequest = new SearchRequest(indexName);searchSourceBuilder.size(pageSize);//设定scroll失效时长Scroll scroll = new Scroll(TimeValue.timeValueMinutes(3));searchRequest.scroll(scroll);SearchResponse searchResponse = null;if(StringUtils.isEmpty(scrollId)){searchResponse = executSearch(searchRequest);String tempscrollId = searchResponse.getScrollId();SearchScrollRequest searchScrollRequest = new SearchScrollRequest(tempscrollId);searchScrollRequest.scroll(scroll);for (int i = 0; i < (pageNo -1); i++) {searchResponse = scrollSearch(searchScrollRequest);}scrollId = tempscrollId;}else {SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);searchResponse = scrollSearch(searchScrollRequest);}//构建结果SearchResult<T> result = createSearchResult(searchResponse,resultObj);result.setSrcollId(scrollId);clearScrollSession(scrollId);return result;}/*** 滚动查询执行* @param searchScrollRequest* @return*/private  SearchResponse scrollSearch(SearchScrollRequest searchScrollRequest){SearchResponse searchResponse = null;try{searchResponse = restHighLevelClient.scroll(searchScrollRequest,RequestOptions.DEFAULT);}catch(Exception e){//异常处理}return searchResponse;}/*** 关闭scroll* @param scrollId* @throws IOException*/private void clearScrollSession(String scrollId) throws IOException {if (scrollId != null) {ClearScrollRequest clearScrollRequest = new ClearScrollRequest();clearScrollRequest.addScrollId(scrollId);ClearScrollResponse clearScrollResponse = restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);clearScrollResponse.isSucceeded();}}}

注意:

使用scroll查询,如果设置的scroll超时,scroll ID会在指定的超时时间内保持活跃,这个超时时间可以通过scroll参数设置。一旦超出这个时间限制,scroll ID将失效,但是不会自动清理。为了避免资源泄露,建议在scroll使用完毕后,显式地清理scroll上下文。

这里最好建立一层缓存记录,即每次客户发来请求后,记录当次查询的scrollId序列,然后定时的释放掉缓存中不用的序列。

search_after分页

 对SearchResult<T>补充sortId值:

@Data
public class SearchResult<T> implements Serializable {private int total;//scrollIdprivate String scrollId;//sortIdprivate List<Object> sortId;private List<DocBaseEntity<T>> source = new ArrayList<>();private JSONObject aggregations;public void addData(DocBaseEntity<T> obj){source.add(obj);}public List<T> getDatas(){return source.stream().map(DocBaseEntity::getDatas).collect(Collectors.toList());}public void addDatas(List<DocBaseEntity<T>> objs){source.addAll(objs);}public void setTotal(Object total){this.total = Integer.parseInt(String.valueOf(total));}public JSONObject toJSONObject(){return JSONUtil.parseObj(this,true);}}

继续定义查询接口ElasticSearchActuator

public interface ElasticSearchActuator {/*** from+size 分页查询* @param indexName 索引名称* @param searchSourceBuilder 查询条件* @param pageNo 页码* @param pageSize 每页数量* @param resultObj 具体目标对象* @return SearchResult*/<T> SearchResult<T> fromSizeSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,Class<T> resultObj);/*** 滚动分页查询* @param indexName 索引* @param searchSourceBuilder 查询体* @param pageNo 页码* @param pageSize 每页条数* @param scrollId 滚动ID* @param resultObj 目标对象* @return SearchResult* @param <T> T*/<T> SearchResult<T> scrollSearchElasticSearchDatas(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,String scrollId,Class<T> resultObj);/*** aftersearch分页查询* @param indexName 索引* @param searchSourceBuilder 查询体dsl* @param pageNo 页码* @param pageSize 每页条数* @param sortId 排序游标* @param resultObj 目标对象* @return SearchResult* @param <T> T*/<T> SearchResult<T> afterSearchElasticSearchData(String indexName,SearchSourceBuilder searchSourceBuilder,int pageNo,int pageSize,List<Object> sortId,Class<T> resultObj);}

实现类:

@Component
@Slf4j
public class ElasticSearchActuatorImpl implements ElasticSearchActuator {//……其他逻辑@Overridepublic <T> SearchResult<T> afterSearchElasticSearchData(String indexName, SearchSourceBuilder searchSourceBuilder, int pageNo, int pageSize, List<Object> sortId, Class<T> resultObj) {SearchRequest searchRequest = new SearchRequest(indexName);searchSourceBuilder.size(pageSize);if(!CollectionUtils.isEmpty(sortId)){searchSourceBuilder.searchAfter(sortId.toArray());}else {if(pageNo > 1){//如果不携带上次排序标识,且非首页,递归查询SearchResult<T> previousPage = afterSearchElasticSearchData(indexName,searchSourceBuilder,pageNo-1,pageSize,null,resultObj);searchSourceBuilder.searchAfter(previousPage.getSortId().toArray());}searchRequest.source(searchSourceBuilder);}try{SearchResponse response = executSearch(searchRequest);SearchResult<T> rest = createSearchResult(response,resultObj);SearchHit[] hits = response.getHits().getHits();if(hits.length > 0){rest.setSortId(Arrays.asList(hits[hits.length-1].getSortValues()));}return rest;}catch (Exception e){//异常处理log.error("XXXXXX");}return null;}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/433453.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于飞腾平台的OpenCV的编译与安装

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

量化交易backtrader实践(三)_指标与策略篇(1)_指标简介与手工双均线策略

01_指标 指标是一个汉语词语&#xff0c;读音是zhǐ biāo&#xff0c;意思是衡量目标的参数&#xff1b;预期中打算达到的指数、规格、标准&#xff0c;一般用数据表示。 统计学术语 指标是说明总体数量特征的概念及其数值的综合&#xff0c;故又称为综合指标。在实际的统计…

YOLOv7改进之MAE主干: 超强ConvNeXtV2 升级版结构,当MAE+YOLO卷积高效涨点

目录 1,原理概述 2,代码改进 新增一个convnextv2.py文件,增加以下代码 修改部分 第二步:在yolo.py中加入以下代码 然后在 在yolo.py中配置找到./models/yolo.py文件下里的parse_model函数,将类名加入进去 参考代码 YOLOv7网络配置文件 1,原理概述 原文:https://…

openinstall鸿蒙SDK再升级,功能全面支持HarmonyOS NEXT

万众期待的鸿蒙操作系统HarmonyOS NEXT即将发布&#xff0c;国产自主的全场景智能操作系统诞生&#xff0c;将为生态伙伴共创共享创造新蓝海&#xff0c;鸿蒙生态的加速构建&#xff0c;也有望催生出互联网生态的第三极。 作为首批鸿蒙生态伙伴&#xff0c;openinstall在App渠…

这些主流的财务管理软件,你用过哪款?

在当今的商业环境中&#xff0c;财务管理面临着诸多棘手的痛点问题&#xff1a; 数据的准确性与及时性难以保证&#xff0c;手工录入易出错且数据更新常不及时&#xff1b; 预算管理困难重重&#xff0c;编制不合理且执行监控难&#xff1b; 财务风险管控不足&#xff0c;应…

Cannot read properties of undefined (reading ‘upgrade‘)

前端开发工具&#xff1a;VSCODE 报错信息&#xff1a; INFO Starting development server...10% building 2/2 modules 0 active ERROR TypeError: Cannot read properties of undefined (reading upgrade)TypeError: Cannot read properties of undefined (reading upgrade…

k8s中,pod生命周期,初始化容器,容器探针,事件处理函数,理解其设计思路及作用

k8s中&#xff0c;为什么要设计pod 平台直接管理容器不是挺好的吗 为什么要以pod为单位进行管理&#xff0c; 然后把容器放在pod里面 那么有pod和没pod的区别是什么 也就是pod提供了什么作用 这个可以考虑从pod生命周期管理的角度去思考 如图&#xff0c;pod主容器在运行…

无限大薄板的电场

单块无限大薄板两端的电场 单块无限大的薄板&#xff0c;如果上面带有均匀分布的电荷&#xff0c;就会在薄板的两侧产生电场&#xff0c;电场大小与距离平板的位置无关&#xff0c;方向与平板垂直&#xff0c;如果平板带正电荷&#xff0c;则电场方向向外指向两侧&#xff0c;…

【性能优化】低配starRocks常驻内存优化

背景说明 由于服务器的实际资源小于starRocks官方的配置&#xff0c;导致starRocks在无任务的情况下&#xff0c;常驻内存偏高&#xff0c;可用于查询的资源变小。 官方文档 实际部署的集群一般是4C8G和8C16G&#xff0c;be的配置不达标 为了解决单次查询内存不足的问题&…

史上最详细论文word排版格式指导保姆级教学!

一、前言 首先&#xff0c;每个学校的论文排版格式都是不太相同的&#xff0c;但大体上都是相似的。 正常来说&#xff0c;论文的排版操作是十分枯燥并且重复的&#xff0c;但是word中的样式工具使得论文排版会变得容易。 接下来我将以某个学校论文格式要求为例&#xff0c;…

python socket编程

socket socket&#xff08;套接字&#xff09;是进程间通信的工具&#xff0c;好比现实生活中的插座&#xff0c;所有家电想要工作都是基于插座进行&#xff0c;进程之间想要进行网络通信需要socket socket负责进程之间的网络数据传输&#xff0c;好比数据的搬运工 2个进程之…

动态规划入门题目->使用最小费用爬楼梯

1.题目&#xff1a; 2.解析&#xff1a; 做题模式&#xff1a; 步骤一&#xff1a;找状态转移方程 步骤二&#xff1a;初始化 步三&#xff1a;填表 步骤四&#xff1a;返回-> dp[n] dp[i]表示到达 i 位置最小花费 逻辑&#xff1a;要爬到楼顶先找到 i 位置 &#xff0c; 要…

高通Android 12 push framework.jar和service.jar

1、Android framework.jar和service.jar替换注意事项 2、单编 adb push service.jar脚本 如下 adb root adb disable-verity adb remountadb push services.jar system/framework adb push services.jar.prof system/framework adb push oat/arm64/services.art /system/fram…

SpringBoot日志集成-LogBack

Log4J&#xff1a;最早的Java日志框架之一&#xff0c;由Apache基金会发起&#xff0c;提供灵活而强大的日志记录机制JDK自带的日志框架&#xff1a;java.util.logging.Logg&#xff0c;是JDK1.4之后提供的日志API&#xff0c;已淘汰logback&#xff1a; logback一个开源的日志…

delphi制作漂亮的农历窗体(IntraWeb+Layui的完美结合)

delphi制作漂亮的农历窗体&#xff08;IntraWebLayui的完美结合&#xff09; 不需要安装服务器&#xff0c;Apache和IIS都不需要&#xff0c;自带企业级服务器。 运行exe服务器就架好了&#xff0c;直接打开手机浏览器或者电脑浏览器&#xff0c;网页就出来了&#xff0c;如果…

sqli-lab靶场学习(四)——Less11-14(post方法)

前言 第1-10关都是get方法&#xff0c;本关开始进入post方法。其实post也好get也好&#xff0c;本质都差不多&#xff0c;使用的技巧也基本相同。 Less11 第11关打开是一个输入用户名密码的界面 显然登陆对话框会使用post方式提交&#xff0c;这里我们尝试在Username一栏通过…

时序预测 | Python实现KAN+LSTM时间序列预测

时序预测 | Python实现KAN+LSTM时间序列预测 目录 时序预测 | Python实现KAN+LSTM时间序列预测预测效果基本介绍程序设计预测效果 基本介绍 时序预测 | KAN+LSTM时间序列预测(Python) KAN作为这两年最新提出的机制,目前很少人用,很适合作为时间序列预测的创新点,可以结合…

CSS01-语法规范、基础选择器

一、CSS语法规范 示例&#xff1a; 二、CSS的基础选择器 选择器(选择符)就是根据不同需求把不同的标签选出来这就是选择器的作用。 简单来说&#xff0c;就是选择标签用的。 选择器的分类&#xff1a; 1、标签选择器 2、类选择器&#xff08;开发最常用&#xff09; 长字符命名…

误差不到1毫米的WGS84与CGCS2000坐标转换工具

我们在《WGS84与CGCS2000坐标的精密转换方法》一文中为你分享了一个WGS84与CGCS2000坐标的精密转换纯理论性的方法。 现在&#xff0c;再为你分享一个据说是误差不到1毫米的WGS84与CGCS2000坐标的转换工具&#xff0c;请从文末查看该工具的领取方法。 WGS84与CGCS2000坐标转换…

信息学奥赛的最佳启蒙阶段是小学还是初中?

信息学奥赛&#xff08;NOI&#xff09;近年来越来越受家长和学生的关注&#xff0c;尤其是在编程教育不断升温的背景下&#xff0c;信息学竞赛成为了许多家庭的教育选择之一。家长们往往关心的是&#xff1a;孩子应该在什么年龄段开始接触信息学竞赛&#xff0c;才能打下坚实的…