springboot工程中使用es实现搜索功能

ElasticSearch是一个基于Lucene的开源的、分布式实时搜索和分析引擎。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。

上一节我们以及安装好了elasticsearch以及kibana、IK分词器

现在让我们看看如何在springboot工程中使用吧。

安装依赖

我们使用的是7.x,注意7.x和8.x的差别较大,初学者可以先从7.x入手。

XML 复制代码
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.12.1</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>7.12.1</version>
        </dependency>

es配置

yml文件配置

XML 复制代码
elasticsearch:
  hostlist: 你的es服务ip #多个结点中间用逗号分隔
  article:
    index: article
    source_fields: id,title,content,summary,thumbnail,categoryId,isTop,status,viewCount,isComment,createTime
java 复制代码
@Configuration
public class ElasticsearchConfig {
    @Value("${elasticsearch.hostlist}")
    private String hostlist;

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        //解析hostlist配置信息
        String[] split = hostlist.split(",");
        //创建HttpHost数组,其中存放es主机和端口的配置信息
        HttpHost[] httpHostArray = new HttpHost[split.length];
        for (int i = 0; i < split.length; i++) {
            String item = split[i];
            httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
        }
        //创建RestHighLevelClient客户端
        return new RestHighLevelClient(RestClient.builder(httpHostArray));
    }
}

索引

定义service接口

java 复制代码
public interface IndexService {
    /**
     * 添加文章索引
     * @param
     * @return
     */
    public Boolean addArticleIndex(String indexName, String id, Object object);
}

实现service接口

java 复制代码
@Service
@Slf4j
public class IndexServiceImpl implements IndexService {

    @Resource
    RestHighLevelClient client;


    @Override
    public Boolean addArticleIndex(String indexName, String id, Object object) {
        // 格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = sdf.format(((Article) object).getCreateTime());

        // 将格式化后的日期字符串替换 JSON 字符串中的 createTime 字段
        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(object));
        jsonObject.put("createTime", dateString);
        String jsonString = jsonObject.toJSONString();
//        String jsonString = JSON.toJSONString(object);
        IndexRequest indexRequest = new IndexRequest(indexName).id(id);
        //指定索引文档内容
        indexRequest.source(jsonString, XContentType.JSON);
        //索引响应对象
        IndexResponse indexResponse = null;
        try {
            indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("添加索引出错:{}", e.getMessage());
            e.printStackTrace();
            ZhiWenPlusException.cast("添加索引出错");
        }
        String name = indexResponse.getResult().name();
        System.out.println(name);
        return name.equalsIgnoreCase("created") || name.equalsIgnoreCase("updated");
    }
}

创建索引接口

java 复制代码
@RestController
@RequestMapping("search/index")
public class ArticleIndexController {

    @Value("${elasticsearch.article.index}")
    private String courseIndexStore;

    @Resource
    private IndexService indexService;

    @ApiOperation(value = "添加文章索引")
    @PostMapping("/article")
    public Boolean addIndex(@RequestBody Article article) {
        Long id = article.getId();
        if (id == null) {
            ZhiWenPlusException.cast("文章id为空");
        }
        Boolean result = indexService.addArticleIndex(courseIndexStore, String.valueOf(id), article);
        if (!result) {
            ZhiWenPlusException.cast("添加课程索引失败");
        }
        return result;
    }
}

搜索

根据关键字搜索文章信息,搜索方式为全文检索,关键字需要匹配文章的标题、简介,并且高亮显示。

定义service接口

java 复制代码
public interface ArticleSearchService {
    /**
     * 搜索文章信息
     * @param pageNo
     * @param pageSize
     * @param keyWords
     * @return
     */
    ResponseResult queryArticleIndex(Long pageNo, Long pageSize, String keyWords);
}

实现service接口

