前提条件:

        elastic search 6.5.0
        springboot版本 2.1.6

1.导入依赖
<!--elasticsearch-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2.配置类
Spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch
      cluster-nodes: 127.0.0.1:9300
3.将数据库的数据导入elasticsearch

启动elasticsearch6.5.0

在需要创建索引的实体类上加上注解

@Document(indexName = "course",  shards = 2,replicas = 0)

加完重启项目,查看es图形化界面就可以看到创建的索引了

4.给索引添加数据

首先编写从数据库获取数据的接口,

    /**
     * 获取所有课程信息(es渲染页面)
     * @return
     */
    @GetMapping("list")
    public PageInfo<CourseDTO> list(Integer pageNum, Integer pageSize) {

        return courseService.getList(pageNum, pageSize);
    }
@Repository
public interface ElasticSearchRepository extends ElasticsearchRepository<CourseDTO,Integer> {

}
@Override
    public PageInfo<CourseDTO> getList(Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<CourseDTO> list = courseMapper.getList();
        return new PageInfo<>(list);
    }

补充:PageHelper是一个分页的工具类

        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.7</version>
        </dependency>
@Select("select c.*,t.teacher_name,t.position from course c\n" +
            "left join teacher t\n" +
            "on c.id = t.course_id")
    List<CourseDTO> getList();

在测试接口可以使用后,编写一个接口ElasticSearchRepository 可以改成别的名字重要的是继承

@Repository
public interface ElasticSearchRepository extends ElasticsearchRepository<CourseDTO,Integer> {

}

在测试类中注入mapper层和ElasticSearchRepository ,从数据库获取数据再保存到es中

@RunWith(SpringRunner.class)
@SpringBootTest(classes = CourseApplication.class)
public class EsTest {

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private ElasticSearchRepository elasticSearchRepository;

    @Test
    public void createCourse(){
        elasticSearchRepository.saveAll(courseMapper.getList());
    }

}

然后再次查看es就发现数据保存到esl了

4.接下来就是编写搜索的方法

高亮工具类

public class ElasticsearchUtil {

    public static void highlightKeywords(Iterable<CourseDTO> courses, String key) {
        // 使用正则表达式进行不区分大小写的匹配
        String highlightedKey = "<span style='color:red;'>" + key + "</span>";
        String regex = "(?i)" + Pattern.quote(key);  // (?i) 表示不区分大小写
        Pattern pattern = Pattern.compile(regex);
        for (CourseDTO course : courses) {
            Matcher matcherCourseName = pattern.matcher(course.getCourseName());
            Matcher matcherBrief = pattern.matcher(course.getBrief());
            Matcher matcherTeacherName = pattern.matcher(course.getTeacherName());
            course.setCourseName(matcherCourseName.replaceAll(highlightedKey));
            course.setBrief(matcherBrief.replaceAll(highlightedKey));
            course.setTeacherName(matcherTeacherName.replaceAll(highlightedKey));
        }
    }
}

编写搜索接口

/**
     *搜索course
     * @param searchDTO
     * @return
     */
    @GetMapping("search")
    public PageImpl<CourseDTO> getCourseByPage(SearchDTO searchDTO){
        return courseService.getCourseByPage(searchDTO);
    }
PageImpl<CourseDTO> getCourseByPage(SearchDTO searchDTO);
@Resource
    private ElasticsearchTemplate elasticsearchTemplate;

@Override
    public PageImpl<CourseDTO> getCourseByPage(SearchDTO searchDTO) {
        // 构建查询条件
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 添加范围查询
        if (searchDTO.getMinPrice() != 0 || searchDTO.getMaxPrice() != 0) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("discounts");
            if (searchDTO.getMinPrice() != 0) {
                rangeQuery.gte(searchDTO.getMinPrice());
            }
            if (searchDTO.getMaxPrice() != 0) {
                rangeQuery.lte(searchDTO.getMaxPrice());
            }
            boolQuery.must(rangeQuery);
        }

        // 添加关键词查询(如果需要)
        if (searchDTO.getKeyWord() != null && !searchDTO.getKeyWord().isEmpty()) {
            boolQuery.should(QueryBuilders.matchQuery("courseName", searchDTO.getKeyWord()));
            boolQuery.should(QueryBuilders.matchQuery("brief", searchDTO.getKeyWord()));
            boolQuery.should(QueryBuilders.matchQuery("teacherName", searchDTO.getKeyWord()));
            boolQuery.minimumShouldMatch(1);
        }

        // 设置查询
        queryBuilder.withQuery(boolQuery);

        // 增加排序条件,按相关性得分降序排序
        queryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));

        // 构建搜索查询
        NativeSearchQuery searchQuery = queryBuilder.build();

        // 执行查询
        List<CourseDTO> courseList = elasticsearchTemplate.queryForList(searchQuery, CourseDTO.class);

        // 设置高亮
        if (searchDTO.getKeyWord() != null && !searchDTO.getKeyWord().isEmpty()){
            ElasticsearchUtil.highlightKeywords(courseList,searchDTO.getKeyWord());
        }

        // 进行内存分页
        int start = searchDTO.getPageNum() * searchDTO.getPageSize();
        int end = Math.min((start + searchDTO.getPageSize()), courseList.size());
        Pageable pageable = PageRequest.of(searchDTO.getPageNum(), searchDTO.getPageSize());

        if (start > courseList.size()) {
            return new PageImpl<>(courseList, pageable, courseList.size());
        }

        List<CourseDTO> pageCourseList = courseList.subList(start, end);
        return new PageImpl<>(pageCourseList, pageable, courseList.size());

    }

searchDTO和前端传来的参数一致

public class SearchDTO {

    private int minPrice;

    private int maxPrice;

    private String keyWord;

    private int pageNum;

    private int pageSize;
}
补充:

我的是根据关键词搜索和价格区间搜索,当值赋值后,高亮会出现html的文本

 所以需要使用v-html进行渲染

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