校园课程助手【4】-使用Elasticsearch实现课程检索

miss writer 2024-08-03 16:01:03 阅读 74

本节将介绍本项目的查询模块,使用Elasticsearch又不是查询接口,具体流程如图所示(如果不了解Elasticsearch可以使用sql语句进行查询):

在这里插入图片描述

这里是两种方法的异同点:

Mysql:擅长事务类型操作,可以确保数据的安全和一致性Elasticsearch:擅长海量数据的搜索、分析、计算对安全性要求较高的写操作,使用mysql实现对查询性能要求较高的搜索需求,使用elasticsearch实现两者再基于某种方式,实现数据的同步,保证一致性

具体流程:

1.导入依赖

<code> <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-elasticsearch</artifactId>

</dependency>

2.在application.yum引入配置

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-elasticsearch</artifactId>

</dependency>

3.在项目中建立elasticsearch.document和elasticsearch.repository包,用于存放elasticsearch文档类和接口操作

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

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

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);

}

实现上述方法

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

package com.java.dao;

import java.util.List;

public interface EsCourseDao {

List<EsProduct> selectAllCourse();

}

<!-- src/main/resources/mapper/EsCourseDao.xml -->

<?xml version="1.0" encoding="UTF-8" ?>code>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.java.dao.EsProductDao">code>

<resultMap id="CourseResultMap" type="EsCourse">code>

<result property="course_id" column="course_id"/>code>

<result property="course_name" column="course_name"/>code>

<result property="course_teacher" column="course_teacher"/>code>

<result property="course_attribute" column="course_attribute"/>code>

<result property="course_stock" column="course_stock"/>code>

</resultMap>

<!-- 查询所有课程 -->

<select id="selectAllCourse" resultMap="CourseResultMap">code>

SELECT course_id,course_name,course_teacher,course_attribute ,course_stock

FROM course

</select>

</mapper>

7.在controller包下新建控制器EsProductController

/**

* 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));

}

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。