栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

SpringBoot基于ElasticSearch7.9.2和ElasticsearchRestTemplate的一些通用接口(可复用)

SpringBoot基于ElasticSearch7.9.2和ElasticsearchRestTemplate的一些通用接口(可复用)

之前写过一篇SpringBoot集成ElasticSearch 7.9.2 教程和简单增删改查案例https://blog.csdn.net/weixin_43753812/article/details/117733551

这里提供一个通用的操作接口和文档的方法类,大多数的使用场景都已经覆盖,话不多说,开整:

    首先,创建一个自定义注解,结合elasticsearch提供的注解一起,配合实体类操作文档和索引。
package com.cqvip.innocence.common.annotation;

import java.lang.annotation.*;


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
public @interface documentId {
}

2.写一个与文档对应的DTO(这里只是示例,具体的实体根据对应需求建立)

package com.cqvip.innocence.project.model.entity;

import com.cqvip.innocence.common.annotation.documentId;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.io.Serializable;


@Data
@document(indexName = "test_info")
public class EsTestInfo implements Serializable {
    private static final long serialVersionUID = 6735913456541605819L;

    @documentId
    @Field(type = FieldType.Keyword)
    private String infoId;

    private String name;

    @Field(type = FieldType.Integer)
    private Integer age;

    @Field(type = FieldType.Keyword)
    private String sex;

    @Field(type = FieldType.Keyword)
    private String[] roles;
}

 3.索引操作的接口和实现

package com.cqvip.innocence.project.esservice;


public interface IndexService{

    
    Boolean createIndexByClass(Class clazz);

    
    Boolean createIndexByName(String indexName);

    
    Boolean isIndexExist(String indexName);

    
    Boolean deleteIndexByName(String indexName);

    
    String getIndexName(Class clazz);
}
package com.cqvip.innocence.project.esservice.impl;

import cn.hutool.core.util.StrUtil;
import com.cqvip.innocence.project.esservice.IndexService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.annotations.document;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.stereotype.Service;

import java.lang.annotation.Annotation;


@Service
public class IndexServiceImpl implements IndexService {

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Override
    public String getIndexName(Class clazz){
        Annotation documentAnnotation = clazz.getDeclaredAnnotation(document.class);
        if(documentAnnotation==null){
            return null;
        }
        String indexName = ((document) documentAnnotation).indexName();
        if (StrUtil.isNotBlank(indexName)){
            return indexName;
        }
        return null;
    }

    @Override
    public Boolean createIndexByClass(Class clazz) {
        Boolean indexExist = isIndexExist(getIndexName(clazz));
        if (indexExist){
            return false;
        }
        IndexOperations indexOps = restTemplate.indexOps(clazz);
        boolean result1 = indexOps.create();
        boolean result2 = indexOps.putMapping(indexOps.createMapping(clazz));
        return result1&result2;
    }

    @Override
    public Boolean createIndexByName(String indexName) {
        Boolean indexExist = isIndexExist(indexName);
        if (indexExist){
            return false;
        }
        IndexOperations indexOps = restTemplate.indexOps(IndexCoordinates.of(indexName));
        return indexOps.create();

    }

    @Override
    public Boolean isIndexExist(String indexName) {
        IndexOperations indexOps = restTemplate.indexOps(IndexCoordinates.of(indexName));
        return indexOps.exists();
    }

    @Override
    public Boolean deleteIndexByName(String indexName) {
        IndexOperations indexOps = restTemplate.indexOps(IndexCoordinates.of(indexName));
        return indexOps.delete();

    }
}

4.文档操作的接口和实现类

package com.cqvip.innocence.project.esservice;

import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.Query;

import java.io.IOException;
import java.util.List;
import java.util.Map;


