一个基于ElasticSearchRestTemplate的增删改查的例子

现在网上的用springboot对ElasticSearch做增删改查的文章,几乎都是用的原生API或者继承了ElasticsearchRepository去做。但是现在我用的springboot2.5.6已经移除了ElasticsearchRepository里的search()方法,只剩了一些特别基础的增删改查,基本上是不能用的。官方明显是想让开发者用ElasticsearchRestTemplate去做,但是搜索网上没有发现很好的增删改查教程,于是我把自己写的代码贴一下:

package com.markerhub.search.model.mq;

import com.alibaba.fastjson.JSON;
import com.markerhub.config.RabbitConfig;
import com.markerhub.entity.Blog;
import com.markerhub.search.model.BlogPostDocument;
import com.markerhub.service.BlogService;
import com.markerhub.util.MyUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RabbitListener(queues = RabbitConfig.ES_QUEUE)
public class MQMessageHandler {

    BlogService blogService;

    @Autowired
    public void setBlogService(BlogService blogService) {
        this.blogService = blogService;
    }

    ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    public void setElasticsearchRestTemplate(ElasticsearchRestTemplate elasticsearchRestTemplate) {
        this.elasticsearchRestTemplate = elasticsearchRestTemplate;
    }

    @SneakyThrows
    @RabbitHandler
    public void handler(PostMQIndexMessage message) {
        switch (message.getType()) {
            case PostMQIndexMessage.UPDATE:

                Long updateId = message.getPostId();
                Blog blogExisted = blogService.getById(updateId);
                BlogPostDocument postDocument = MyUtils.blogToDocument(blogExisted);
                String obj = JSON.toJSONString(postDocument);
                Document document = Document.parse(obj);

                UpdateQuery query = UpdateQuery
                        .builder(String.valueOf(updateId))
                        .withDocument(document)
                        .build();

                IndexCoordinates indexCoordinates = elasticsearchRestTemplate.getIndexCoordinatesFor(BlogPostDocument.class);

                UpdateResponse update = elasticsearchRestTemplate.update(query, indexCoordinates);

                String result = String.valueOf(update.getResult());
                log.info("更新结果: {}", result);
                break;
            case PostMQIndexMessage.REMOVE:

                Long deleteId = message.getPostId();

                String delete = elasticsearchRestTemplate.delete(deleteId.toString(), BlogPostDocument.class);

                log.info("删除结果: {}", delete);

                break;
            case PostMQIndexMessage.CREATE:

                Long createId = message.getPostId();
                Blog newBlog = blogService.getById(createId);

                BlogPostDocument newDocument = MyUtils.blogToDocument(newBlog);

                BlogPostDocument save = elasticsearchRestTemplate.save(newDocument);
                log.info("保存结果: {}", save);
                break;
            default:
                log.error("没找到对应的消息类型: {}", message);
        }
    }
}

es里的实体类是BlogPostDocument。上面是对rabbitmq整合时当数据库更新,往队列发一条消息,发消息的代码没有贴出来,不过重点不在这里。这里通知消费者去执行相关的方法。首先ElasticsearchRestTemplate把增删改查分开了,增是增,删是删,改是改,查是查,不能再把增改一起用了。实现比较简单,代码也比较直白,查询代码是这样的:

/**
     * 搜索功能,从es搜索
     */
    @GetMapping("/search/{currentPage}")
    public Result search(@PathVariable Integer currentPage, @RequestParam String keyword) {
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, "title", "description", "content");
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(multiMatchQueryBuilder)
                .withSort(SortBuilders.fieldSort("created").order(SortOrder.DESC))
                .build();

        SearchHits<BlogPostDocument> search = elasticsearchRestTemplate.search(nativeSearchQuery, BlogPostDocument.class);

        if (search.getTotalHits() == 0) {
            throw new ResourceNotFoundException("没有相关记录");
        }

//        List<SearchHit<BlogPostDocument>> list = search.getSearchHits();

        ArrayList<BlogPostDocument> list = new ArrayList<>();

        for (SearchHit<BlogPostDocument> hit : search.getSearchHits()) {
            list.add(hit.getContent());
        }

        Page<BlogPostDocument> page = MyUtils.listToPage(list, currentPage, 5);

        return Result.succ(page);
    }


    @GetMapping("/searchByYear/{currentPage}/{year}")
    public Result searchByYear(@PathVariable Integer currentPage, @RequestParam String keyword, @PathVariable Integer year) {

        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, "title", "description", "content");

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.boolQuery()
                        .must(QueryBuilders.rangeQuery("created").gte(year + "-01-01T00:00:00").lte(year + "-12-31T23:59:59")
                                .includeUpper(true)
                                .includeLower(true))
                        .must(multiMatchQueryBuilder))
                .withSort(SortBuilders.fieldSort("created").order(SortOrder.DESC))
                .build();

        SearchHits<BlogPostDocument> search = elasticsearchRestTemplate.search(nativeSearchQuery, BlogPostDocument.class);

        if (search.getTotalHits() == 0) {
            throw new ResourceNotFoundException("没有相关记录");
        }

        ArrayList<BlogPostDocument> list = new ArrayList<>();

        for (SearchHit<BlogPostDocument> hit : search.getSearchHits()) {
            list.add(hit.getContent());
        }

        Page<BlogPostDocument> page = MyUtils.listToPage(list, currentPage, 5);

        return Result.succ(page);
    }

这里是多匹配查询,multiMatchQuery会匹配传入的所有field,由于继承了ik分词器,搜索比较智能吧。

总体来看,总而言之,ElasticsearchRestTemplate的应用方法是,先构建相应的query对象(查询MultiMatchQueryBuilder或者更新UpdateQuery之类的),在这个对象里传入你的查询条件或者修改的对象或者新增的对象,再传入ElasticsearchRestTemplate的相关方法里。

posted @ 2021-12-13 20:16  imissinstagram  Views(3332)  Comments(0Edit  收藏  举报