关于Elasticsearch封装公共索引增删改查
作者:小疙瘩的编程之路
索引是Elasticsearch中存储数据的逻辑单元,类似于关系数据库中的表,它包含多个文档,每个文档都是一个结构化的JSON数据格式,在实际应用中,索引的使用与配置可以依据不同的方案进行,例如在Spring Boot项目中,可以选择自动配置或者手动编写配置类
什么是索引?
- 定义:索引是 Elasticsearch 中用于存储数据的逻辑命名空间。它由多个文档组成,每个文档是一个 JSON 格式的结构化数据
- 对应关系:在关系数据库中,索引类似于表;而在 Elasticsearch 中,索引则相当于数据库的集合或目录。
依赖
选择方案一
使用这个依赖的话必须搭配配置类去使用
<!-- elasticsearch --> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.7.0</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.7.0</version> </dependency>
选择方案二
使用这个依赖的话配置类可写可不写,因为springboot工程已经帮我们自动的去完成配置了,不需要我们自己写了
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>
配置
es: host: 111.229.0.43 port: 9200 scheme: http
配置类
package com.macro.mall.demo.config; import lombok.Data; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; @Data @Component public class InitEsRes { @Value("${es.host}") private String host; @Value("${es.port}") private int port; @Value("${es.scheme}") private String scheme; @Bean public RestHighLevelClient restHighLevelClient(){ return new RestHighLevelClient( RestClient.builder(new HttpHost(host,port,scheme)) ); } }
dto
package com.macro.mall.demo.dto; import io.swagger.annotations.ApiModelProperty; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; /** * @Author:xsp * @Description: es索引传输对象 * @name:EsIndexDto * @Date:2024/10/16 15:30 */ @Data public class EsIndexDto { /** * 索引名称 */ @NotEmpty(message = "索引名称不能为空") @ApiModelProperty(value = "索引名称", required = true, example = "。。。。") private String indexName; /** * 索引映射 */ @ApiModelProperty(value = "索引映射", required = true, example = "。。。。") private String indexMappings; /** * 索引配置 */ @ApiModelProperty(value = "索引配置", required = true, example = "。。。。") private String indexSettings; }
controller
package com.macro.mall.demo.controller; import com.macro.mall.common.api.CommonResult; import com.macro.mall.demo.dto.EsIndexDto; import com.macro.mall.demo.service.EsIndexService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import jakarta.validation.constraints.NotEmpty; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.Map; /** * @Author:xsp * @Description: es索引管理 * @name:EsController * @Date:2024/10/15 20:38 */ @RestController @RequestMapping("/index") @Validated @Api(tags = "es索引管理") public class EsIndexController { @Autowired private EsIndexService esIndexService; /** * 创建索引的接口 * @param esIndexDto 索引信息 * @return */ @ApiOperation(value = "创建索引") @PostMapping("/create") public CommonResult createIndex(@Validated @RequestBody EsIndexDto esIndexDto) { esIndexService.createIndex(esIndexDto); return CommonResult.successMessage("索引创建成功"); // 调用服务方法创建索引 } /** * 删除索引的接口 * @param indexName 索引名称 * @return */ @ApiOperation(value = "删除索引") @DeleteMapping("/delete") public CommonResult deleteIndex(@RequestParam @NotEmpty(message = "索引名称不能为空") String indexName) { esIndexService.deleteIndex(indexName); // 调用服务方法删除索引 return CommonResult.successMessage("索引删除成功"); } /** * 获取索引的接口 * @param indexName 索引名称 * @return */ @ApiOperation(value = "获取索引映射") @GetMapping("/get") public CommonResult<Map<String, Object>> getIndex(@RequestParam @NotEmpty(message = "索引名称不能为空") String indexName) { Map<String, Object> indexMappings = esIndexService.getIndex(indexName); return CommonResult.success(indexMappings); // 调用服务方法获取索引 } /** * 根据索引名称修改索引配置 * @param esIndexDto 索引信息 * @return */ @ApiOperation(value = "修改索引配置") @PutMapping("/update") public CommonResult updateIndex(@Validated @RequestBody EsIndexDto esIndexDto) { esIndexService.updateIndex(esIndexDto); return CommonResult.successMessage("索引更新成功"); // 调用服务方法更新索引 } /** * 判断索引是否存在 * @param indexName 索引名称 * @return */ @ApiOperation(value = "判断索引是否存在") @GetMapping("/exists") public CommonResult exists(@RequestParam @NotEmpty(message = "索引名称不能为空") String indexName) { boolean exists =esIndexService.exists(indexName); return CommonResult.success(exists); } }
serveice
package com.macro.mall.demo.service; import com.macro.mall.demo.dto.EsDocDto; import com.macro.mall.demo.dto.EsIndexDto; import java.util.List; import java.util.Map; /** * @Author:xsp * @Description: * @name:EsService * @Date:2024/10/15 20:39 */ public interface EsDocService { /** * 批量添加 * @param esDocDto 文档信息 */ void batchAdd(EsDocDto esDocDto); /** * 批量删除 * @param indexName 索引名称 * @param ids 多个id */ void batchDelete(String indexName, List<String> ids); }
impl
package com.macro.mall.demo.service.impl; import com.macro.mall.demo.dto.EsDocDto; import com.macro.mall.demo.dto.EsIndexDto; import com.macro.mall.demo.service.EsIndexService; import lombok.extern.log4j.Log4j2; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.GetIndexRequest; import org.elasticsearch.client.indices.GetIndexResponse; import org.elasticsearch.common.xcontent.XContentType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Map; /** * @Author:xsp * @Description: * @name:EsServiceImpl * @Date:2024/10/15 20:39 */ @Service @Slf4j public class EsIndexServiceImpl implements EsIndexService { @Autowired private RestHighLevelClient restHighLevelClient; /** * 创建索引 * * @param esIndexDto 索引信息 */ @Override public void createIndex(EsIndexDto esIndexDto) { // 检查索引是否已存在 if (exists(esIndexDto.getIndexName())) { throw new RuntimeException("索引已经存在: " + esIndexDto.getIndexName()); } // 创建索引请求 CreateIndexRequest request = new CreateIndexRequest(esIndexDto.getIndexName()); // 设置索引配置 if (StringUtils.isNotBlank(esIndexDto.getIndexMappings())) { request.settings(esIndexDto.getIndexMappings(), XContentType.JSON); } // 执行创建索引操作 try { restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); log.info("索引创建成功: {}", esIndexDto.getIndexName()); } catch (Exception e) { log.error("创建索引失败, 错误信息: {}", e.getMessage()); throw new RuntimeException("创建索引失败: " + esIndexDto.getIndexName(), e); } } /** * 删除索引 * * @param indexName 索引名称 */ @Override public void deleteIndex(String indexName) { // 检查索引是否存在 if (!exists(indexName)) { throw new RuntimeException("索引不存在: " + indexName); } // 创建删除索引请求 DeleteIndexRequest request = new DeleteIndexRequest(indexName); // 执行删除索引操作 try { restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT); log.info("索引删除成功: {}", indexName); } catch (Exception e) { log.error("删除索引失败, 错误信息: {}", e.getMessage()); throw new RuntimeException("删除索引失败: " + indexName, e); } } /** * 获取索引映射 * * @param indexName 索引名称 * @return 索引映射信息 */ @Override public Map<String, Object> getIndex(String indexName) { // 检查索引是否存在 if (!exists(indexName)) { throw new RuntimeException("索引不存在: " + indexName); } // 创建获取索引请求 GetIndexRequest request = new GetIndexRequest(indexName); // 执行获取索引映射操作 try { GetIndexResponse response = restHighLevelClient.indices().get(request, RequestOptions.DEFAULT); log.info("获取索引映射成功: {}", indexName); return response.getMappings().get(indexName).sourceAsMap(); // 返回索引映射 } catch (Exception e) { log.error("获取索引映射失败, 错误信息: {}", e.getMessage()); throw new RuntimeException("获取索引映射失败: " + indexName, e); } } /** * 更新索引配置 * * @param esIndexDto 索引信息 */ @Override public void updateIndex(EsIndexDto esIndexDto) { // 检查索引是否存在 if (!exists(esIndexDto.getIndexName())) { throw new RuntimeException("索引不存在: " + esIndexDto.getIndexName()); } // 创建更新索引设置请求 UpdateSettingsRequest request = new UpdateSettingsRequest(esIndexDto.getIndexName()); // 更新索引映射 if (StringUtils.isNotBlank(esIndexDto.getIndexMappings())) { request.settings(esIndexDto.getIndexMappings(), XContentType.JSON); } // 执行更新索引设置操作 try { boolean acknowledged = restHighLevelClient.indices().putSettings(request, RequestOptions.DEFAULT).isAcknowledged(); if (acknowledged) { log.info("索引设置更新成功: {}", esIndexDto.getIndexName()); } else { log.warn("索引设置更新未被确认: {}", esIndexDto.getIndexName()); } } catch (Exception e) { log.error("更新索引设置失败, 错误信息: {}", e.getMessage()); throw new RuntimeException("更新索引设置失败: " + esIndexDto.getIndexName(), e); } } /** * 判断索引是否存在 * * @param indexName 索引名称 * @return 索引是否存在 */ @Override public boolean exists(String indexName) { // 创建获取索引请求 GetIndexRequest request = new GetIndexRequest(indexName); try { // 执行获取索引操作并返回索引是否存在 boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); log.info("判断索引是否存在: {}, 结果: {}", indexName, exists); return exists; } catch (Exception e) { log.error("判断索引是否存在失败, 错误信息: {}", e.getMessage()); return false; // 返回判断失败 } } }
统一结果集
package com.macro.mall.common.api; import cn.hutool.json.JSONUtil; /** * 通用返回对象 * Created by 9a8204a7-f77d-4ab8-ae70-b4721fef2f95 on 2019/4/19. */ public class CommonResult<T> { private long code; private String message; private T data; protected CommonResult() { } protected CommonResult(long code, String message, T data) { this.code = code; this.message = message; this.data = data; } /** * 成功返回信息 * @param message 提示信息 */ public static <T> CommonResult<T> successMessage(String message) { return new CommonResult<T>(ResultCode.SUCCESS.getCode(), message, null); } /** * 成功返回结果 * * @param data 获取的数据 */ public static <T> CommonResult<T> success(T data) { return new CommonResult<T>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data); } /** * 成功返回结果 * * @param data 获取的数据 * @param message 提示信息 */ public static <T> CommonResult<T> success(T data, String message) { return new CommonResult<T>(ResultCode.SUCCESS.getCode(), message, data); } /** * 失败返回结果 * @param errorCode 错误码 */ public static <T> CommonResult<T> failed(IErrorCode errorCode) { return new CommonResult<T>(errorCode.getCode(), errorCode.getMessage(), null); } /** * 失败返回结果 * @param errorCode 错误码 * @param message 错误信息 */ public static <T> CommonResult<T> failed(IErrorCode errorCode,String message) { return new CommonResult<T>(errorCode.getCode(), message, null); } /** * 失败返回结果 * @param message 提示信息 */ public static <T> CommonResult<T> failed(String message) { return new CommonResult<T>(ResultCode.FAILED.getCode(), message, null); } /** * 失败返回结果 */ public static <T> CommonResult<T> failed() { return failed(ResultCode.FAILED); } /** * 参数验证失败返回结果 */ public static <T> CommonResult<T> validateFailed() { return failed(ResultCode.VALIDATE_FAILED); } /** * 参数验证失败返回结果 * @param message 提示信息 */ public static <T> CommonResult<T> validateFailed(String message) { return new CommonResult<T>(ResultCode.VALIDATE_FAILED.getCode(), message, null); } /** * 未登录返回结果 */ public static <T> CommonResult<T> unauthorized(T data) { return new CommonResult<T>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage(), data); } /** * 未授权返回结果 */ public static <T> CommonResult<T> forbidden(T data) { return new CommonResult<T>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage(), data); } public long getCode() { return code; } public void setCode(long code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } @Override public String toString() { return JSONUtil.toJsonStr(this); } }
这里我用的是这个统一结果集,结合自己实际情况去使用相对应的统一结果集
Spring原生效验异常
@ResponseBody @ExceptionHandler(value = ApiException.class) public CommonResult handle(ApiException e) { if (e.getErrorCode() != null) { return CommonResult.failed(e.getErrorCode()); } return CommonResult.failed(e.getMessage()); } @ResponseBody @ExceptionHandler(value = MethodArgumentNotValidException.class) public CommonResult handleValidException(MethodArgumentNotValidException e) { BindingResult bindingResult = e.getBindingResult(); String message = null; if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); if (fieldError != null) { message = fieldError.getField()+fieldError.getDefaultMessage(); } } return CommonResult.validateFailed(message); } @ResponseBody @ExceptionHandler(value = BindException.class) public CommonResult handleValidException(BindException e) { BindingResult bindingResult = e.getBindingResult(); String message = null; if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); if (fieldError != null) { message = fieldError.getField()+fieldError.getDefaultMessage(); } } return CommonResult.validateFailed(message); } /** * 最大异常 * @param e * @return */ @ResponseBody @ExceptionHandler(value = Exception.class) public CommonResult handle(Exception e) { e.printStackTrace(); return CommonResult.validateFailed(e.getMessage()); }
这里我是用的这几个写的异常捕获器,结合自己实际情况去使用相对应的异常捕获
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。