ES使用过程中遇到的问题

1、深度分页问题

之前已经总结过了,具体的可以参考下之前的博客:ES深度分页

2、ES默认分页问题

准确的说,并不是 ElasticSearch的问题,而是其客户端 JestClient的问题。

默认情况下,SearchSourceBuilder不设置分页信息的话,默认查询 10条数据。试想,若符合条件的结果集大于 10的且没有显式设置分页信息,那么必然会出现结果集数据丢失的问题,进而造成 BUG!

如果不明确本次分页的大小(页面分页查询是可以明确的),那么建议大家查询数据前,先进行 count,然后再根据 count值进行分页设置。

searchSourceBuilder.size(pageSize);
searchSourceBuilder.from(dataFrom);

2.1、思考:

是否存在一种机制,可以在开发者没有设置分页信息的情况下,默认为其赋予一个合理的分页信息,尽可能保证符合条件的结果集完整性?
可以看到查询的语句是:

SearchResult result = jestMultiThreadClient.execute(search);

这种需求,很适合使用 AOP来解决。
具体的逻辑如下:

/**
 * @author tly
 * 带有分页的语句:{"from":1,"size":10,"query":{"bool":{"must":[{"terms":{"id":[1,2],"boost":1.0}}],"adjust_pure_negative":true,"boost":1.0}},"sort":[{"id":{"order":"desc"}}]}
 * 不带有分页的语句:{"query":{"bool":{"must":[{"terms":{"id":[1,2],"boost":1.0}}],"adjust_pure_negative":true,"boost":1.0}},"sort":[{"id":{"order":"desc"}}]}
 */
@Aspect
@Component
@Slf4j
public class JestExecuteAspect {

    @Autowired
    @Qualifier("jestMultiThreadClient")
    private JestClient jestMultiThreadClient;

    @Pointcut("execution(* io.searchbox.client.JestClient.execute(..))")
    public void jestExecutePoint(){

    }

    @Around("jestExecutePoint()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        // 只处理方法参数是 Action<T>
        if (args.length != 1) {
            return joinPoint.proceed();
        }
        Action action = (Action) args[0];
        // 若不是 Search类型,则放行
        if (!(action instanceof Search)) {
            return joinPoint.proceed();
        }
        Search search = (Search) action;
        try {
            // 获取到 Search中的的 query(查询的 es语句)
            Field queryField = Search.class.getDeclaredField("query");
            queryField.setAccessible(true);
            Object obj = queryField.get(search);
            // 判断是否已经存在分页信息了
            SearchSourceBuilderTemp builder = JsonTools.defaultMapper().fromJson(obj.toString(), SearchSourceBuilderTemp.class);
            if (builder.getFrom() >= 0 || builder.getSize() >= 0) {
                // 存在分页信息,则放行
                return joinPoint.proceed();
            }
            log.error("JestExecuteAspect检测到没有配置分页信息!");
            String str = obj.toString();
            // 默认先进行 count统计出数量
            Count count = new Count.Builder()
                    .addIndex(search.getIndex())
                    .query(str)
                    .build();
            CountResult result = jestMultiThreadClient.execute(count);
            Double counts = result.getCount();
            // 若没有统计出来,则默认 size为 10。考虑到深度分页的问题,默认最大值为 60000
            int size = counts == null ? 10 : Math.min(counts.intValue(), 60000);
            // 设置分页信息
            str = str.charAt(0) + "\"from\":0,\"size\":" + size + "," + str.substring(1);
            queryField.set(search, str);
            return joinPoint.proceed();
        } catch (Exception e) {
            log.info("jestExecutePoint出现异常,走原逻辑. {}", e);
        }
        return joinPoint.proceed();
    }

    @Data
    public static class SearchSourceBuilderTemp {
        private int from = -1;

        private int size = -1;
    }
}

单元测试结果:


debug结果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容