Java博文
JAVA 21 都体验了吧
Java程序员必备的Intellij插件(长期更新,截止到2018-05-03) - 掘金
32.6k star🔥原来国内的独立开发者都在做这些事情
工作六年,我学会了用 Arthas 来辅助我的日常工作
太方便了!Arthas,生产问题大杀器 - 掘金
新一代Java高性能构建工具Maven-mvnd【实践可行版】
怎么在业务团队写好发消息的代码?
Intellij 开源热加载插件 HotSwapHelper 发布,兼容若依、jeecg 等框架
SpringBoot多环境日志配置_Java_快乐非自愿限量之名_InfoQ写作社区
VSCode配置JAVA开发环境_Java_IT蜗壳-Tango_InfoQ写作社区
Java虚拟线程探究与性能解析
Jakarta EE 11 发布,增强企业 Java 开发人员生产力和性能
重要:Java25正式发布(长期支持版)!
Access Token + Refresh Token 全解析:前后端分离架构的认证与安全方案
设计一个支持千万级用户的 IM 系统:消息推送如何保证可靠性
Spring Boot + CRaC 启动速度提升了10倍!
Java 25 新特性 更简洁、更高效、更现代
玩转 Java8 Stream,让你代码更高效紧凑简洁文章目录前言一、Stream特性二、Stream创建2.1用集合创 - 掘金
Guava 简介:让 Java 开发更高效
横空出世!MyBatis-Plus 同款 ES ORM 框架,用起来够优雅!
一个Java工程师的17个日常效率工具
Quarkus:轻量级 Java 的未来?
OpenJDK、Temurin、GraalVM...到底该装哪个?
Lombok坑哭了!若依框架一行@Data炸出Param为null,我卡了一下午才发现BaseEntity的猫腻
缓存性能王者,阿里巴巴二级缓存JetCache框架
MapStruct使用反思与简单易用性封装
Dockerfile 构建 Java 应用瘦身优化
还在手动搭Maven多模块?这款IDEA插件让我效率提升10倍(真实体验)
本文档使用 MrDoc 发布
-
+
横空出世!MyBatis-Plus 同款 ES ORM 框架,用起来够优雅!
> 使用过Spring Data操作ES的小伙伴应该有所了解,它只能实现一些非常基本的数据管理工作,一旦遇到稍微复杂点的查询,基本都要依赖ES官方提供的RestHighLevelClient,Spring Data只是在其基础上进行了简单的封装。最近发现一款更优雅的ES ORM框架`Easy-Es`,使用它能像MyBatis-Plus一样操作ES,今天就以mall项目中的商品搜索功能为例,来聊聊它的使用! Easy-Es(简称EE)是一款基于Elasticsearch(简称ES)官方提供的RestHighLevelClient打造的ORM开发框架,在RestHighLevelClient的基础上,只做增强不做改变,为简化开发、提高效率而生。EE和Mybatis-Plus(简称MP)的用法非常相似,如果你之前使用过MP的话,应该能很快上手EE。EE的理念是:把简单、易用、方便留给用户,把复杂留给框架。 EE的主要特性如下: - 全自动索引托管:开发者无需关心索引的创建、更新及数据迁移等繁琐步骤,框架能自动完成。 - 屏蔽语言差异:开发者只需要会MySQL的语法即可使用ES。 - 代码量极少:与直接使用官方提供的RestHighLevelClient相比,相同的查询平均可以节省3-5倍的代码量。 - 零魔法值:字段名称直接从实体中获取,无需手写。 - 零额外学习成本: 开发者只要会国内最受欢迎的Mybatis-Plus用法,即可无缝迁移至EE。 ## MySQL与Easy-Es语法对比 首先我们来对MySQL、Easy-Es和RestHighLevelClient的语法做过对比,来快速学习下Easy-Es的语法。 | MySQL | Easy-Es | es-DSL/es java api | | --- | --- | --- | | and | and | must | | or | or | should | | \= | eq | term | | != | not | boolQueryBuilder.mustNot(queryBuilder) | | gt | QueryBuilders.rangeQuery('es field').gt() | | \>= | ge | .rangeQuery('es field').gte() | | < | lt | .rangeQuery('es field').lt() | | <= | le | .rangeQuery('es field').lte() | | like '%field%' | like | QueryBuilders.wildcardQuery(field,_value_) | | not like '%field%' | notLike | must not wildcardQuery(field,_value_) | | like '%field' | likeLeft | QueryBuilders.wildcardQuery(field,\*value) | | like 'field%' | likeRight | QueryBuilders.wildcardQuery(field,value\*) | | between | between | QueryBuilders.rangeQuery('es field').from(xx).to(xx) | | notBetween | notBetween | must not QueryBuilders.rangeQuery('es field').from(xx).to(xx) | | is null | isNull | must not QueryBuilders.existsQuery(field) | | is notNull | isNotNull | QueryBuilders.existsQuery(field) | | in | in | QueryBuilders.termsQuery(" xx es field", xx) | | not in | notIn | must not QueryBuilders.termsQuery(" xx es field", xx) | | group by | groupBy | AggregationBuilders.terms() | | order by | orderBy | fieldSortBuilder.order(ASC/DESC) | | min | min | AggregationBuilders.min | | max | max | AggregationBuilders.max | | avg | avg | AggregationBuilders.avg | | sum | sum | AggregationBuilders.sum | | order by xxx asc | orderByAsc | fieldSortBuilder.order(SortOrder.ASC) | | order by xxx desc | orderByDesc | fieldSortBuilder.order(SortOrder.DESC) | | \- | match | matchQuery | | \- | matchPhrase | QueryBuilders.matchPhraseQuery | | \- | matchPrefix | QueryBuilders.matchPhrasePrefixQuery | | \- | queryStringQuery | QueryBuilders.queryStringQuery | | select \* | matchAllQuery | QueryBuilders.matchAllQuery() | | \- | highLight | HighlightBuilder.Field | | ... | ... | ... | ## 集成及配置 > 接下来把Easy-Es集成到项目中配置下就可以使用了。 - 首先需要在`pom.xml`中添加Easy-Es的相关依赖; ```xml <dependency> <groupId>org.dromara.easy-es</groupId> <artifactId>easy-es-boot-starter</artifactId> <version>3.0.0</version> </dependency> ``` - 由于底层使用了ES官方提供的RestHighLevelClient,这里ES的相关依赖版本需要统一下,这里使用的ES客户端版本为`7.17.28`,ES版本为`7.17.3`; ```xml <dependencyManagement> <dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.17.28</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.17.28</version> </dependency> </dependencies> </dependencyManagement> ``` - 再修改配置文件`application.yml`对Easy-Es进行配置。 ```yaml easy-es: enable: true address: localhost:9200 banner: false ``` - 添加Easy-Es的Java配置,使用`@EsMapperScan`配置好Easy-Es的Mapper接口和文档对象路径,如果你使用了MyBatis-Plus的话,需要和它的扫描路径区分开来。 ```java public class EasyEsConfig { } ``` ## 使用 > Easy-Es集成和配置完成后,就可以开始使用了。这里还是以`mall`项目的商品搜索功能为例,聊聊Easy-Es的使用 。 ### mall项目介绍 这里还是简单介绍下mall项目吧,mall项目是一套基于 SpringBoot + Vue + uni-app 实现的电商系统(Github标星60K),采用Docker容器化部署,后端支持多模块和微服务架构。包括前台商城项目和后台管理系统,能支持完整的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员、支付等功能! **项目演示:**  ### 注解的使用 > 下面我们来学习下Easy-Es中注解的使用。 - 首先我们需要创建文档对象`EsProduct`,然后给类和字段添加上Easy-Es的注解; ```java public class EsProduct implements Serializable { private static final long serialVersionUID = -1L; private Long id; private String productSn; private Long brandId; private String brandName; private Long productCategoryId; private String productCategoryName; private String pic; private String name; private String subTitle; private String keywords; private BigDecimal price; private Integer sale; private Integer newStatus; private Integer recommandStatus; private Integer stock; private Integer promotionType; private Integer sort; private List<EsProductAttributeValue> attrValueList; } ``` | 注解名称 | 用途 | 参数 | | --- | --- | --- | | @IndexName | 索引名注解 | value:指定索引名;shardsNum:分片数;replicasNum:副本数 | | @IndexId | ES主键注解 | type:指定注解类型,CUSTOMIZE表示自定义 | | @IndexField | ES字段注解 | fieldType:字段在索引中的类型;analyzer:索引文档时用的分词器;nestedClass:嵌套类 | - EsProduct中嵌套类型EsProductAttributeValue的代码如下。 ```java public class EsProductAttributeValue implements Serializable { private static final long serialVersionUID = 1L; private Long id; private Long productAttributeId; private String value; private Integer type; private String name; } ``` ### 商品信息维护 > 下面我们来实现几个简单的商品信息维护接口,包括商品信息的导入、创建和删除。 - 首先我们需要定义一个Mapper,继承BaseEsMapper; ```java public interface EsProductMapper extends BaseEsMapper<EsProduct> { } ``` - 然后在Service实现类中直接使用EsProductMapper内置方法实现即可,是不是和MyBatis-Plus的用法一致? ```java public class EsProductServiceImpl implements EsProductService { private static final Logger LOGGER = LoggerFactory.getLogger(EsProductServiceImpl.class); private EsProductMapper esProductMapper; public int importAll() { return esProductMapper.insertBatch(getAllEsProductList(null)); } public void delete(Long id) { esProductMapper.deleteById(id); } public EsProduct create(Long id) { EsProduct result = null; List<EsProduct> esProductList = getAllEsProductList(id); if (esProductList.size() > 0) { result = esProductList.get(0); esProductMapper.insert(result); } return result; } public void delete(List<Long> ids) { if (!CollectionUtils.isEmpty(ids)) { esProductMapper.deleteBatchIds(ids); } } } ``` ### 简单商品搜索 > 下面我们来实现一个最简单的商品搜索,分页搜索商品名称、副标题、关键词中包含指定关键字的商品。 - 通过QueryWrapper来构造查询条件,然后使用Mapper中的方法来进行查询,使用过MyBatis-Plus的小伙伴应该很熟悉了; ```java public class EsProductServiceImpl implements EsProductService { private EsProductMapper esProductMapper; public EsPageInfo<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) { LambdaEsQueryWrapper<EsProduct> wrapper = new LambdaEsQueryWrapper<>(); if(StrUtil.isEmpty(keyword)){ wrapper.matchAllQuery(); }else{ wrapper.multiMatchQuery(keyword,EsProduct::getName,EsProduct::getSubTitle,EsProduct::getKeywords); } return esProductMapper.pageQuery(wrapper, pageNum, pageSize); } } ```  - 把DSL语句直接复制Kibana中即可执行查看结果了,这和我们手写DSL语句没什么两样的。  ### 综合商品搜索 > 下面我们来实现一个复杂的商品搜索,涉及到过滤、不同字段匹配权重不同以及可以进行排序。 - 首先来说需求,按输入的关键字搜索商品名称(权重10)、副标题(权重5)和关键词(权重2),可以按品牌和分类进行筛选,可以有5种排序方式,默认按相关度进行排序,看下接口文档有助于理解;  - 这个功能之前使用Spring Data来实现非常复杂,使用Easy-Es来实现确实简洁不少,下面是使用Easy-Es的实现方式; ```java public class EsProductServiceImpl implements EsProductService { private EsProductMapper esProductMapper; public EsPageInfo<EsProduct> search(String keyword, Long brandId, Long productCategoryId, Integer pageNum, Integer pageSize,Integer sort) { LambdaEsQueryWrapper<EsProduct> wrapper = new LambdaEsQueryWrapper<>(); if (brandId != null || productCategoryId != null) { if (brandId != null) { wrapper.eq(EsProduct::getBrandId,brandId); } if (productCategoryId != null) { wrapper.eq(EsProduct::getProductCategoryId,productCategoryId); } } if (StrUtil.isEmpty(keyword)) { wrapper.matchAllQuery(); } else { wrapper.and(i -> i.match(EsProduct::getName, keyword, 10f) .or().match(EsProduct::getSubTitle, keyword, 5f) .or().match(EsProduct::getKeywords, keyword, 2f)); } if(sort==1){ wrapper.orderByDesc(EsProduct::getId); }else if(sort==2){ wrapper.orderByDesc(EsProduct::getSale); }else if(sort==3){ wrapper.orderByAsc(EsProduct::getPrice); }else if(sort==4){ wrapper.orderByDesc(EsProduct::getPrice); }else{ wrapper.sortByScore(SortOrder.Desc); } return esProductMapper.pageQuery(wrapper, pageNum, pageSize); } } ``` - 再对比下之前使用Spring Data的实现方式,没有QueryWrapper来构造条件,还要硬编码字段名称,确实优雅了不少!  ### 相关商品推荐 > 当我们查看相关商品的时候,一般底部会有一些商品推荐,这里简单来实现下。 - 首先来说下需求,可以根据指定商品的ID来查找相关商品,看下接口文档有助于理解;  - 这里我们的实现原理是这样的:首先根据ID获取指定商品信息,然后以指定商品的名称、品牌和分类来搜索商品,并且要过滤掉当前商品,调整搜索条件中的权重以获取最好的匹配度; - 使用Easy-Es来实现依旧是那么简洁! ```java public class EsProductServiceImpl implements EsProductService { private EsProductMapper esProductMapper; public EsPageInfo<EsProduct> recommend(Long id, Integer pageNum, Integer pageSize) { LambdaEsQueryWrapper<EsProduct> wrapper = new LambdaEsQueryWrapper<>(); List<EsProduct> esProductList = getAllEsProductList(id); if (esProductList.size() > 0) { EsProduct esProduct = esProductList.get(0); String keyword = esProduct.getName(); Long brandId = esProduct.getBrandId(); Long productCategoryId = esProduct.getProductCategoryId(); wrapper.not().eq(EsProduct::getId,id); wrapper.and(i -> i.match(EsProduct::getName, keyword, 8f) .or().match(EsProduct::getSubTitle, keyword, 2f) .or().match(EsProduct::getKeywords, keyword, 2f) .or().match(EsProduct::getBrandId, brandId, 5f) .or().match(EsProduct::getProductCategoryId, productCategoryId, 3f)); return esProductMapper.pageQuery(wrapper, pageNum, pageSize); } return esProductMapper.pageQuery(wrapper, pageNum, pageSize); } } ``` ## 总结 今天将之前的使用Spring Data的商品搜索案例使用Easy-Es改写了一下,确实使用Easy-Es更简单,但是对于复杂的聚合搜索功能,两者都需要使用原生的RestHighLevelClient用法来实现。使用Easy-Es来操作ES确实足够优雅,它类似MyBatis-Plus的用法能大大降低我们的学习成本,快速完成开发工作! ## 参考资料 官方文档:[www.easy-es.cn/](https://link.juejin.cn?target=https%3A%2F%2Fwww.easy-es.cn%2F) ## 项目源码地址 [github.com/macrozheng/…](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fmacrozheng%2Fspring-examples%2Ftree%2Fmaster%2Fspring-easyes)
admin
2025年10月5日 10:11
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码