ES(Elasticsearch)分页查询通常使用 from
和 size
参数来控制查询结果的分页。from
用于指定从哪个结果开始,size
用于指定返回多少条记录。
示例查询
假设你想查询 my_index
索引,并且希望分页获取数据:
json
GET /my_index/_search { "from": 0, "size": 10, "query": { "match_all": {} } }
参数解释:
from
: 表示从第几条记录开始(默认为0,表示从第一条开始)。size
: 表示每页返回多少条记录。
分页逻辑:
- 第一页:
from = 0
,size = 10
(返回从0到9的记录)。 - 第二页:
from = 10
,size = 10
(返回从10到19的记录)。 - 第三页:
from = 20
,size = 10
(返回从20到29的记录)。
注意事项:
- 当你分页查询时,如果数据量非常大,建议使用
search_after
进行深分页,它比from/size
更高效。 from
和size
使用时会增加查询的开销,特别是在大数据集上。
from size
public List<ResFoodOrderInspectionVO> queryGroupByOrgGroupLocationCode(ReqFoodOrderInspectionVO reqVO) {
log.info("食用订单巡检表查询条件:{}", reqVO.toString());
StopWatch stopwatch = new StopWatch();
stopwatch.start();
List<ResFoodOrderInspectionVO> resList = Lists.newArrayList();
SearchRequest searchRequest = new SearchRequest(EsOperateTables.FOOD_ORDER_INSPECTION_V2.getAlias());
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.fetchSource(RES_FBASEFOODORDERINSPEC_FIELDS, null);
// searchSourceBuilder.size(0);// 设置为0代表不需要取查询到的所有数据,只需要取聚合的相关的数据
searchSourceBuilder.size(reqVO.getSize());
searchSourceBuilder.from((reqVO.getPage() - 1) * reqVO.getSize());
BoolQueryBuilder booleanQuery = QueryBuilders.boolQuery();
// 组装查询条件
buildBooleanQuery(booleanQuery, reqVO);
searchSourceBuilder.query(QueryBuilders.constantScoreQuery(booleanQuery));
// 分组,统计,排序
FoodOrderInspectionConvertor.groupCountAgg(searchSourceBuilder, reqVO, foodOrderInspectionDisabled);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = null;
try {
searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
stopwatch.stop();
} catch (IOException e) {
log.error(ErrorMsgConstant.FOODORDERINSPECTION_QUERYES_ERROR, e);
throw new OrderCenterException(ErrorMsgConstant.FOODORDERINSPECTION_QUERYES_ERROR);
}
if (Objects.isNull(searchResponse)) {
return Collections.emptyList();
}
Terms terms = searchResponse.getAggregations().get(FoodOrderInspectionConstant.GROUPDIMENSION);
if (Objects.isNull(terms)) {
return Collections.emptyList();
}
// 包含门店,且按日统计时,需要判断总量,其他场景,总分组量实际不会大于10000,不需要判断
if (CollectionUtils.isNotEmpty(reqVO.getLocationCodes()) && !reqVO.getGroupMonth() && searchResponse.getHits().getTotalHits() > FoodOrderInspectionConstant.GROUP_RETURN_SIZE) {
throw new OrderCenterException(ErrorMsgConstant.GROUP_TOTALSIZE_TOOLONG);
}
// 组装数据
for (Terms.Bucket entry : terms.getBuckets()) {
resList.add(FoodOrderInspectionConvertor.toResVO(entry, reqVO));
}
// 取聚合统计后合计
Map<String, Aggregation> totalMap = searchResponse.getAggregations().getAsMap();
resList.forEach(v -> {
v.setResFoodOrderInspectionTotalVO(FoodOrderInspectionConvertor.buildTotal(totalMap));
});
log.info("食用订单巡检报表查询耗时:{}", stopwatch.getTotalTimeMillis());
return resList;
}
}
searchAfter
java
private SearchRequest buildSearchRequest(EsSchemel esSchemel, QueryBuilder params, int pageSize, String orderBy, String scrollId) {
if (pageSize > 10000) {
//fixed:es error,from + size must be less than or equal to: [10000]
pageSize = 10000;
}
SearchRequest searchRequest = new SearchRequest(esSchemel.getIndex());
searchRequest.types(esSchemel.getType());
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(params);
//sourceBuilder.from(pageNo - 1);
sourceBuilder.size(pageSize);
sourceBuilder.timeout(new TimeValue(30, TimeUnit.SECONDS));
if (esSchemel.getSelectCols() != null && esSchemel.getSelectCols().length > 0) {
//性能参数,减少io
sourceBuilder.fetchSource(esSchemel.getSelectCols(), EXCLUDEFIELDS);
}
if (!Strings.isNullOrEmpty(orderBy)) {
sourceBuilder.sort(new FieldSortBuilder(orderBy).order(SortOrder.DESC));
if (!Strings.isNullOrEmpty(scrollId)) {
sourceBuilder.searchAfter(new Object[]{scrollId});
}
}
searchRequest.source(sourceBuilder);
return searchRequest;
}