ElasticSearch自定义注解增删改方式

 更新时间:2025年04月17日 09:46:43   作者:guoyangsheng_  
这篇文章主要介绍了ElasticSearch自定义注解增删改方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

导入依赖

<!--提供与 Elasticsearch 交互的高层次客户端,便于在 Java 应用中使用 Elasticsearch 的功能。-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<!-- Spring Boot 的起始器,简化了与 Elasticsearch 的集成 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- 高性能的 JSON 处理库,用于 JSON 的解析和生成 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version> <!-- 请使用最新的版本 -->
</dependency>
<!-- 通过注解简化 Java 代码,自动生成 getter、setter、构造函数等代码,减少样板代码的编写 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

导入 ElasticSearchUtil 工具

@Component
@Slf4j
public class ElasticSearchUtil {
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 取对象id
     *
     * @param data
     * @return
     */
    private String getObjectId(Object data) {
        String idValue = null;
        try {
            String idName = "id";
            //获取Object类下所有字段
            Field[] declaredFields = data.getClass().getDeclaredFields();
            //循环遍历
            for (Field field : declaredFields) {
                //获取字段上的'IdIndex'的注解实例
                IdIndex annotation = field.getAnnotation(IdIndex.class);
                //如果不为空
                if (annotation != null) {
                    //将annotation中的idName赋给变量idName
                    idName = annotation.idName();
                    //终止循环
                    break;
                }
            }
            //查找一个名为 idName 的字段,并返回一个 Field 对象,表示这个字段
            Field declaredField = data.getClass().getDeclaredField(idName);
            //设置对象的访问权限
            declaredField.setAccessible(true);
            idValue = declaredField.get(data).toString();
            log.info(" >>>>>> idValue:{}", idValue);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return idValue;
    }

    /**
     * 创建索引
     *
     * @return
     * @params index
     */
    public String createIndex(Object data) throws Exception {
        //根据实体注解取索引名字
        DocumentIndex annotation = data.getClass().getAnnotation(DocumentIndex.class);
        String indexName = annotation.indexName();

        //索引已经存在,不需要创建索引
        if (isIndexExist(indexName)) return indexName;

        //1.创建索引请求
        CreateIndexRequest request = new CreateIndexRequest(indexName);

        //创建基础配置
        Settings.Builder builder = Settings.builder().put("index.max_result_window", annotation.maxSize());//10亿数据
        builder.put("index.number_of_shards", annotation.shards()) // 分片数量
                .put("index.number_of_replicas", annotation.replicas()); // 副本数量
        request.settings(builder);//索引文档基础配置

        //mapping结构
        JSONObject mapping = new JSONObject();
        JSONObject props = new JSONObject();
        mapping.put("properties", props);

        Class<?> aClass = data.getClass();
        //aClass.getConstructors();
        //aClass.getMethods();
        //取对象所有私有属性
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field field : declaredFields) {
            Class type = field.getType();
            String name = field.getName();
            JSONObject prop = new JSONObject();
            PropertyIndex propIndex = field.getAnnotation(PropertyIndex.class);
            if (propIndex != null) {//自定义属性各种配置
                if (propIndex.name() != null && !"".equals(propIndex.name())) {
                    name = propIndex.name();
                }
                props.put(name, prop);//通过注解可以指定索引字段名称
                prop.put("type", propIndex.type());
                prop.put("index", true);//默认true
                if ("text".equals(propIndex.type())) {
                    prop.put("analyzer", propIndex.analyzer());//"analyzer": "ik_max_word",
                    prop.put("search_analyzer", propIndex.searchAnalyzer());//"search_analyzer": "ik_smart"
                }
                if (!propIndex.index()) { //设置非索引
                    prop.put("index", false);
                }
            } else { //默认处理
                props.put(name, prop);
                if (type.newInstance() instanceof String) {
                    prop.put("type", "keyword");
                } else if (type.newInstance() instanceof Date) {
                    prop.put("type", "date");
                    prop.put("format", "yyyy-MM-dd HH:mm:ss");//"format": "yyyy-MM-dd HH:mm:ss"
                } else if (type.newInstance() instanceof Integer) {
                    prop.put("type", "integer");
                } else if (type.newInstance() instanceof Long) {
                    prop.put("type", "long");
                } else {
                    prop.put("type", "text");
                    prop.put("analyzer", "ik_smart");//"analyzer": "ik_max_word",
                    prop.put("search_analyzer", "ik_smart");//"search_analyzer": "ik_smart"
                }
            }

        }

        String jsonString = mapping.toJSONString();
        log.info("jsonString: " + jsonString);
        request.mapping("_doc", jsonString, XContentType.JSON);

        //2.执行客户端请求
        CreateIndexResponse createIndexResponse = restHighLevelClient.indices()
                .create(request, RequestOptions.DEFAULT);

        return indexName;
    }