java 复制代码
@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Value("${elasticsearch.article.index}")
    private String courseIndexStore;
    @Value("${elasticsearch.article.source_fields}")
    private String sourceFields;

    @Resource
    RestHighLevelClient client;


    @Override
    public ResponseResult queryArticleIndex(Long pageNo, Long pageSize,String keyWords) {
        //设置索引
        SearchRequest searchRequest = new SearchRequest(courseIndexStore);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //source源字段过虑
        String[] sourceFieldsArray = sourceFields.split(",");
        searchSourceBuilder.fetchSource(sourceFieldsArray, new String[]{});

        if (StringUtils.isNotEmpty(keyWords)) {
            //匹配关键字
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyWords, "title", "summary");
            //设置匹配占比
            multiMatchQueryBuilder.minimumShouldMatch("70%");
            //提升另个字段的Boost值
            multiMatchQueryBuilder.field("title", 10);
            boolQueryBuilder.must(multiMatchQueryBuilder);
        }

        int start = (int) ((pageNo - 1) * pageSize);
        searchSourceBuilder.from(start);
        searchSourceBuilder.size(Math.toIntExact(pageSize));
        //布尔查询
        searchSourceBuilder.query(boolQueryBuilder);
        //高亮设置
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font class='eslight'>");
        highlightBuilder.postTags("</font>");
        //设置高亮字段
        highlightBuilder.fields().add(new HighlightBuilder.Field("title"));
        searchSourceBuilder.highlighter(highlightBuilder);
        //请求搜索
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("课程搜索异常:{}", e.getMessage());
//            return new SearchPageResultDto<CourseIndex>(new ArrayList(), 0, 0, 0);
            ZhiWenPlusException.cast("课程搜索异常");
        }

        //结果集处理
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        //记录总数
        TotalHits totalHits = hits.getTotalHits();
        //数据列表
        List<Article> list = new ArrayList<>();

        for (SearchHit hit : searchHits) {

            String sourceAsString = hit.getSourceAsString();
            Article article = JSON.parseObject(sourceAsString, Article.class);

            //取出source
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();

            //课程id
            Long id = article.getId();
            //取出名称
            String title = article.getTitle();
            //取出高亮字段内容
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields != null) {
                HighlightField nameField = highlightFields.get("title");
                if (nameField != null) {
                    Text[] fragments = nameField.getFragments();
                    StringBuffer stringBuffer = new StringBuffer();
                    for (Text str : fragments) {
                        stringBuffer.append(str.string());
                    }
                    title = stringBuffer.toString();

                }
            }
            article.setId(id);
            article.setTitle(title);

            list.add(article);

        }

        return new ResponseResult().ok(list);
    }
}

创建搜索接口

java 复制代码
@RestController
@RequestMapping("search/article")
public class ArticleSearchController {

    @Resource
    private ArticleSearchService articleSearchService;

    @GetMapping("/list")
    public ResponseResult searchArticle(Long pageNum, Long pageSize,String keywords) {
        ResponseResult result = articleSearchService.queryArticleIndex(pageNum, pageSize, keywords);
        return result;
    }
}
相关推荐
齐 飞11 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
狂放不羁霸19 分钟前
idea | 搭建 SpringBoot 项目之配置 Maven
spring boot·maven·intellij-idea
LunarCod28 分钟前
WorkFlow源码剖析——Communicator之TCPServer(中)
后端·workflow·c/c++·网络框架·源码剖析·高性能高并发
计算机学长felix1 小时前
基于SpringBoot的“校园交友网站”的设计与实现(源码+数据库+文档+PPT)
数据库·spring boot·毕业设计·交友
码农派大星。1 小时前
Spring Boot 配置文件
java·spring boot·后端
江深竹静,一苇以航1 小时前
springboot3项目整合Mybatis-plus启动项目报错:Invalid bean definition with name ‘xxxMapper‘
java·spring boot
杜杜的man2 小时前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*2 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
llllinuuu2 小时前
Go语言结构体、方法与接口
开发语言·后端·golang
cookies_s_s2 小时前
Golang--协程和管道
开发语言·后端·golang