# es-plus **Repository Path**: hzh727172424/es-plus ## Basic Information - **Project Name**: es-plus - **Description**: es-plus elasticsearch增强框架 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 0 - **Created**: 2022-09-26 - **Last Updated**: 2025-08-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: ElasticSearch, ORM, 控制台, es查询简化 ## README ## 什么是 Es-Plus Es-Plus 是Elasticsearch Api增强工具 - 只做增强不做改变,简化`CRUD`操作. ## 特点 - **无侵入**:Es-Plus 在 rest-high-level-client 的基础上进行扩展,只做增强不做改变.支持原生rest-high-level-client - **融合mybatis-plus语法和ES-Rest-Api**: 适用于习惯mybatis-plus语法和会原生es语句操作的人群 - **优雅的聚合封装**:让es的聚合操作变得更简易 - **内置es所有分词器**:提供es所有的分词器和可配置定义filters - **自动reindex功能**:es索引库属性的改变会导致es需要重建索引.重建索引的数据迁移由框架自动完成.使用了读写锁,确保reindex过程中额外生成的数据也能同步(但会有删除数据的冗余) - **兼容es多版本**: 同时支持es6.7和es7.8双版本 - **优雅的nested嵌套查询**: 使用lambda表达式封装实现更优雅的嵌套查询 - **静态链式es编程**: 支持使用静态类,无需指定对应实体类即可执行。可以简单快速对es的索引进行增删改查。 - **多数据源es**: 通用@EsIndex指定默认数据源 - **自定义es执行前后拦截器**: @EsInterceptors 具体用法见下面的例子 - **提供Es控制台页面**: 新功能-提供es多数据源增删改查的控制台 详见下方例子 ## 引入 目前使用版本0.4.72 本次更新 - **多数据源es**: 通用@EsIndex指定默认数据源 - **自定义es执行前后拦截器**: @EsInterceptors 具体用法见下面的例子 优化了查询api的使用,更贴近es的查询语法 ``` xml io.github.zhaohaoh es-plus-spring-boot-starter Latest Version ``` ## 新-es控制台类似navicat es-head的es查询编辑工具。 ### 下载es-plus-console的jar包 java -jar启动后 自动打开网站 ![img.png](img.png) ![img_1.png](img_1.png) ## 简单两步! 快速开始! ### 第一步 application.peoperties配置 ```properties # es地址 多个逗号分隔 默认数据源 master es-plus.address=xxx.xxx.xxx.xxx:9200 # 是否异步reindex es-plus.global-config.reindex-async=false # 是否开启自动reindex. 如果没有开启也会自动对新增的字段添加映射 es-plus.global-config.index-auto-move=false # 查询最大数量的限制 es-plus.global-config.search-size=5000 # 索引添加统一的环境后缀 测试环境 es-plus.global-config.global-suffix=_test # 索引全局默认分词器 默认值ep_standard 可选 #ep_ik_max_word,ep_ik_smart,ep_simple,ep_keyword,ep_stop,ep_whitespace,ep_pattern,ep_language,ep_snowball es-plus.global-config.default-analyzer=ep_ik_max_word # 自定义全局refresh策略 es-plus.global-config.refresh-policy=wait_until # 全局默认获取es的id的字段 默认id es-plus.global-config.global-es-id=id es-plus.username= es-plus.password= # es多版本 es-plus.global-config.version=7 ##es多数据源 local是数据源名称,可自定义 es-plus.client-properties.local.address=localhost:9100 ``` ### 第二步 静态链式编程 ```java public class SamplesEsService extends EsServiceImpl { // 无实体类使用指定index索引直接保存 查询同理 public void update() { Map map = new HashMap<>(); map.put("username", "fsdfsfds"); map.put("id", "d73d1b4e46244b0db766987759d6e"); Es.chainUpdate(Map.class).index("sys_user2ttt").save(map); } public void newSelect() { EsResponse aaaaa = Es.chainLambdaQuery(SamplesEsDTO.class).term(SamplesEsDTO::getUsername, "hzh").list(); System.out.println(aaaaa); } } ``` ## ORM映射方式 ### 实体类 没有配置@EsField会根据java自动映射.获取不到映射则设置为Object ```java @Data @EsIndex(index = "sys_user1") public class SysUser { @EsId private Long id; @EsField(type = EsFieldType.STRING) private String username; /** * 昵称 */ private String nickName; private String phone; /** * 真实姓名 */ private String realName; /** * 是否锁定 */ private Integer lockState; @EsField(type = EsFieldType.NESTED) private SysRole sysRole; private List ids; } ``` ### 常规查询 ```java @Service public class SysUserEsService extends EsServiceImpl{ public void search() { // 声明语句嵌套关系是must EsResponse esResponse = esChainQueryWrapper().must() .terms(SysUser::getUsername, "admin", "hzh", "shi") // 多个must嵌套 .must(a -> // 声明内部语句关系的should a.should() .term(SysUser::getRealName, "dasdsad") .term(SysUser::getPhone, "1386859111")) // 查询 .list(); List list = esResponse.getList(); } public void agg() { // 声明语句嵌套关系是must EsChainQueryWrapper esChainQueryWrapper = esChainQueryWrapper().must() .terms(SysUser::getUsername, "admin", "hzh", "shi") // 多个must嵌套 .must(a -> // 声明内部语句关系的should a.should() .term(SysUser::getRealName, "dasdsad") .term(SysUser::getPhone, "1386859111")); esChainQueryWrapper.esLambdaAggWrapper() // terms聚合并且指定数量10000 .terms(SysUser::getUsername, a -> a.size(10000)) // 在terms聚合的基础上统计lock数量 .subAggregation(t -> t.count(SysUser::getLockSate)); EsResponse esResponse = esChainQueryWrapper // 查询 .list(); List list = esResponse.getList(); EsAggregationsResponse esAggregationsReponse = esResponse.getEsAggregationsReponse(); // 以下方法选一种 Terms terms = esAggregationsReponse.getTerms(SysUser::getUsername); Map termsAsMap = esAggregationsReponse.getTermsAsMap(SysUser::getUsername); } //嵌套对象的查询 public void nested() { EsChainLambdaQueryWrapper asChainQueryWrap = new EsChainLambdaQueryWrapper<>(SamplesNestedDTO.class); asChainQueryWrap.should().term(SamplesNestedDTO::getUsername, "hzh"); asChainQueryWrap.terms(SamplesNestedDTO::getUsername, "term"); // 声明语句嵌套关系是must EsChainLambdaQueryWrapper queryWrapper = esChainQueryWrapper().must() .nestedQuery( SamplesEsDTO::getSamplesNesteds, (esQueryWrap) -> { esQueryWrap.mustNot().term("state", false); esQueryWrap.mustNot().term("id", 2L); }); EsResponse esResponse = queryWrapper.list(); //lambda写法 EsChainLambdaQueryWrapper queryWrapper = esChainQueryWrapper().must() .nestedQuery( SamplesEsDTO::getSamplesNesteds,SamplesNestedDTO.class, (esQueryWrap) -> { esQueryWrap.mustNot().term(SamplesNestedDTO::getState, false); esQueryWrap.mustNot().term(SamplesNestedDTO::getId, 2L); }); EsResponse esResponse = queryWrapper.list(); // 查询 List list = esResponse.getList(); } //优雅的nested嵌套查询 //三级嵌套对象附加innerHits查询方法 一级对象SamplesEsDTO 二级对象SamplesNestedDTO 三级对象 SamplesNestedInnerDTO public void nested() { //获取二级查询条件 Consumer> innerConsumer = getSamplesNestedConsumer(); // InnerHit InnerHitBuilder innerHitBuilder = new InnerHitBuilder("test"); innerHitBuilder.setSize(10); //一级查询条件 EsChainLambdaQueryWrapper queryWrapper = esChainQueryWrapper().must() .nestedQuery(SamplesEsDTO::getSamplesNesteds, SamplesNestedDTO.class, innerConsumer, ScoreMode.None,innerHitBuilder); EsResponse esResponse = queryWrapper.list(); // 查询 List list = esResponse.getList(); } /** * 获取二级嵌套查询对象 */ private Consumer> getSamplesNestedConsumer() { Consumer> innerConsumer = (esQueryWrap) -> { esQueryWrap.must().term(SamplesNestedDTO::getUsername, "3"); InnerHitBuilder innerHitBuilder1 = new InnerHitBuilder(); innerHitBuilder1.setSize(100); Consumer> innerInnerConsumer = getSamplesNestedInnerConsumer(); esQueryWrap.must().nestedQuery(SamplesNestedDTO::getSamplesNestedInner, SamplesNestedInnerDTO.class, innerInnerConsumer, ScoreMode.None, innerHitBuilder1); }; return innerConsumer; } /** * 获取三级嵌套查询对象 */ private Consumer> getSamplesNestedInnerConsumer() { Consumer> innerInnerConsumer = (innerQuery) -> { innerQuery.must().term(SamplesNestedInnerDTO::getUsername, 3); }; return innerInnerConsumer; } } ``` ## 最新拦截器案例 ```java @Component @EsInterceptors(value = { //需要拦截的类名和方法。 类EsPlusClient和EsPlusIndexClient。增删改查数据类,索引增删改类。参数中还可以指定索引名。 @InterceptorElement(type = EsPlusClient.class, methodName = "search") }) public class EsSearchAfterInterceptor implements EsInterceptor { @Override public void before(String index, Method method, Object[] args) { Integer page = null; Integer size = null; EsParamWrapper esParamWrapper = null; EsQueryParamWrapper esQueryParamWrapper = null; for (Object arg : args) { if (arg instanceof EsParamWrapper) { esParamWrapper = (EsParamWrapper) arg; esQueryParamWrapper = esParamWrapper.getEsQueryParamWrapper(); page = esQueryParamWrapper.getPage(); size = esQueryParamWrapper.getSize(); if (esQueryParamWrapper.getEsSelect()!= null && !esQueryParamWrapper.getEsSelect().getFetch()){ return; } if (esQueryParamWrapper.getSearchAfterValues()!=null){ return; } break; } } if (esParamWrapper == null || page == null | size == null) { return; } //执行你的逻辑 } @Override public void after(String index, Method method, Object[] args, Object result) { Integer page = null; Integer size = null; for (Object arg : args) { if (arg instanceof EsParamWrapper) { EsParamWrapper esParamWrapper = (EsParamWrapper) arg; EsQueryParamWrapper esQueryParamWrapper = esParamWrapper.getEsQueryParamWrapper(); page = esQueryParamWrapper.getPage(); size = esQueryParamWrapper.getSize(); if (esQueryParamWrapper.getEsSelect()!= null && !esQueryParamWrapper.getEsSelect().getFetch()){ return; } break; } } int endIndex = page * size; EsResponse response = (EsResponse) result; //执行你的逻辑 } } ``` ## Es版本 遇到版本冲突使用6.7.0和7.8.0 ## 自动Reindex reindex功能默认关闭,暂不建议生产开启。 #### 如何开启: es-plus.global-config.auto-reindex=true #### 开启异步reindex es-plus.global-config.reindex-async=true #### 注意事项 reindex会有部分删除数据的冗余.但是通过锁保证了新增和更新数据的错误.但是依然建议在业务低峰期执行. - [流程图](https://github.com/zhaohaoh/es-plus/blob/master/reindex%E6%B5%81%E7%A8%8B%E5%9B%BE.md) ## 作者 微信:huangzhaohao1995 # 版权 | License [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)