    /**
     * 判断索引是否存在
     *
     * @param index
     * @return
     */
    public boolean isIndexExist(String index) throws IOException {
        GetIndexRequest request = new GetIndexRequest(index);
        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        return exists;
    }

    /**
     * 删除索引
     *
     * @param index
     * @return
     */
    public boolean deleteIndex(String index) throws IOException {
        if (!isIndexExist(index)) {
            log.error("Index is not exits!");
            return false;
        }
        DeleteIndexRequest request = new DeleteIndexRequest(index);
        org.elasticsearch.action.support.master.AcknowledgedResponse delete = restHighLevelClient.indices()
                .delete(request, RequestOptions.DEFAULT);
        return delete.isAcknowledged();
    }

    /**
     * 写入数据
     */
    public boolean insertData(Object data, String indexName) {
        try {
            IndexRequest request = new IndexRequest(indexName).id(getObjectId(data)).source(JSON.toJSONString(data), XContentType.JSON);
            restHighLevelClient.index(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.info(" >>>>>>> insertData error: {}", e.getMessage());
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 批量写入数据
     */
    public boolean batchInsert(List<Object> datas) {
        //参数校验
        if (CollectionUtils.isEmpty(datas)) return false;

        DocumentIndex annotation = datas.get(0).getClass().getAnnotation(DocumentIndex.class);
        String indexName = annotation.indexName();

        try {
            BulkRequest bulkRequest = new BulkRequest();

            datas.forEach(data -> {
                bulkRequest.add(new IndexRequest(indexName).id(getObjectId(data))
                        .source(JSON.toJSONString(data), XContentType.JSON));
            });

            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.info(" >>>>>>> insertData error: {}", e.getMessage());
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 更新数据,可以直接修改索引结构
     */
    public boolean batchUpdate(List<Object> datas) {

        if (CollectionUtils.isEmpty(datas)) return false;

        DocumentIndex annotation = datas.get(0).getClass().getAnnotation(DocumentIndex.class);
        String indexName = annotation.indexName();
        try {
            BulkRequest bulkRequest = new BulkRequest();

            datas.forEach(data -> {
                bulkRequest.add(new UpdateRequest(indexName, "doc", getObjectId(data)).doc(JSON.toJSONString(data)));
            });

            restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.info(" >>>>>>> insertData error: {}", e.getMessage());
            e.printStackTrace();
        }

        return true;
    }

    /**
     * 修改
     *
     * @param data
     * @return
     */
    public boolean updateData(Object data) {
        try {
            //获取索引名
            String indexName = data.getClass().getAnnotation(DocumentIndex.class).indexName();
            //创建修改请求
            UpdateRequest updateRequest = new UpdateRequest(indexName, "_doc", getObjectId(data)).doc(JSON.toJSONString(data), XContentType.JSON);
            restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.info(" >>>>>>> updateData error: {}", e.getMessage());
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 删除数据
     */
    public boolean delete(String indexName, String id) {
        try {
            DeleteRequest deleteRequest = new DeleteRequest(indexName, "_doc", id);
            restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error(" delete Exception:{}", e.getMessage());
            e.printStackTrace();
        }
        return true;
    }

}

导入config

@Configuration
public class InitRestHighLevelClient  {

    @Value("${es.hostname:IP}")
    private String hostname;

    @Value("${es.port:端口}")
    private int port;

    /**
     * 初始化 RestHighLevelClient 对象
     *
     * @return
     */
    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost(hostname, port, "http"))
        );
        return client;
    }
}

注解类DocumentIndex

/**
 * @Author:GuoYangsheng
 * @Description:
 * @name:DocumentIndex
 * @Date:2024/9/12 16:43
 */
@Target(ElementType.TYPE)//指定注解可以应用于类、接口或枚举
@Retention(RetentionPolicy.RUNTIME)//可以通过反射机制访问和读取
public @interface DocumentIndex {

    //指定索引的名称。默认为空字符串,表示未指定
    String indexName() default "";

    //默认为索引的文档数量上限为10000
    int maxSize() default 10000;

    //指定索引的分片数量 默认为3 分片可以提高索引的性能和可扩展性
    int shards() default 3;

    //指定索引的副本数量 默认为1 副本可以提高数据的可靠性和查询性能
    int replicas() default 1;
}

注解类IdIndex

/**
 * @Author:GuoYangsheng
 * @Description:
 * @name:IdIndex
 * @Date:2024/9/12 16:50
 */
@Target(ElementType.FIELD)//指定 ‘IdIndex' 可以应用于类中字段上
@Retention(RetentionPolicy.RUNTIME)//可以通过反射机制访问和读取
public @interface IdIndex {
    //指定属性标识符名称为 'id'
    String idName() default "id";
}

注解类PropertyIndex

/**
 * @Author:GuoYangsheng
 * @Description:
 * @name:PropertyIndex
 * @Date:2024/9/12 16:58
 */

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * ES索引字段注解
 */
@Target(ElementType.FIELD)//指定 ‘IdIndex' 可以应用于类中字段上
@Retention(RetentionPolicy.RUNTIME)//可以通过反射机制访问和读取
public @interface PropertyIndex {
    //用于指定字段在Elasticsearch索引中的名称
    String name() default "";
    //指定字段的数据类型
    String type() default "keyword";
    //指定用于字段的分词器
    String analyzer() default "ik_smart";
    //是否建立索引
    boolean index() default true;
    //指定用于搜索时的分词器
    String searchAnalyzer() default "ik_smart";
    //指定是否忽略该字段的索引
    boolean ignore() default true;
}

controller

/**
 * @Author:GuoYangsheng
 * @Description:
 * @name:SysDeptController
 * @Date:2024/9/12 20:26
 */
@RestController
@RequestMapping("/sysDept")
public class SysDeptController {
    @Autowired
    private SysDeptService sysDeptService;

    /**
     * 创建索引
     *
     * @param sysDept
     * @return
     */
    @GetMapping("/createIndex")
    public void createIndex(SysDept sysDept) {
        sysDeptService.createIndex(sysDept);
    }

    /**
     * 保存
     *
     * @param sysDept
     */
    @PostMapping("/save")
    public Boolean save(@RequestBody SysDept sysDept) {
        return sysDeptService.save(sysDept);
    }

    /**
     * 删除数据
     *
     * @param indexName
     * @param id
     * @return
     */
    @DeleteMapping("/deleteById")
    public Boolean deleteById(String indexName, String id) {
        return sysDeptService.deleteById(indexName, id);
    }

    /**
     * 修改数据
     *
     * @param sysDept
     * @return
     */
    @PutMapping("/updateSysDept")
    public Boolean updateSysDept(@RequestBody SysDept sysDept) {
        return sysDeptService.updateSysDept(sysDept);
    }
}

service

/**
 * @Author:GuoYangsheng
 * @Description:
 * @name:SysDeptService
 * @Date:2024/9/12 20:26
 */
public interface SysDeptService {
    /**
     * 创建索引
     *
     * @param sysDept
     */
    void createIndex(SysDept sysDept);

    /**
     * 保存
     *
     * @param sysDept
     */
    Boolean save(SysDept sysDept);


    /**
     * 删除数据
     *
     * @param indexName
     * @param id
     * @return
     */
    Boolean deleteById(String indexName, String id);

    /**
     * 修改数据
     *
     * @param sysDept
     * @return
     */
    Boolean updateSysDept(SysDept sysDept);
}

实现层 直接调用工具类方法即可

/**
 * @Author:GuoYangsheng
 * @Description:
 * @name:SysDeptServiceImpl
 * @Date:2024/9/12 20:26
 */
@Service
public class SysDeptServiceImpl implements SysDeptService {
    @Resource
    private ElasticSearchUtil elasticSearchUtil;

    /**
     * 创建索引
     *
     * @param sysDept
     */
    @Override
    public void createIndex(SysDept sysDept) {
        try {
            elasticSearchUtil.createIndex(sysDept);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 保存
     *
     * @param sysDept
     */
    @Override
    public Boolean save(SysDept sysDept) {
        return elasticSearchUtil.insertData(sysDept);
    }


    /**
     * 删除数据
     *
     * @param indexName
     * @param id
     * @return
     */
    @Override
    public Boolean deleteById(String indexName, String id) {

        return elasticSearchUtil.delete(indexName, id);
    }

    /**
     * 修改数据
     *
     * @param sysDept
     * @return
     */
    @Override
    public Boolean updateSysDept(SysDept sysDept) {

        return elasticSearchUtil.updateData(sysDept);
    }
}

在Elastic开发工具中查看效果,或者下载Apipost工具测试即可

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java中Shiro安全框架的权限管理

    Java中Shiro安全框架的权限管理

    这篇文章主要介绍了Java中Shiro安全框架的权限管理,Apache Shiro是Java的一个安全框架,Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境,需要的朋友可以参考下
    2023-08-08
  • mybaits-plus lambdaQuery() 和 lambdaUpdate() 常见的使用方法

    mybaits-plus lambdaQuery() 和 lambdaUpdate() 常见的使用方法

    MyBatis-Plus是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生,这篇文章主要介绍了mybaits-plus lambdaQuery() 和 lambdaUpdate() 比较常见的使用方法,需要的朋友可以参考下
    2023-01-01
  • 登陆验证码kaptcha结合spring boot的用法详解

    登陆验证码kaptcha结合spring boot的用法详解

    在一个web应用中验证码是一个常见的元素。不管是防止机器人还是爬虫都有一定的作用,下面这篇文章主要给大家介绍了登陆验证码kaptcha结合spring boot用法的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-06-06
  • SpringBoot获取HttpServletRequest的3种方式总结

    SpringBoot获取HttpServletRequest的3种方式总结

    这篇文章主要给大家介绍了关于SpringBoot获取HttpServletRequest的3种方式,在Spring boot项目中经常要用到Servlet的常用对象如HttpServletRequest request,HttpServletResponse response,HttpSession session,需要的朋友可以参考下
    2023-08-08
  • Java读取文件及基于正则表达式的获取电话号码功能详解

    Java读取文件及基于正则表达式的获取电话号码功能详解

    这篇文章主要介绍了Java读取文件及基于正则表达式的获取电话号码功能,结合实例形式详细分析了正则匹配操作的相关语法及电话号码匹配的原理与实现技巧,需要的朋友可以参考下
    2017-09-09
  • Spring Cloud OpenFeign 远程调用

    Spring Cloud OpenFeign 远程调用

    这篇文章主要介绍了Spring Cloud OpenFeign 远程调用,本文通过远程调用的GitHub开放API用到的OpenFeign作为示例代码作为入口进行讲解。然后以图解+解读源码的方式深入剖析了OpenFeign的运行机制和架构设计,需要的朋友可以参考一下
    2022-08-08
  • java WSDL接口webService实现方式

    java WSDL接口webService实现方式

    这篇文章主要为大家详细介绍了java WSDL接口webService实现方式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • Mybatis-Plus中的查询指定字段

    Mybatis-Plus中的查询指定字段

    在使用Mybatis-Plus进行数据查询时,可以通过指定字段来优化查询效率,方法一和方法二分别执行不同的SQL语句,其中方法二在执行时通常会更高效,因为它可能通过减少数据处理量和优化查询结构来提升性能,比较两种方法的SQL执行情况
    2024-09-09
  • 浅谈Java中Spring Boot的优势

    浅谈Java中Spring Boot的优势

    在本篇文章中小编给大家分析了Java中Spring Boot的优势以及相关知识点内容,兴趣的朋友们可以学习参考下。
    2018-09-09
  • Java文件读写详解

    Java文件读写详解

    在真实的应用场景中,很多时候需要使用 Java 读写文件。比如说,读取配置文件信息、读取用户输入等。本篇文章将会详细介绍 Java 文件读写的相关知识,其中包括:读取文件、写入文件、复制文件和删除文件等操作,需要的朋友可以参考下
    2023-05-05

最新评论