ElasticSearch自定義注解增刪改方式
更新時(shí)間:2025年04月17日 09:46:43 作者:guoyangsheng_
這篇文章主要介紹了ElasticSearch自定義注解增刪改方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
導(dǎo)入依賴
<!--提供與 Elasticsearch 交互的高層次客戶端,便于在 Java 應(yīng)用中使用 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 代碼,自動(dòng)生成 getter、setter、構(gòu)造函數(shù)等代碼,減少樣板代碼的編寫 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
導(dǎo)入 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(); //循環(huán)遍歷 for (Field field : declaredFields) { //獲取字段上的'IdIndex'的注解實(shí)例 IdIndex annotation = field.getAnnotation(IdIndex.class); //如果不為空 if (annotation != null) { //將annotation中的idName賦給變量idName idName = annotation.idName(); //終止循環(huán) break; } } //查找一個(gè)名為 idName 的字段,并返回一個(gè) Field 對象,表示這個(gè)字段 Field declaredField = data.getClass().getDeclaredField(idName); //設(shè)置對象的訪問權(quán)限 declaredField.setAccessible(true); idValue = declaredField.get(data).toString(); log.info(" >>>>>> idValue:{}", idValue); } catch (Exception e) { log.error(e.getMessage()); } return idValue; } /** * 創(chuàng)建索引 * * @return * @params index */ public String createIndex(Object data) throws Exception { //根據(jù)實(shí)體注解取索引名字 DocumentIndex annotation = data.getClass().getAnnotation(DocumentIndex.class); String indexName = annotation.indexName(); //索引已經(jīng)存在,不需要?jiǎng)?chuàng)建索引 if (isIndexExist(indexName)) return indexName; //1.創(chuàng)建索引請求 CreateIndexRequest request = new CreateIndexRequest(indexName); //創(chuàng)建基礎(chǔ)配置 Settings.Builder builder = Settings.builder().put("index.max_result_window", annotation.maxSize());//10億數(shù)據(jù) builder.put("index.number_of_shards", annotation.shards()) // 分片數(shù)量 .put("index.number_of_replicas", annotation.replicas()); // 副本數(shù)量 request.settings(builder);//索引文檔基礎(chǔ)配置 //mapping結(jié)構(gòu) 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);//默認(rèn)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()) { //設(shè)置非索引 prop.put("index", false); } } else { //默認(rèn)處理 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.執(zhí)行客戶端請求 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(); } /** * 寫入數(shù)據(jù) */ 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; } /** * 批量寫入數(shù)據(jù) */ public boolean batchInsert(List<Object> datas) { //參數(shù)校驗(yàn) 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; } /** * 更新數(shù)據(jù),可以直接修改索引結(jié)構(gòu) */ 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(); //創(chuàng)建修改請求 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; } /** * 刪除數(shù)據(jù) */ 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; } }
導(dǎo)入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)//指定注解可以應(yīng)用于類、接口或枚舉 @Retention(RetentionPolicy.RUNTIME)//可以通過反射機(jī)制訪問和讀取 public @interface DocumentIndex { //指定索引的名稱。默認(rèn)為空字符串,表示未指定 String indexName() default ""; //默認(rèn)為索引的文檔數(shù)量上限為10000 int maxSize() default 10000; //指定索引的分片數(shù)量 默認(rèn)為3 分片可以提高索引的性能和可擴(kuò)展性 int shards() default 3; //指定索引的副本數(shù)量 默認(rèn)為1 副本可以提高數(shù)據(jù)的可靠性和查詢性能 int replicas() default 1; }
注解類IdIndex
/** * @Author:GuoYangsheng * @Description: * @name:IdIndex * @Date:2024/9/12 16:50 */ @Target(ElementType.FIELD)//指定 ‘IdIndex' 可以應(yīng)用于類中字段上 @Retention(RetentionPolicy.RUNTIME)//可以通過反射機(jī)制訪問和讀取 public @interface IdIndex { //指定屬性標(biāo)識符名稱為 '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' 可以應(yīng)用于類中字段上 @Retention(RetentionPolicy.RUNTIME)//可以通過反射機(jī)制訪問和讀取 public @interface PropertyIndex { //用于指定字段在Elasticsearch索引中的名稱 String name() default ""; //指定字段的數(shù)據(jù)類型 String type() default "keyword"; //指定用于字段的分詞器 String analyzer() default "ik_smart"; //是否建立索引 boolean index() default true; //指定用于搜索時(shí)的分詞器 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; /** * 創(chuàng)建索引 * * @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); } /** * 刪除數(shù)據(jù) * * @param indexName * @param id * @return */ @DeleteMapping("/deleteById") public Boolean deleteById(String indexName, String id) { return sysDeptService.deleteById(indexName, id); } /** * 修改數(shù)據(jù) * * @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 { /** * 創(chuàng)建索引 * * @param sysDept */ void createIndex(SysDept sysDept); /** * 保存 * * @param sysDept */ Boolean save(SysDept sysDept); /** * 刪除數(shù)據(jù) * * @param indexName * @param id * @return */ Boolean deleteById(String indexName, String id); /** * 修改數(shù)據(jù) * * @param sysDept * @return */ Boolean updateSysDept(SysDept sysDept); }
實(shí)現(xiàn)層 直接調(diào)用工具類方法即可
/** * @Author:GuoYangsheng * @Description: * @name:SysDeptServiceImpl * @Date:2024/9/12 20:26 */ @Service public class SysDeptServiceImpl implements SysDeptService { @Resource private ElasticSearchUtil elasticSearchUtil; /** * 創(chuàng)建索引 * * @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); } /** * 刪除數(shù)據(jù) * * @param indexName * @param id * @return */ @Override public Boolean deleteById(String indexName, String id) { return elasticSearchUtil.delete(indexName, id); } /** * 修改數(shù)據(jù) * * @param sysDept * @return */ @Override public Boolean updateSysDept(SysDept sysDept) { return elasticSearchUtil.updateData(sysDept); } }
在Elastic開發(fā)工具中查看效果,或者下載Apipost工具測試即可
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
mybaits-plus?lambdaQuery()?和?lambdaUpdate()?常見的使用方法
MyBatis-Plus是一個(gè)?MyBatis?(opens?new?window)的增強(qiáng)工具,在?MyBatis?的基礎(chǔ)上只做增強(qiáng)不做改變,為簡化開發(fā)、提高效率而生,這篇文章主要介紹了mybaits-plus?lambdaQuery()?和?lambdaUpdate()?比較常見的使用方法,需要的朋友可以參考下2023-01-01登陸驗(yàn)證碼kaptcha結(jié)合spring boot的用法詳解
在一個(gè)web應(yīng)用中驗(yàn)證碼是一個(gè)常見的元素。不管是防止機(jī)器人還是爬蟲都有一定的作用,下面這篇文章主要給大家介紹了登陸驗(yàn)證碼kaptcha結(jié)合spring boot用法的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-06-06SpringBoot獲取HttpServletRequest的3種方式總結(jié)
這篇文章主要給大家介紹了關(guān)于SpringBoot獲取HttpServletRequest的3種方式,在Spring boot項(xiàng)目中經(jīng)常要用到Servlet的常用對象如HttpServletRequest request,HttpServletResponse response,HttpSession session,需要的朋友可以參考下2023-08-08Java讀取文件及基于正則表達(dá)式的獲取電話號碼功能詳解
這篇文章主要介紹了Java讀取文件及基于正則表達(dá)式的獲取電話號碼功能,結(jié)合實(shí)例形式詳細(xì)分析了正則匹配操作的相關(guān)語法及電話號碼匹配的原理與實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-09-09Spring?Cloud?OpenFeign?遠(yuǎn)程調(diào)用
這篇文章主要介紹了Spring?Cloud?OpenFeign?遠(yuǎn)程調(diào)用,本文通過遠(yuǎn)程調(diào)用的GitHub開放API用到的OpenFeign作為示例代碼作為入口進(jìn)行講解。然后以圖解+解讀源碼的方式深入剖析了OpenFeign的運(yùn)行機(jī)制和架構(gòu)設(shè)計(jì),需要的朋友可以參考一下2022-08-08java WSDL接口webService實(shí)現(xiàn)方式
這篇文章主要為大家詳細(xì)介紹了java WSDL接口webService實(shí)現(xiàn)方式的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04