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;
    }
}
相关推荐
凡人的AI工具箱7 分钟前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
小码的头发丝、10 分钟前
Spring Boot 注解
java·spring boot
午觉千万别睡过13 分钟前
RuoYI分页不准确问题解决
spring boot
java亮小白199715 分钟前
Spring循环依赖如何解决的?
java·后端·spring
2301_8112743132 分钟前
大数据基于Spring Boot的化妆品推荐系统的设计与实现
大数据·spring boot·后端
草莓base1 小时前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
Mephisto.java1 小时前
【大数据学习 | Spark】Spark的改变分区的算子
大数据·elasticsearch·oracle·spark·kafka·memcache
mqiqe1 小时前
Elasticsearch 分词器
python·elasticsearch
Ljw...1 小时前
表的增删改查(MySQL)
数据库·后端·mysql·表的增删查改
编程重生之路1 小时前
Springboot启动异常 错误: 找不到或无法加载主类 xxx.Application异常
java·spring boot·后端