一個基於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的相關方法里。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM