作者:微信小助手
发布时间:2023-11-15T09:30:53
使用过Spring Data操作ES的小伙伴应该有所了解,它只能实现一些非常基本的数据管理工作,一旦遇到稍微复杂点的查询,基本都要依赖ES官方提供的RestHighLevelClient,Spring Data只是在其基础上进行了简单的封装。最近发现一款更优雅的ES ORM框架Easy-Es,使用它能像MyBatis-Plus一样操作ES,今天就以一个实际的mall商城项目中的商品搜索功能为例,来聊聊它的使用! Easy-Es(简称EE)是基于Elasticsearch(简称ES)官方提供的RestHighLevelClient开发的ORM框架,旨在简化开发流程并提高效率。EE在保持RestHighLevelClient原有功能的基础上进行增强,而不做任何改变。与Mybatis-Plus(简称MP)相比,EE的用法非常相似,如果您之前使用过MP,应该能够很快上手EE。EE的设计理念是:将简单、易用和方便留给用户,而将复杂的任务交由框架来处理。 EE的主要特性如下: 全自动索引管理:开发者无需繁琐地处理索引的创建、更新和数据迁移等步骤,框架会自动完成这些任务。 屏蔽语言差异:开发者只需要熟悉MySQL语法,就能够轻松地使用ES进行开发。 更少的代码量:相比直接使用官方提供的RestHighLevelClient,使用EE平均可以节省3-5倍的代码量来进行相同的查询操作。 零魔法值:字段名称会直接从实体中获取,无需手动编写。 无额外学习成本:如果开发者已经熟悉国内最受欢迎的Mybatis-Plus的用法,那么可以无缝迁移至EE,无需额外学习成本。 下面我们来实现几个简单的商品信息维护接口,包括商品信息的导入、创建和删除。 下面我们来实现一个最简单的商品搜索,分页搜索商品名称、副标题、关键词中包含指定关键字的商品。 下面我们来实现一个复杂的商品搜索,涉及到过滤、不同字段匹配权重不同以及可以进行排序。 当我们查看相关商品的时候,一般底部会有一些商品推荐,这里简单来实现下。 今天主要介绍了Easy-Es的一些常见的用法,确实使用Easy-Es更简单,但是对于复杂的聚合搜索功能,还是需要使用原生的RestHighLevelClient用法来实现。使用Easy-Es来操作ES确实足够优雅,它类似MyBatis-Plus的用法能大大降低我们的学习成本,快速完成开发工作!
Easy-Es简介
MySQL与Easy-Es语法对比
集成及配置
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.14.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.14.0</version>
</dependency>
</dependencies>
</dependencyManagement>
easy-es:
# 是否开启EE自动配置
enable: true
# ES连接地址+端口
address: localhost:9200
# 关闭自带banner
banner: false
/**
* EasyEs配置类
* Created by macro on 2022/9/16.
*/
@Configuration
@EsMapperScan("com.macro.mall.tiny.easyes")
public class EasyEsConfig {
}使用
注解的使用
/**
* 搜索商品的信息
* Created by macro on 2018/6/19.
*/
@Data
@EqualsAndHashCode
@IndexName(value = "pms", shardsNum = 1, replicasNum = 0)
public class EsProduct implements Serializable {
private static final long serialVersionUID = -1L;
@IndexId(type = IdType.CUSTOMIZE)
private Long id;
@IndexField(fieldType = FieldType.KEYWORD)
private String productSn;
private Long brandId;
@IndexField(fieldType = FieldType.KEYWORD)
private String brandName;
private Long productCategoryId;
@IndexField(fieldType = FieldType.KEYWORD)
private String productCategoryName;
private String pic;
@IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word")
private String name;
@IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word")
private String subTitle;
@IndexField(fieldType = FieldType.TEXT, analyzer = "ik_max_word")
private String keywords;
private BigDecimal price;
private Integer sale;
private Integer newStatus;
private Integer recommandStatus;
private Integer stock;
private Integer promotionType;
private Integer sort;
@IndexField(fieldType = FieldType.NESTED, nestedClass = EsProductAttributeValue.class)
private List<EsProductAttributeValue> attrValueList;
@Score
private Float score;
}
/**
* 搜索商品的属性信息
* Created by macro on 2018/6/27.
*/
@Data
@EqualsAndHashCode
public class EsProductAttributeValue implements Serializable {
private static final long serialVersionUID = 1L;
@IndexField(fieldType = FieldType.LONG)
private Long id;
@IndexField(fieldType = FieldType.KEYWORD)
private Long productAttributeId;
//属性值
@IndexField(fieldType = FieldType.KEYWORD)
private String value;
//属性参数:0->规格;1->参数
@IndexField(fieldType = FieldType.INTEGER)
private Integer type;
//属性名称
@IndexField(fieldType=FieldType.KEYWORD)
private String name;
}商品信息维护
/**
* 商品ES操作类
* Created by macro on 2018/6/19.
*/
public interface EsProductMapper extends BaseEsMapper<EsProduct> {
}
/**
* 搜索商品管理Service实现类
* Created by macro on 2018/6/19.
*/
@Service
public class EsProductServiceImpl implements EsProductService {
@Autowired
private EsProductDao productDao;
@Autowired
private EsProductMapper esProductMapper;
@Override
public int importAll() {
List<EsProduct> esProductList = productDao.getAllEsProductList(null);
return esProductMapper.insertBatch(esProductList);
}
@Override
public void delete(Long id) {
esProductMapper.deleteById(id);
}
@Override
public EsProduct create(Long id) {
EsProduct result = null;
List<EsProduct> esProductList = productDao.getAllEsProductList(id);
if (esProductList.size() > 0) {
result = esProductList.get(0);
esProductMapper.insert(result);
}
return result;
}
@Override
public void delete(List<Long> ids) {
if (!CollectionUtils.isEmpty(ids)) {
esProductMapper.deleteBatchIds(ids);
}
}
}简单商品搜索
/**
* 搜索商品管理Service实现类
* Created by macro on 2018/6/19.
*/
@Service
public class EsProductServiceImpl implements EsProductService {
@Autowired
private EsProductMapper esProductMapper;
@Override
public PageInfo<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);
}
}
综合商品搜索
/**
* 搜索商品管理Service实现类
* Created by macro on 2018/6/19.
*/
@Service
public class EsProductServiceImpl implements EsProductService {
@Autowired
private EsProductMapper esProductMapper;
@Override
public PageInfo<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).enableMust2Filter(true);
}
}
//搜索
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);
}
}
相关商品推荐
/**
* 搜索商品管理Service实现类
* Created by macro on 2018/6/19.
*/
@Service
public class EsProductServiceImpl implements EsProductService {
@Autowired
private EsProductMapper esProductMapper;
@Override
public PageInfo<EsProduct> recommend(Long id, Integer pageNum, Integer pageSize) {
LambdaEsQueryWrapper<EsProduct> wrapper = new LambdaEsQueryWrapper<>();
List<EsProduct> esProductList = productDao.getAllEsProductList(id);
if (esProductList.size() > 0) {
EsProduct esProduct = esProductList.get(0);
String keyword = esProduct.getName();
Long brandId = esProduct.getBrandId();
Long productCategoryId = esProduct.getProductCategoryId();
//用于过滤掉相同的商品
wrapper.ne(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);
}
}总结