public interface documentService {

    
    HighlightBuilder getHighlightBuilder(String[] fields);

    
    Boolean isExist(String id, Class clazz);

    
    String saveByEntity(T t);

    
    List saveBatchByEntities(List entities) throws Exception;

    
    void updateByEntity(T t);

    
    void updateByEntities(List entities);

    
    String deleteById(String id, Class clazz);

    
    void deleteByIds(List ids, Class clazz);

    
    void deleteByQuery(Query query, Class clazz);

    
    T getEntityById(String id,Class clazz);

    
    List getEntityByIds(List ids, Class clazz);

    
    Long getCount(Query query,Class clazz);

    
    List getInfoList(Query query, Class clazz,Boolean isHighLight);

    
    Map getPageList(Query query, PageRequest pageRequest,Class clazz);

    
    Map> getFacetByQuery(SearchSourceBuilder query, Class clazz) throws IOException;
}

 

package com.cqvip.innocence.project.esservice.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.cqvip.innocence.common.annotation.documentId;
import com.cqvip.innocence.common.exception.ElasticServiceException;
import com.cqvip.innocence.project.esservice.documentService;
import com.cqvip.innocence.project.esservice.IndexService;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.lucene.search.IndexSearcher;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.document.document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.lang.reflect.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



@Service
public class documentServiceImpl implements documentService {

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Qualifier("highLevelClient")
    @Autowired
    private RestHighLevelClient highLevelClient;

