本节将介绍本项目的查询模块,使用Elasticsearch又不是查询接口,具体流程如图所示(如果不了解Elasticsearch可以使用sql语句进行查询):
这里是两种方法的异同点:
- Mysql:擅长事务类型操作,可以确保数据的安全和一致性
- Elasticsearch:擅长海量数据的搜索、分析、计算
- 对安全性要求较高的写操作,使用mysql实现
- 对查询性能要求较高的搜索需求,使用elasticsearch实现
- 两者再基于某种方式,实现数据的同步,保证一致性
具体流程:
1.导入依赖
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2.在application.yum引入配置
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
3.在项目中建立elasticsearch.document和elasticsearch.repository包,用于存放elasticsearch文档类和接口操作
java
package com.java.elasticsearch.document;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.math.BigDecimal;
@Document(indexName = "course")
public class CourseInfo {
@Id
private String courseId;
@Field(type = FieldType.Text, analyzer = "standard") // 使用标准分析器
private String courseName;
@Field(type = FieldType.Text, analyzer = "standard") // 使用标准分析器
private String courseTeacher;
@Field(type = FieldType.Text)
private String courseDetail;
@Field(type = FieldType.Integer)
private Integer courseAttribute;
@Field(type = FieldType.Double)
private BigDecimal coursePrice;
@Field(type = FieldType.Integer)
private Integer courseStock;
// 构造函数、getter 和 setter 方法
// Getters and setters for each field
public String getCourseId() {
return courseId;
}
public void setCourseId(String courseId) {
this.courseId = courseId;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public String getCourseTeacher() {
return courseTeacher;
}
public void setCourseTeacher(String courseTeacher) {
this.courseTeacher = courseTeacher;
}
public String getCourseDetail() {
return courseDetail;
}
public void setCourseDetail(String courseDetail) {
this.courseDetail = courseDetail;
}
public Integer getCourseAttribute() {
return courseAttribute;
}
public void setCourseAttribute(Integer courseAttribute) {
this.courseAttribute = courseAttribute;
}
public BigDecimal getCoursePrice() {
return coursePrice;
}
public void setCoursePrice(BigDecimal coursePrice) {
this.coursePrice = coursePrice;
}
public Integer getCourseStock() {
return courseStock;
}
public void setCourseStock(Integer courseStock) {
this.courseStock = courseStock;
}
}
4、在repository包下新建操作Elasticsearch的接口继承ElasticsearchRepository
java
package com.java.elasticsearch.repository;
import com.java.elasticsearch.document.CourseInfo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface CourseRepository extends ElasticsearchRepository<CourseInfo, String> {
// 按课程名查询
Page<CourseInfo> findByCourseName(String courseName, int courseAttribute, Pageable pageable);
// 按授课老师名查询
Page<CourseInfo> findByCourseTeacher(String courseTeacher, int courseAttribute,Pageable pageable);
// 查询课程名为courseName且授课老师为courseTeacher的记录
@Query("{\"bool\": {\"must\": [{\"match\": {\"courseName\": \"?0\"}}, {\"match\": {\"courseTeacher\": \"?1\"}}]}}")
Page<CourseInfo> findByCourseNameAndCourseTeacher(String courseName, String courseTeacher, Pageable pageable);
}
5.在service包下新建Elasticsearch课程搜索Service类EsCourseService
java
package com.java.service;
import com.java.elasticsearch.document.EsCourse;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface EsCourseService {
/**
* 从数据库中导入课程到ES
* @return
*/
int importAll();
/**
* 根据id删除课程
* @param id
*/
void delete(Long id);
/**
* 根据id创建商品
* @param id
* @return
*/
EsProduct create(Long id);
/**
* 批量删除
* @param ids
*/
void deletes(List<Long> ids);
/**
* 根据关键字搜索
* @param keyword
* @param pageNum
* @param pageSize
* @return
*/
Page<EsProduct> searchPage(String keyword, Integer pageNum,Integer pageSize);
}
实现上述方法
java
package com.java.service.impl;
import com.java.dao.EsProductDao;
import com.java.elasticsearch.document.EsProduct;
import com.java.elasticsearch.repository.EsProductRepository;
import com.java.service.EsProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@Service
@Transactional
public class EsProductServiceImpl implements EsProductService {
private static final Logger logger = LoggerFactory.getLogger(EsProductServiceImpl.class);
@Autowired
private EsProductDao esProductDao;
@Autowired
private EsProductRepository esProductRepository;
@Override
public int importAll() {
List<EsProduct> esProductList = esProductDao.getProductEs(null);
Iterable<EsProduct> iterable = esProductRepository.saveAll(esProductList);
Iterator<EsProduct> iterator = iterable.iterator();
logger.info("导入ES数据{}:",iterator);
int count = 0;
while (iterator.hasNext()) {
count++;
iterator.next();
}
return count;
}
@Override
public void delete(Long id) {
logger.info("删除ES中的商品{}:",id);
esProductRepository.deleteById(id);
}
@Override
public EsProduct create(Long id) {
List<EsProduct> esProducts = esProductDao.getProductEs(id);
if (CollectionUtils.isEmpty(esProducts)) {
return null;
}
EsProduct esProduct = esProducts.get(0);
logger.info("导入ES单条商品{}:",esProduct);
return esProductRepository.save(esProduct);
}
@Override
public void deletes(List<Long> ids) {
if (!CollectionUtils.isEmpty(ids)) {
List<EsProduct> esProductList = new ArrayList<>();
ids.forEach(id->{
EsProduct esProduct = new EsProduct();
esProduct.setId(id);
esProductList.add(esProduct);
});
logger.info("批量删除ES中的商品{}:",esProductList);
esProductRepository.deleteAll(esProductList);
}
}
@Override
// 搜索课程
public Page<CourseInfo> searchCourses(String query, Integer courseAttribute, Pageable pageable) {
if (query != null && !query.isEmpty()) {
return courseRepository.findByCourseNameOrCourseTeacher(query, query, pageable);
} else {
// 如果没有搜索词,则返回所有符合条件的课程
return courseRepository.findByCourseAttributeAndCourseStockGreaterThan(courseAttribute, pageable);
}
}
}
6.在dao包下新建操作数据库接口EsProductDao和映射xml文件EsProductDao.xml
java
package com.java.dao;
import java.util.List;
public interface EsCourseDao {
List<EsProduct> selectAllCourse();
}
java
<!-- src/main/resources/mapper/EsCourseDao.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.java.dao.EsProductDao">
<resultMap id="CourseResultMap" type="EsCourse">
<result property="course_id" column="course_id"/>
<result property="course_name" column="course_name"/>
<result property="course_teacher" column="course_teacher"/>
<result property="course_attribute" column="course_attribute"/>
<result property="course_stock" column="course_stock"/>
</resultMap>
<!-- 查询所有课程 -->
<select id="selectAllCourse" resultMap="CourseResultMap">
SELECT course_id,course_name,course_teacher,course_attribute ,course_stock
FROM course
</select>
</mapper>
7.在controller包下新建控制器EsProductController
java
/**
* ES搜索课程Controller
**/
@Controller
@Api(tags = "EsProductController",description = "ES课程搜索")
public class EsProductController {
@Autowired
private EsProductService esProductService;
@ApiOperation("从数据库导入ES课程数据")
@RequestMapping(value = "/esProduct/importAll",method = RequestMethod.POST)
@ResponseBody
public CommonResult<Integer> importAll(){
int count = esProductService.importAll();
return CommonResult.success(count);
}
@ApiOperation("根据id删除课程")
@RequestMapping(value = "/esProduct/delete/{id}",method = RequestMethod.POST)
@ResponseBody
public CommonResult deleteById(@PathVariable Long id){
esProductService.delete(id);
return RespBean.success("删除成功");
}
@ApiOperation("批量删除课程")
@RequestMapping(value = "/esProduct/deletes",method = RequestMethod.POST)
@ResponseBody
public CommonResult deleteById(List<Long> ids){
esProductService.deletes(ids);
return RespBean.success("删除成功");
}
@ApiOperation("根据id创建课程")
@RequestMapping(value = "/esProduct/create",method = RequestMethod.POST)
@ResponseBody
public CommonResult create(Long id){
EsProduct esProduct = esProductService.create(id);
if (StringUtils.isEmpty(esProduct)) {
return CommonResult.failed("创建失败");
}
return RespBean.success("创建成功");
}
@ApiOperation("搜索课程")
@RequestMapping(value = "/esProduct/search",method = RequestMethod.GET)
@ResponseBody
public CommonResult<CommonPage<EsProduct>> search(@RequestParam(required = false) String keyword,
@RequestParam(required = false, defaultValue = "0") Integer pageNum,
@RequestParam(required = false, defaultValue = "5") Integer pageSize){
Page<EsProduct> esProductPage = esProductService.searchPage(keyword,pageNum,pageSize);
return RespBean.success(CommonPage.restPage(esProductPage));
}
}