目录
- 导入依赖
- 导入 ElasticSearchUtil 工具
- 导入config
- 注解类DocumentIndex
- 注解类IdIndex
- 注解类PropertyIndex
- controller
- service
- 实现层 直接调用工具类方法即可
- 总结
导入依赖
<!--提供与 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类下所有字段 http://www.devze.com Field[] declaredFields = data.getClass().getDeclaredFields(); //循环遍历 for (Field field : declaredFields) { //获取字段上的'IdIndex'的注解实例 IdIndex annotation = field.getAnnotation(IdIndex.class); //如果不为空 if (annotation != null) { //将annotation中的idNamejavascript赋给变量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;http://www.devze.com } /** * 更新数据,可以直接修改索引结构 */ 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 trphpue; } /** * 修改 * * @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}") javascript 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工具测试即可
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。
精彩评论