    @Autowired
    private IndexService indexService;

    
    private String getPrimaryNameByClass(Class clazz){
        Field[] fields = clazz.getDeclaredFields();
        for (Field f:fields) {
            documentId id = f.getAnnotation(documentId.class);
            if (id != null){
                return f.getName();
            }
        }
        return null;
    }

    
    private String getPrimaryValueByEntity(T t){
        Class clazz = (Class) t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field f:fields) {
            Class type = f.getType();
            if (type.getTypeName().equals(String.class.getTypeName())){
                documentId id = f.getAnnotation(documentId.class);
                if (id != null){
                    try {
                        String replace = f.getName()
                                .replace(f.getName().substring(0, 1), f.getName().substring(0, 1).toUpperCase());
                        Method method = clazz.getMethod("get" + replace);
                        String invoke = (String) method.invoke(t);
                        if (StrUtil.isNotBlank(invoke)){
                            return invoke;
                        }else {
                            return null;
                        }
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }

    
    private String indexNameExceptionHandler(Class clazz){
        String indexName = indexService.getIndexName(clazz);
        if (StrUtil.isBlank(indexName)){
            throw new ElasticServiceException("The index name on the current class does not exist!");
        }else {
            return indexName;
        }
    }

    
    private  List mappingHighlight(List> searchHits){
        List infoList = new ArrayList<>();
        for (SearchHit searchHit : searchHits) {
            T content = searchHit.getContent();
            Map> highlightFields = searchHit.getHighlightFields();
            for (Map.Entry> entry : highlightFields.entrySet()) {
                try {
                    PropertyUtils.setProperty(content,entry.getKey(),entry.getValue().get(0));
                } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
            infoList.add(content);
        }
        return infoList;
    }

    @Override
    public HighlightBuilder getHighlightBuilder(String[] fields) {
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        for (String field : fields) {
            highlightBuilder.field(field);
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("");
        highlightBuilder.postTags("");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }


    @Override
    public Boolean isExist(String id,Class clazz) {
        String name = indexNameExceptionHandler(clazz);
        return restTemplate.exists(id, IndexCoordinates.of(name));
    }

    @Override
    public  String saveByEntity(T t) {
        String id = getPrimaryValueByEntity(t);
        String indexName = indexNameExceptionHandler((Class) t.getClass());
        if (StrUtil.isBlank(id)){
            throw new ElasticServiceException("document id cannot be empty!");
        }
        IndexQuery build = new IndexQueryBuilder().withId(id).withObject(t).build();
        String index = restTemplate.index(build, IndexCoordinates.of(indexName));
        //业务需要,新增后马上刷新,ElasticsearchRestTemplate是默认不立即刷新(立即刷新会影响性能)
        restTemplate.indexOps(t.getClass()).refresh();
        return index;
    }

    @Override
    public List saveBatchByEntities(List entities){
        Class clazz =(Class) entities.get(0).getClass();
        String indexName = indexNameExceptionHandler(clazz);
        List queryList = new ArrayList<>();
        for (T item:entities){
            String id = getPrimaryValueByEntity(item);
            if (StrUtil.isBlank(id)){
                throw new ElasticServiceException("document id cannot be empty!");
            }
            IndexQuery build = new IndexQueryBuilder().withId(id).withObject(item).build();
            queryList.add(build);
        }
        List idList = restTemplate.bulkIndex(queryList, IndexCoordinates.of(indexName));
        restTemplate.indexOps(IndexCoordinates.of(indexName)).refresh();
        return idList;
    }

    @Override
    public void updateByEntity(T t) {
        String indexName = indexNameExceptionHandler((Class) t.getClass());
        document document = document.parse(JSON.toJSonString(t));
        document.setId(getPrimaryValueByEntity(t));
        UpdateQuery build = UpdateQuery.builder(document.getId())
                .withRefresh(UpdateQuery.Refresh.Wait_For) //更新后立即刷新可见(影响性能,按需注释或使用)
                .withdocument(document)
                .build();
        restTemplate.update(build, IndexCoordinates.of(indexName));
    }

    @Override
    public void updateByEntities(List entities) {
        Class clazz =(Class) entities.get(0).getClass();
        String indexName = indexNameExceptionHandler(clazz);
        List updateQueries = new ArrayList<>();
        entities.forEach(item->{
            document document = document.parse(JSON.toJSonString(item));
            document.setId(getPrimaryValueByEntity(item));
            UpdateQuery build = UpdateQuery.builder(document.getId())
                    .withRefresh(UpdateQuery.Refresh.Wait_For)
//                    .withDocAsUpsert(true) //不加默认false。true表示更新时不存在就插入
                    .withdocument(document)
                    .build();
            updateQueries.add(build);
        });
        restTemplate.bulkUpdate(updateQueries,IndexCoordinates.of(indexName));
    }

    @Override
    public String deleteById(String id, Class clazz) {
        String indexName = indexNameExceptionHandler(clazz);
        return restTemplate.delete(id,IndexCoordinates.of(indexName));
    }

    @Override
    public void deleteByIds(List ids, Class clazz) {
        String indexName = indexNameExceptionHandler(clazz);
        StringQuery query = new StringQuery(QueryBuilders.termsQuery(getPrimaryNameByClass(clazz), ids).toString());
        restTemplate.delete(query,clazz,IndexCoordinates.of(indexName));
    }

    @Override
    public void deleteByQuery(Query query,Class clazz) {
        String indexName = indexNameExceptionHandler(clazz);
        restTemplate.delete(query,clazz,IndexCoordinates.of(indexName));
    }

    @Override
    public T getEntityById(String id,Class clazz) {
        return restTemplate.get(id,clazz);
    }

    @Override
    public List getEntityByIds(List ids, Class clazz) {
        String indexName = indexNameExceptionHandler(clazz);
        NativeSearchQuery build = new NativeSearchQueryBuilder().withIds(ids).build();
        return restTemplate.multiGet(build, clazz, IndexCoordinates.of(indexName));
    }

    @Override
    public Long getCount(Query query,Class clazz) {
        return restTemplate.count(query,clazz);
    }

    @Override
    public List getInfoList(Query query,Class clazz,Boolean isHighLight) {
        query.setTrackTotalHits(true);
        SearchHits search = restTemplate.search(query,clazz);
        if (isHighLight){
            return mappingHighlight(search.getSearchHits());
        }
        List infoList = new ArrayList<>();
        for (SearchHit searchHit : search){
            infoList.add(searchHit.getContent());
        }
        return infoList;
    }

    @Override
    public Map getPageList(Query query, PageRequest pageRequest,Class clazz) {
        query.setTrackTotalHits(true);
        query.setPageable(pageRequest);
        SearchHits search = restTemplate.search(query,clazz);
        Aggregations aggregations = search.getAggregations();
        List> searchHits = search.getSearchHits();
        List esSourceInfos = mappingHighlight(searchHits);
        Page infos = new PageImpl(
                esSourceInfos,
                pageRequest,
                search.getTotalHits());
        Map map = new HashMap<>();
        map.put("page",infos);
        map.put("ag",formatFacet(aggregations));
        return map;
    }

    @Override
    public Map> getFacetByQuery(SearchSourceBuilder query, Class clazz) throws IOException {
        String indexName = indexNameExceptionHandler(clazz);
        SearchRequest request = new SearchRequest(indexName);
        SearchSourceBuilder builder = query;
        request.source(builder);
        SearchResponse response = highLevelClient.search(request, RequestOptions.DEFAULT);
        Aggregations aggregations = response.getAggregations();
        return formatFacet(aggregations);
    }


    
    private Map> formatFacet(Aggregations aggregations){
        if (aggregations == null){
            return null;
        }
        Map> map = new HashMap<>();
        List list = aggregations.asList();
        list.forEach(item->{
            ParsedStringTerms newItem = (ParsedStringTerms) item;
            String name = newItem.getName();
            List buckets = newItem.getBuckets();
            map.put(name,buckets);
        });
        return map;
    }
}

 5.使用示例,使用@Autowired自动注入,并且带上泛型类

package com.cqvip.innocence.tests;

import com.cqvip.innocence.project.esservice.documentService;
import com.cqvip.innocence.project.esservice.IndexService;
import com.cqvip.innocence.project.model.entity.EsTestInfo;
import org.apache.commons.lang3.builder.ToStringExclude;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.util.ArrayList;
import java.util.List;


@SpringBootTest
public class EsTest {

    @Autowired
    private IndexService indexService;

    @Autowired
    private documentService documentService;

    @Test
    public void indexOperation(){
        Boolean index = indexService.createIndexByClass(EsTestInfo.class);
        System.out.println("index = " + index);
    }

    @Test
    public void saveByEntity(){
        EsTestInfo esTestInfo = new EsTestInfo();
        esTestInfo.setAge(20);
        esTestInfo.setInfoId("test_02");
        esTestInfo.setName("一库一库");
        esTestInfo.setSex("男");
        String entity = null;
        try {
            entity = documentService.saveByEntity(esTestInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("entity = " + entity);
    }

    @Test
    public void isExist(){
        Boolean test_01 = documentService.isExist("test_01", EsTestInfo.class);
        System.out.println("test_01 = " + test_01);
    }

    @Test
    public void updateByEntity(){
        EsTestInfo info = documentService.getEntityById("test_01", EsTestInfo.class);
        info.setName(info.getName()+"_update");
        documentService.updateByEntity(info);
    }

    @Test
    public void deleteById(){
        String deleteById = documentService.deleteById("test_01", EsTestInfo.class);
        System.out.println("deleteById = " + deleteById);
    }

    @Test
    public void saveBatchByEntities(){
        List list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            EsTestInfo info = new EsTestInfo();
            info.setInfoId("test_batch_"+(i+1)+"");
            info.setName("name_batch_"+(i+1)+"");
            info.setSex("N");
            info.setAge((i+1)*10);
            info.setRoles(new String[]{"管理员","超级管理员"});
            list.add(info);
        }
        try {
            documentService.saveBatchByEntities(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void getInfoList(){
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.wildcardQuery("infoId","test_batch_*"));
        NativeSearchQuery build = queryBuilder.withQuery(boolQuery).build();
        List infoList = documentService.getInfoList(build,EsTestInfo.class,true);
    }

    @Test
    public void count(){
        Long count = documentService.getCount(new NativeSearchQueryBuilder().build(),EsTestInfo.class);
        System.out.println("count = " + count);
    }

    @Test
    public void deleteByIds(){
        ArrayList strings = new ArrayList<>();
        strings.add("test_01");
        strings.add("test_02");
        Class clazz = EsTestInfo.class;
        documentService.deleteByIds(strings, clazz);
    }

    @Test
    public void update() {
        EsTestInfo info = new EsTestInfo();
        info.setName("wait_for");
        info.setInfoId("test_batch_wait_for_2");
        documentService.saveByEntity(info);
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
                .must(QueryBuilders.wildcardQuery("infoId","test_batch_*"));
        NativeSearchQuery build = queryBuilder.withQuery(boolQuery).build();
        List infoList = documentService.getInfoList(build,EsTestInfo.class);
        System.out.println("infoList = " + infoList);
    }
}

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/775417.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号