├── src ├── main │ ├── resources │ │ └── application.properties │ └── java │ │ └── com │ │ └── xinghua │ │ └── elasticsearchservice │ │ ├── service │ │ ├── IUserEsService.java │ │ ├── IProductEsService.java │ │ └── impl │ │ │ ├── UserEsServiceImplImpl.java │ │ │ └── ProductEsServiceImplImpl.java │ │ ├── common │ │ ├── model │ │ │ └── EntityEsModel.java │ │ ├── dto │ │ │ ├── SortDTO.java │ │ │ └── ExceptionDTO.java │ │ ├── utils │ │ │ ├── CommonException.java │ │ │ ├── ResultCode.java │ │ │ └── StandardResult.java │ │ └── service │ │ │ ├── IBaseService.java │ │ │ └── impl │ │ │ └── BaseServiceImpl.java │ │ ├── ElasticsearchServiceApplication.java │ │ ├── utils │ │ └── DataUtils.java │ │ ├── controller │ │ ├── UserEsController.java │ │ └── ProductEsController.java │ │ ├── model │ │ ├── UserEsModel.java │ │ └── ProductEsModel.java │ │ └── constans │ │ └── Constants.java └── test │ └── java │ └── com │ └── xinghua │ └── elasticsearchservice │ ├── ElasticsearchServiceApplicationTests.java │ ├── BaseProductEsTest.java │ └── ProductEsTest.java ├── README.md └── pom.xml /src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/17666555910/SpringBoot-Elasticsearch-Demo/HEAD/src/main/resources/application.properties -------------------------------------------------------------------------------- /src/test/java/com/xinghua/elasticsearchservice/ElasticsearchServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ElasticsearchServiceApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/service/IUserEsService.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.service; 2 | 3 | import com.xinghua.elasticsearchservice.common.service.IBaseService; 4 | import com.xinghua.elasticsearchservice.model.ProductEsModel; 5 | import com.xinghua.elasticsearchservice.model.UserEsModel; 6 | 7 | /** 8 | * @Description user接口层 9 | * @Author 姚广星 10 | * @Date 2020/2/24 16:57 11 | **/ 12 | public interface IUserEsService extends IBaseService { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/model/EntityEsModel.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.data.annotation.Id; 7 | 8 | /** 9 | * @Description 基础实体类 10 | * @Author 姚广星 11 | * @Date 2020/2/28 21:18 12 | **/ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class EntityEsModel { 17 | @Id 18 | private String id; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/service/IProductEsService.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.service; 2 | 3 | import com.xinghua.elasticsearchservice.common.service.IBaseService; 4 | import com.xinghua.elasticsearchservice.model.ProductEsModel; 5 | import org.elasticsearch.search.aggregations.Aggregations; 6 | import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; 7 | 8 | /** 9 | * @Description product接口层 10 | * @Author 姚广星 11 | * @Date 2020/2/24 16:57 12 | **/ 13 | public interface IProductEsService extends IBaseService { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/ElasticsearchServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 6 | 7 | 8 | /** 9 | * @Description 启动类 10 | * @Author 姚广星 11 | * @Date 2020/2/24 16:57 12 | **/ 13 | @SpringBootApplication 14 | @EnableSwagger2 15 | public class ElasticsearchServiceApplication { 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(ElasticsearchServiceApplication.class, args); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/service/impl/UserEsServiceImplImpl.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.service.impl; 2 | 3 | import com.xinghua.elasticsearchservice.common.service.impl.BaseServiceImpl; 4 | import com.xinghua.elasticsearchservice.model.UserEsModel; 5 | import com.xinghua.elasticsearchservice.service.IUserEsService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 9 | import org.springframework.stereotype.Service; 10 | 11 | /** 12 | * @Description user 实现层 13 | * @Author 姚广星 14 | * @Date 2020/2/24 16:57 15 | **/ 16 | @Slf4j 17 | @Service 18 | public class UserEsServiceImplImpl extends BaseServiceImpl implements IUserEsService { 19 | 20 | @Autowired 21 | private ElasticsearchTemplate elasticsearchTemplate; 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/dto/SortDTO.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.dto; 2 | 3 | import io.swagger.annotations.ApiModel; 4 | import io.swagger.annotations.ApiModelProperty; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import org.springframework.data.elasticsearch.annotations.Field; 9 | import org.springframework.data.elasticsearch.annotations.FieldType; 10 | 11 | /** 12 | * @Description 排序类 13 | * @Author 姚广星 14 | * @Date 2020/2/29 22:58 15 | **/ 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @ApiModel(value = "排序基类") 20 | public class SortDTO { 21 | 22 | /** 23 | * 需要排序的字段 24 | */ 25 | @ApiModelProperty(value = "需要排序的字段") 26 | private String key; 27 | 28 | /** 29 | * 排序规则 30 | */ 31 | @ApiModelProperty(value = "排序规则") 32 | private Boolean isASC; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/utils/CommonException.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.utils; 2 | 3 | /** 4 | * 异常类 5 | * 6 | * @author Xing 7 | */ 8 | public class CommonException extends RuntimeException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | private int code; 13 | 14 | public int getCode() { 15 | return code; 16 | } 17 | 18 | public void setCode(int code) { 19 | this.code = code; 20 | } 21 | 22 | public CommonException() { 23 | super(); 24 | } 25 | 26 | public CommonException(String message, Throwable cause) { 27 | super(message, cause); 28 | 29 | } 30 | 31 | public CommonException(String message) { 32 | super(message); 33 | 34 | } 35 | 36 | public CommonException(Throwable cause) { 37 | super(cause); 38 | 39 | } 40 | 41 | public CommonException(ResultCode resultCode) { 42 | super(resultCode.message()); 43 | this.code = resultCode.code(); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/service/impl/ProductEsServiceImplImpl.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.service.impl; 2 | 3 | import com.xinghua.elasticsearchservice.common.service.impl.BaseServiceImpl; 4 | import com.xinghua.elasticsearchservice.model.ProductEsModel; 5 | import com.xinghua.elasticsearchservice.service.IProductEsService; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.elasticsearch.search.aggregations.Aggregations; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 10 | import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; 11 | import org.springframework.stereotype.Service; 12 | 13 | /** 14 | * @Description product 实现层 15 | * @Author 姚广星 16 | * @Date 2020/2/24 16:57 17 | **/ 18 | @Slf4j 19 | @Service 20 | public class ProductEsServiceImplImpl extends BaseServiceImpl implements IProductEsService { 21 | 22 | @Autowired 23 | private ElasticsearchTemplate elasticsearchTemplate; 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/utils/DataUtils.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @Description 处理数据工具类 8 | * @Author 姚广星 9 | * @Date 2020/2/27 23:09 10 | **/ 11 | public class DataUtils { 12 | 13 | /** 14 | * 按指定大小,分隔集合,将集合按规定个数分为n个部分 15 | * 16 | * @param list 17 | * @param len 长度 18 | * @return 19 | */ 20 | public static List> splitList(List list, int len) { 21 | if (list == null || list.size() == 0 || len < 1) { 22 | return null; 23 | } 24 | //返回结果 25 | List> result = new ArrayList>(); 26 | //传入集合长度 27 | int size = list.size(); 28 | //分隔后的集合个数 29 | int count = (size + len - 1) / len; 30 | for (int i = 0; i < count; i++) { 31 | List subList = list.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1))); 32 | result.add(subList); 33 | } 34 | return result; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/dto/ExceptionDTO.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.dto; 2 | 3 | /** 4 | * 异常传输对象 5 | * 6 | * @author 姚广星 7 | * @date 2020/2/24 16:13 8 | */ 9 | public class ExceptionDTO { 10 | 11 | private String message; 12 | 13 | private int code; 14 | 15 | private StackTraceElement[] stackTrace; 16 | 17 | private String exceptionClassName; 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | this.message = message; 25 | } 26 | 27 | public int getCode() { 28 | return code; 29 | } 30 | 31 | public void setCode(int code) { 32 | this.code = code; 33 | } 34 | 35 | public StackTraceElement[] getStackTrace() { 36 | return stackTrace; 37 | } 38 | 39 | public void setStackTrace(StackTraceElement[] stackTrace) { 40 | this.stackTrace = stackTrace; 41 | } 42 | 43 | public String getExceptionClassName() { 44 | return exceptionClassName; 45 | } 46 | 47 | public void setExceptionClassName(String exceptionClassName) { 48 | this.exceptionClassName = exceptionClassName; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/utils/ResultCode.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.utils; 2 | 3 | /** 4 | * 公共的返回码 5 | * 返回码code: 6 | * 成功:10000 7 | * 失败:10001 8 | * 未登录:10002 9 | * 未授权:10003 10 | * 抛出异常:99999 11 | */ 12 | public enum ResultCode { 13 | 14 | SUCCESS(true,200,"操作成功!", true), 15 | 16 | FAIL(false,201,"操作失败", false), 17 | 18 | UNAUTHENTICATED(false,301,"您还未登录", false), 19 | 20 | UNAUTHORISE(false,302,"权限不足", false), 21 | 22 | MOBILEORPASSWORDERROR(false,303,"用户名或密码错误", false), 23 | 24 | ACCOUNT_DISABLED(false,304,"登录失败次数过多,账号被禁用", false), 25 | 26 | VERIFICATION_CODE_ERROR(false, 305, "验证码错误", false), 27 | 28 | SESSION_EXPIRATION(false, 306, "登录过期,请重新登录", false), 29 | 30 | SERVER_ERROR(false,500,"抱歉,系统繁忙,请稍后重试!", false); 31 | 32 | 33 | //操作是否成功 34 | private boolean success; 35 | //操作代码 36 | private int code; 37 | //提示信息 38 | private String message; 39 | // 响应业务状态 40 | private boolean state; 41 | 42 | ResultCode(boolean success, int code, String message, boolean state){ 43 | this.success = success; 44 | this.code = code; 45 | this.message = message; 46 | this.state = state; 47 | } 48 | 49 | public boolean success() { 50 | return success; 51 | } 52 | 53 | public int code() { 54 | return code; 55 | } 56 | 57 | public String message() { 58 | return message; 59 | } 60 | 61 | public boolean state() { 62 | return state; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/controller/UserEsController.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.controller; 2 | 3 | import com.xinghua.elasticsearchservice.common.utils.StandardResult; 4 | import com.xinghua.elasticsearchservice.constans.Constants; 5 | import com.xinghua.elasticsearchservice.model.UserEsModel; 6 | import com.xinghua.elasticsearchservice.service.IUserEsService; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.web.bind.annotation.*; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * @Description 用户 控制器 17 | * @Author 姚广星 18 | * @Date 2020/2/24 16:55 19 | **/ 20 | @RestController 21 | @Slf4j 22 | @Api(tags = "用户 控制器") 23 | public class UserEsController { 24 | 25 | @Autowired 26 | private IUserEsService userService; 27 | 28 | /** 29 | * 初始化数据 30 | * 1: 删除原有的索引 31 | * 2: 创建索引并且初始化映射 32 | * 3: bulk 批量初始化数据 33 | * 34 | * @param userModelListl 35 | */ 36 | @ApiOperation(value = "初始化数据 yaoguangxing", notes = "初始化数据 yaoguangxing", response = UserEsModel.class) 37 | @PutMapping("/user/init") 38 | public StandardResult bulkDelete(@RequestBody List userModelListl) { 39 | try { 40 | userService.init(userModelListl); 41 | return StandardResult.ok(Constants.SUCCESS_MSG); 42 | } catch (Exception e) { 43 | log.error("异常信息:", e); 44 | return StandardResult.faild("异常信息", e); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/model/UserEsModel.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.model; 2 | 3 | import com.xinghua.elasticsearchservice.common.model.EntityEsModel; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | import org.springframework.data.elasticsearch.annotations.Document; 10 | import org.springframework.data.elasticsearch.annotations.Field; 11 | import org.springframework.data.elasticsearch.annotations.FieldType; 12 | 13 | /** 14 | * @Description ES 实体类 15 | * Document:配置操作哪个索引下的哪个类型 16 | * Id:标记文档ID字段 17 | * Field:配置映射信息,如:分词器 18 | * @Author 姚广星 19 | * @Date 2020/2/24 16:13 20 | **/ 21 | 22 | @Data 23 | @NoArgsConstructor 24 | @AllArgsConstructor 25 | @ApiModel(value = "用户ES对象") 26 | @Document(indexName = "user", type = "user") 27 | public class UserEsModel extends EntityEsModel { 28 | 29 | /** 30 | * 名称 31 | */ 32 | @ApiModelProperty(value = "名称") 33 | @Field(analyzer = "ik_smart", searchAnalyzer = "ik_smart", type = FieldType.Text) 34 | private String name; 35 | 36 | /** 37 | * 年龄 38 | */ 39 | @ApiModelProperty(value = "年龄") 40 | private Integer age; 41 | 42 | /** 43 | * 居住地址 44 | */ 45 | @ApiModelProperty(value = "居住地址") 46 | @Field(analyzer = "ik_smart", searchAnalyzer = "ik_smart", type = FieldType.Text) 47 | private String address; 48 | 49 | /** 50 | * 手机 51 | */ 52 | @ApiModelProperty(value = "手机") 53 | @Field(type = FieldType.Keyword) 54 | private String mobile; 55 | 56 | /** 57 | * 性别 1:男 2:女 58 | */ 59 | @ApiModelProperty(value = "性别 1:男 2:女") 60 | private String sex; 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/constans/Constants.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.constans; 2 | 3 | 4 | /** 5 | * @author 姚广星 6 | * @Description 常量类 7 | * @Date 2020/2/24 16:13 8 | */ 9 | public class Constants { 10 | 11 | /** 12 | * 系统错误信息 13 | */ 14 | public static final String SYSTEM_ERROR_MSG = "系统内部错误,请刷新页面重试或联系管理员解决"; 15 | 16 | public static final String SUCCESS_MSG = "操作成功"; 17 | 18 | public static final String NO_ROLE_ERROR = "当前登陆人未配置相应权限"; 19 | 20 | public static final String PARAM_ERROR = "参数错误"; 21 | 22 | /*** 23 | * 系统是否过滤HTML参数 24 | */ 25 | public static final String SYSTEM_PARAMETERS_FLAG = "system.parameters.flag"; 26 | 27 | /** 28 | * 系统数据状态 29 | */ 30 | public static final String SYSTEM_DATA_ISDELETE_NO = "0";// 可用 31 | public static final String SYSTEM_DATA_ISDELETE_YES = "1";//删除 32 | public static final String SYSTEM_DATA_ISDELETE_DISABLED = "2";//禁用 33 | 34 | //是否禁用 35 | public static final String SYSTEM_DATA_DISABLED = "0";//否 36 | public static final String SYSTEM_DATA_ABLE = "1";//是 37 | 38 | public static final String SYSTEM_TOKEN = "accessToken"; 39 | 40 | /** 41 | * 数字0和1常量 42 | */ 43 | public static final String DATA_ZERO = "0"; 44 | public static final String DATA_ONE = "1"; 45 | public static final String DATA_TWO = "2"; 46 | 47 | /** 48 | * 响应码常量 49 | */ 50 | public static final String SYSTEM_ENCODING = "UTF-8";// 系统编码 51 | public static final int RESPONSE_CODE_SUCCESS = 200;// 响应成功 52 | public static final int RESPONSE_CODE_ERROR = 500;// 响应失败 53 | public static final int RESPONSE_CODE_LOGIN_FAILED = 401;// 登录失败 54 | public static final int RESPONSE_CODE_TOKEN_FAILURE = 403;// 登录的 token 已过期 或者 不存在 55 | public static final int RESPONSE_CODE_HANDLE_FAILURE = 600;//工作项已被别人办理 56 | public static final int RESPONSE_CODE_URL_FAILURE = 700;// 应用无权限访问此接口 57 | public static final String RESPONSE_MSG_ERROR = "/error"; //异常跳转地址 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/model/ProductEsModel.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.model; 2 | 3 | import com.xinghua.elasticsearchservice.common.model.EntityEsModel; 4 | import io.swagger.annotations.ApiModel; 5 | import io.swagger.annotations.ApiModelProperty; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Data; 8 | import lombok.NoArgsConstructor; 9 | import org.springframework.data.annotation.Id; 10 | import org.springframework.data.elasticsearch.annotations.Document; 11 | import org.springframework.data.elasticsearch.annotations.Field; 12 | import org.springframework.data.elasticsearch.annotations.FieldType; 13 | 14 | /** 15 | * @Description ES 实体类 16 | * Document:配置操作哪个索引下的哪个类型 17 | * Id:标记文档ID字段 18 | * Field:配置映射信息,如:分词器 19 | * @Author 姚广星 20 | * @Date 2020/2/24 16:13 21 | **/ 22 | 23 | @Data 24 | @NoArgsConstructor 25 | @AllArgsConstructor 26 | @ApiModel(value = "商品ES对象") 27 | @Document(indexName = "product", type = "product") 28 | public class ProductEsModel extends EntityEsModel { 29 | 30 | /** 31 | * 名称 32 | */ 33 | @ApiModelProperty(value = "名称") 34 | @Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word", type = FieldType.Text) 35 | private String title; 36 | 37 | /** 38 | * 价格 39 | */ 40 | @ApiModelProperty(value = "价格") 41 | private Double price; 42 | 43 | /** 44 | * 产地 45 | */ 46 | @ApiModelProperty(value = "产地") 47 | @Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word", type = FieldType.Text) 48 | private String origin; 49 | 50 | /** 51 | * 品牌ID 52 | */ 53 | @ApiModelProperty(value = "品牌ID") 54 | @Field(type = FieldType.Keyword) 55 | private String brandId; 56 | 57 | /** 58 | * 品牌名称 59 | */ 60 | @ApiModelProperty(value = "品牌名称") 61 | @Field(type = FieldType.Keyword) 62 | private String brandName; 63 | 64 | /** 65 | * 关键字 66 | */ 67 | @ApiModelProperty(value = "关键字") 68 | @Field(analyzer = "ik_max_word", searchAnalyzer = "ik_max_word", type = FieldType.Text) 69 | private String keyword; 70 | 71 | public ProductEsModel(String id, String title, Double price, String origin, String brandId, String brandName, String keyword) { 72 | super(id); 73 | this.title = title; 74 | this.price = price; 75 | this.origin = origin; 76 | this.brandId = brandId; 77 | this.brandName = brandName; 78 | this.keyword = keyword; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return "ProductEsModel{" + 84 | "title='" + title + '\'' + 85 | ", id=" + super.getId() + 86 | ", price=" + price + 87 | ", origin='" + origin + '\'' + 88 | ", brandId='" + brandId + '\'' + 89 | ", brandName='" + brandName + '\'' + 90 | ", keyword='" + keyword + '\'' + 91 | '}'; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SpringBoot-Elasticsearch-Demo 2 | 3 | ### 题外话: 4 | 本实例为博主原创,属于简单易上手并且能够拿来就用的SpringBoot ES 项目,全文使用的是ElasticsearchTemplate进行开发。 5 | 本实例涵盖ES中的各类操作,如索引操作、CRUD操作、批处理、结果排序、分页查询、检索查询、关键字查询、高亮显示、逻辑查询、过滤查询、分组查询等等。并且已经过生产环境验证,各位可放心使用。如有不对之处欢迎在博客中留言交流。谢谢!!! 6 | 7 | **欢迎各位大神添加微信公众号:“愿为最亮星”,我们将在这一起探讨Java技术。** 8 | 9 | 10 | ### 1、CSDN 专栏:《Elasticsearch 入门和项目实战》 11 | #### 博客路径: https://blog.csdn.net/a767815662/category_9190277.html 12 | |--- 第一讲:简介以及安装 13 | |--- 第二讲:kibana 安装以及ES 的概念名词 14 | |--- 第三讲:ES 基本操作、批处理 15 | |--- 第四讲:ES 高级查询 16 | |--- 第五讲:ES 项目实战(一):简介及环境搭建 17 | |--- 第六讲:ES 项目实战(二):基本操作、批处理、高级查询 18 | 19 | 20 | ### 2、项目介绍: 21 | 本项目是基于SpringBoot 2.1.3 版本进行开发的,采用的是 Spring Data Elasticsearch。 22 | 23 | ElasticsearchTemplate:框架封装的用于便捷操作Elasticsearch的模板类 24 | NativeSearchQueryBuilder:用于生成查询条件的构建器,需要去封装各种查询条件 25 | QueryBuilder:该接口表示一个查询条件,其对象可以通过QueryBuilders工具类中的方法快速生成各种条件 26 | boolQuery():生成bool条件,相当于 "bool": { } 27 | matchQuery():生成match条件,相当于 "match": { } 28 | rangeQuery():生成range条件,相当于 "range": { } 29 | AbstractAggregationBuilder:用于生成分组查询的构建器,其对象通过AggregationBuilders工具类生成 30 | Pageable:表示分页参数,对象通过PageRequest.of(页数, 容量)获取 31 | SortBuilder:排序构建器,对象通过SortBuilders.fieldSort(字段).order(规则)获取 32 | 33 | ### 3、项目结构介绍: 34 | --- com.xinghua.elasticsearchservice 35 | | --- common 基础依赖 36 | | --- dto 展示层 37 | | --- model 基础实体类 38 | | --- utils 基础工具包 39 | | --- service 基础业务包(通用CRUD,批量操作接口) 40 | | --- impl 基础业务实现层(通用CRUD,批量操作实现) 41 | | --- constans 常量包 42 | | --- controller 视图层 43 | | --- model 实体 44 | | --- service 业务层 45 | | --- impl 业务实现层 46 | | --- utils 工具包 47 | 48 | ### 4、项目集成的插件 49 | --- swagger API 50 | --- lombok 51 | --- elasticsearch 52 | --- fastjson 53 | 54 | ### 5、已实现的ES功能 55 | --- IBaseService 56 | | --- getIndexName(): 获取ES索引名称 57 | | --- getIndexType(): 获取ES索引类型 58 | | --- getEntityClass(): 返回泛型上的Class对象 59 | | --- init(List entityList): 初始化数据 60 | | --- createEntityEsIndex(): 创建索引和映射 61 | | --- saveOrUpdate(T entityModel): 新增或修改 62 | | --- delete(String id): 删除entity 63 | | --- deleteIndex(): 删除索引 64 | | --- batchInsertOrUpdate(List entityModelList):批量新增/更新 65 | 66 | 以下是高级查询相关的接口 67 | | --- getPageRequest(int pageNumber, int pageSize):获取PageRequest对象 68 | | --- searchPage(NativeSearchQueryBuilder nativeSearchQueryBuilder, int pageNumber, int pageSize):分页查询 69 | | --- searchPageBySort(List sortDTOList, NativeSearchQueryBuilder nativeSearchQueryBuilder, int pageNumber, int pageSize):分页查询 按照指定字段排序,多个字段按照先后顺序排序 70 | | --- searchList(NativeSearchQueryBuilder nativeSearchQueryBuilder):查询操作 71 | | --- searchListBySort(List sortDTOList, NativeSearchQueryBuilder nativeSearchQueryBuilder):查询操作-按照指定字段排序,多个字段按照先后顺序排序 72 | | --- query(NativeSearchQueryBuilder nativeSearchQueryBuilder):用于分组查询 73 | 74 | ### 6、实例测试类 75 | --- BaseProductEsTest:基础功能测试类 76 | --- ProductEsTest:各种高级查询功能测试类 77 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/service/IBaseService.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.service; 2 | 3 | import com.xinghua.elasticsearchservice.common.dto.SortDTO; 4 | import com.xinghua.elasticsearchservice.common.model.EntityEsModel; 5 | import org.elasticsearch.index.query.QueryBuilder; 6 | import org.elasticsearch.search.aggregations.Aggregations; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.PageRequest; 9 | import org.springframework.data.domain.Pageable; 10 | import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @Description 提供公共的,基础的 ElasticSearch 功能 16 | * @Author 姚广星 17 | * @Date 2020/2/24 16:57 18 | **/ 19 | public interface IBaseService { 20 | 21 | /** 22 | * 获取ES索引名称 23 | * 24 | * @return 25 | */ 26 | String getIndexName(); 27 | 28 | /** 29 | * 获取ES索引类型 30 | * 31 | * @return 32 | */ 33 | String getIndexType(); 34 | 35 | 36 | /** 37 | * 返回泛型上的Class对象 38 | * 39 | * @return 40 | */ 41 | Class getEntityClass(); 42 | 43 | /** 44 | * 初始化数据 45 | * 1: 删除原有的索引 46 | * 2: 创建索引并且初始化映射 47 | * 3: bulk 批量初始化数据 48 | * 49 | * @param entityList 50 | * @throws Exception 51 | */ 52 | void init(List entityList); 53 | 54 | /** 55 | * 创建索引和映射(若原有索引存在则删除重新创建) 56 | * 57 | * @return 58 | */ 59 | Boolean createEntityEsIndex(); 60 | 61 | /** 62 | * 新增或修改 63 | * 64 | * @param entityModel 65 | * @return 66 | */ 67 | String saveOrUpdate(T entityModel); 68 | 69 | /** 70 | * 删除entity 71 | * 72 | * @param id 73 | * @return 74 | */ 75 | String delete(String id); 76 | 77 | /** 78 | * 删除索引 79 | * 80 | * @return 81 | */ 82 | Boolean deleteIndex(); 83 | 84 | 85 | /** 86 | * 批量新增/更新 87 | * 88 | * @param entityModelList 89 | */ 90 | void batchInsertOrUpdate(List entityModelList); 91 | 92 | /** 93 | * 分页查询 94 | * 95 | * @param nativeSearchQueryBuilder 查询条件 96 | * @param pageNumber 页数 97 | * @param pageSize 页码 98 | * @return 99 | */ 100 | Page searchPage(NativeSearchQueryBuilder nativeSearchQueryBuilder, int pageNumber, int pageSize); 101 | 102 | /** 103 | * 分页查询 按照指定字段排序,多个字段按照先后顺序排序 104 | * 105 | * @param sortDTOList 排序条件 106 | * @param nativeSearchQueryBuilder 查询条件 107 | * @param pageNumber 页数 108 | * @param pageSize 页码 109 | * @return 110 | */ 111 | Page searchPageBySort(List sortDTOList, NativeSearchQueryBuilder nativeSearchQueryBuilder, int pageNumber, int pageSize); 112 | 113 | /** 114 | * 查询操作 115 | * 116 | * @param nativeSearchQueryBuilder 查询条件 117 | * @return 118 | */ 119 | List searchList(NativeSearchQueryBuilder nativeSearchQueryBuilder); 120 | 121 | /** 122 | * 查询操作-按照指定字段排序,多个字段按照先后顺序排序 123 | * 124 | * @param sortDTOList 排序条件 125 | * @param nativeSearchQueryBuilder 查询条件 126 | * @return 127 | */ 128 | List searchListBySort(List sortDTOList, NativeSearchQueryBuilder nativeSearchQueryBuilder); 129 | 130 | /** 131 | * 获取PageRequest对象 132 | * 133 | * @param pageNumber 页数 134 | * @param pageSize 页码 135 | * @return 136 | */ 137 | PageRequest getPageRequest(int pageNumber, int pageSize); 138 | 139 | /** 140 | * 用于分组查询 141 | * 142 | * @param nativeSearchQueryBuilder 查询条件 143 | * @return Aggregations 即 DSL 中的 aggs 144 | */ 145 | Aggregations query(NativeSearchQueryBuilder nativeSearchQueryBuilder); 146 | } 147 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.3.RELEASE 9 | 10 | 11 | 12 | 13 | 14 | false 15 | 16 | jcenter-releases 17 | jcenter 18 | http://jcenter.bintray.com 19 | 20 | 21 | com.xinghua 22 | elasticsearch-service 23 | 1.0.0 24 | elasticsearch-service 25 | Demo project for Spring Boot 26 | 27 | 28 | 1.8 29 | 2.7.0 30 | 1.3.1 31 | 1.5.16 32 | 1.5.16 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | 42 | 43 | io.springfox 44 | springfox-swagger2 45 | ${swagger.version} 46 | 47 | 48 | io.springfox 49 | springfox-swagger-ui 50 | ${swagger.version} 51 | 52 | 53 | io.github.swagger2markup 54 | swagger2markup 55 | ${swagger2markup.version} 56 | 57 | 58 | io.swagger 59 | swagger-core 60 | ${swagger-core.version} 61 | 62 | 63 | io.swagger 64 | swagger-models 65 | ${swagger-models.version} 66 | 67 | 68 | 69 | 70 | org.springframework.boot 71 | spring-boot-starter-data-elasticsearch 72 | 73 | 74 | 75 | 76 | org.projectlombok 77 | lombok 78 | true 79 | 80 | 81 | 82 | org.springframework.boot 83 | spring-boot-starter-test 84 | test 85 | 86 | 87 | org.junit.vintage 88 | junit-vintage-engine 89 | 90 | 91 | 92 | 93 | org.junit.jupiter 94 | junit-jupiter 95 | RELEASE 96 | test 97 | 98 | 99 | 100 | 101 | com.alibaba 102 | fastjson 103 | 1.2.32 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | org.springframework.boot 112 | spring-boot-maven-plugin 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /src/test/java/com/xinghua/elasticsearchservice/BaseProductEsTest.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice; 2 | 3 | import com.xinghua.elasticsearchservice.model.ProductEsModel; 4 | import com.xinghua.elasticsearchservice.service.IProductEsService; 5 | import org.junit.jupiter.api.AfterEach; 6 | import org.junit.jupiter.api.BeforeEach; 7 | import org.junit.jupiter.api.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.test.context.junit4.SpringRunner; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | * @Description 基础功能测试类 18 | * @Author 姚广星 19 | * @Date 2020/3/1 12:55 20 | **/ 21 | @RunWith(SpringRunner.class) 22 | @SpringBootTest 23 | class BaseProductEsTest { 24 | 25 | @Autowired 26 | private IProductEsService productEsService; 27 | 28 | @BeforeEach 29 | void setUp() { 30 | //System.out.println("执行初始化"); 31 | } 32 | 33 | @AfterEach 34 | void tearDown() { 35 | } 36 | 37 | /** 38 | * 获取索引名称 39 | */ 40 | @Test 41 | void getIndexName() { 42 | System.out.println(productEsService.getIndexName()); 43 | } 44 | 45 | /** 46 | * 获取类型 47 | */ 48 | @Test 49 | void getIndexType() { 50 | System.out.println(productEsService.getIndexType()); 51 | } 52 | 53 | /** 54 | * 删除索引 55 | */ 56 | @Test 57 | void deleteIndex() { 58 | Boolean aBoolean = productEsService.deleteIndex(); 59 | System.out.println("aBoolean = " + aBoolean); 60 | } 61 | 62 | /** 63 | * 返回泛型上的Class对象 64 | */ 65 | @Test 66 | void getEntityClass() { 67 | System.out.println(productEsService.getEntityClass()); 68 | } 69 | 70 | /** 71 | * 创建索引和映射(若原有索引存在则删除重新创建) 72 | */ 73 | @Test 74 | void createEntityEsIndex() { 75 | System.out.println(productEsService.createEntityEsIndex()); 76 | } 77 | 78 | /** 79 | * 初始化数据 80 | * 1: 删除原有的索引 81 | * 2: 创建索引并且初始化映射 82 | * 3: bulk 批量初始化数据 83 | */ 84 | @Test 85 | void init() { 86 | List productEsModels = new ArrayList<>(); 87 | ProductEsModel p1 = new ProductEsModel("1", "小米2青春版手机", 1799.99, 88 | "广东省深圳市", "3", "小米", "小米2青春版手机"); 89 | 90 | ProductEsModel p2 = new ProductEsModel("2", "小米2经典版手机", 1899.99, 91 | "广东省深圳市", "3", "小米", "小米2经典版手机"); 92 | 93 | ProductEsModel p3 = new ProductEsModel("3", "小米note手机", 2799.99, 94 | "广东省深圳市", "3", "小米", "小米note手机"); 95 | 96 | ProductEsModel p4 = new ProductEsModel("4", "华为手机1", 1999.99, 97 | "湖南省", "1", "华为", "华为手机1"); 98 | 99 | ProductEsModel p5 = new ProductEsModel("5", "华为手机2", 2888.88, 100 | "湖南省", "1", "华为", "华为手机2"); 101 | 102 | ProductEsModel p6 = new ProductEsModel("6", "vivo 10", 999.99, 103 | "广东省广州市", "2", "vivo", "vivo 10"); 104 | 105 | ProductEsModel p7 = new ProductEsModel("7", "vivo 20", 1899.99, 106 | "广东省广州市", "2", "vivo", "vivo 20"); 107 | 108 | productEsModels.add(p1); 109 | productEsModels.add(p2); 110 | productEsModels.add(p3); 111 | productEsModels.add(p4); 112 | productEsModels.add(p5); 113 | productEsModels.add(p6); 114 | productEsModels.add(p7); 115 | productEsService.init(productEsModels); 116 | } 117 | 118 | /** 119 | * 新增或修改 120 | */ 121 | @Test 122 | void saveOrUpdate() { 123 | System.out.println(productEsService.saveOrUpdate(new ProductEsModel("8", "9", 1899.99, 124 | "广东省广州市", "2", "vivo", "80"))); 125 | } 126 | 127 | /** 128 | * 删除 129 | */ 130 | @Test 131 | void delete() { 132 | System.out.println(productEsService.delete("8")); 133 | } 134 | 135 | /** 136 | * 获取PageRequest对象 137 | */ 138 | @Test 139 | void getPageRequest() { 140 | System.out.println(productEsService.getPageRequest(1, 10)); 141 | } 142 | 143 | /** 144 | * 批量新增/更新 145 | */ 146 | @Test 147 | void batchInsertOrUpdate() { 148 | List productEsModels = new ArrayList<>(); 149 | ProductEsModel p1 = new ProductEsModel("8", "罗技鼠标", 990.00, 150 | "广东省湛江市", "4", "罗技", "罗技鼠标"); 151 | 152 | ProductEsModel p2 = new ProductEsModel("9", "双飞燕鼠标", 99.99, 153 | "广东省湛江市", "5", "双飞燕", "双飞燕鼠标"); 154 | productEsModels.add(p1); 155 | productEsModels.add(p2); 156 | productEsService.batchInsertOrUpdate(productEsModels); 157 | } 158 | 159 | } -------------------------------------------------------------------------------- /src/test/java/com/xinghua/elasticsearchservice/ProductEsTest.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice; 2 | 3 | import com.xinghua.elasticsearchservice.common.dto.SortDTO; 4 | import com.xinghua.elasticsearchservice.model.ProductEsModel; 5 | import com.xinghua.elasticsearchservice.service.IProductEsService; 6 | import org.elasticsearch.index.query.MatchQueryBuilder; 7 | import org.elasticsearch.index.query.QueryBuilder; 8 | import org.elasticsearch.index.query.QueryBuilders; 9 | import org.elasticsearch.search.aggregations.Aggregation; 10 | import org.elasticsearch.search.aggregations.AggregationBuilders; 11 | import org.elasticsearch.search.aggregations.Aggregations; 12 | import org.elasticsearch.search.aggregations.bucket.terms.DoubleTerms; 13 | import org.elasticsearch.search.aggregations.bucket.terms.LongTerms; 14 | import org.elasticsearch.search.aggregations.bucket.terms.StringTerms; 15 | import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg; 16 | import org.junit.jupiter.api.AfterEach; 17 | import org.junit.jupiter.api.BeforeEach; 18 | import org.junit.jupiter.api.Test; 19 | import org.junit.runner.RunWith; 20 | import org.mockito.internal.invocation.MatchersBinder; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.test.context.SpringBootTest; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; 25 | import org.springframework.test.context.junit4.SpringRunner; 26 | 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | 30 | import static org.junit.jupiter.api.Assertions.*; 31 | 32 | /** 33 | * @Description 各种高级查询功能测试类 34 | * @Author 姚广星 35 | * @Date 2020/3/1 12:55 36 | **/ 37 | @RunWith(SpringRunner.class) 38 | @SpringBootTest 39 | class ProductEsTest { 40 | 41 | @Autowired 42 | private IProductEsService productEsService; 43 | 44 | @BeforeEach 45 | void setUp() { 46 | //System.out.println("执行初始化"); 47 | } 48 | 49 | @AfterEach 50 | void tearDown() { 51 | } 52 | 53 | /** 54 | * 分页查询-按照价格降序排列,显示第2页,每页显示3个 (分页+排序) 55 | */ 56 | @Test 57 | void query1() { 58 | List sortDTOList = new ArrayList<>(); 59 | sortDTOList.add(new SortDTO("price", false)); 60 | Page productEsModels = productEsService.searchPageBySort(sortDTOList, new NativeSearchQueryBuilder(), 2, 3); 61 | productEsModels.forEach(System.out::println); 62 | } 63 | 64 | /** 65 | * 分页查询-按照品牌升序然后价格降序排列,显示第2页,每页显示3个 (分页+多条件排序) 66 | */ 67 | @Test 68 | void query2() { 69 | List sortDTOList = new ArrayList<>(); 70 | sortDTOList.add(new SortDTO("brandId", true)); 71 | sortDTOList.add(new SortDTO("price", false)); 72 | Page productEsModels = productEsService.searchPageBySort(sortDTOList, new NativeSearchQueryBuilder(), 2, 3); 73 | productEsModels.forEach(System.out::println); 74 | } 75 | 76 | /** 77 | * 查询商品标题中符合"小米 手机"的字样的商品 (match 查询) 78 | */ 79 | @Test 80 | void query3() { 81 | NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder(); 82 | searchQueryBuilder.withQuery( 83 | QueryBuilders.matchQuery("title", "小米 手机") 84 | ); 85 | List productEsModels = productEsService.searchList(searchQueryBuilder); 86 | productEsModels.forEach(System.out::println); 87 | } 88 | 89 | /** 90 | * 查询所有商品标题中带有 鼠标 或者 价格为 1899.99,并且按照价格降序排序 (逻辑查询 must / should / must_not,相当于and / or / not) 91 | */ 92 | @Test 93 | void query4() { 94 | NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); 95 | nativeSearchQueryBuilder.withQuery( 96 | QueryBuilders.boolQuery() 97 | .should(QueryBuilders.termQuery("title", "鼠标")) 98 | .should(QueryBuilders.termQuery("price", 1899.99)) 99 | ); 100 | List sortDTOList = new ArrayList<>(); 101 | sortDTOList.add(new SortDTO("price", false)); 102 | List productEsModels = productEsService.searchListBySort(sortDTOList, nativeSearchQueryBuilder); 103 | productEsModels.forEach(System.out::println); 104 | } 105 | 106 | /** 107 | * 查询商品标题或产地中符合"手机,湛江"的字样的商品 (关键字查询) 108 | */ 109 | @Test 110 | void query5() { 111 | NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); 112 | nativeSearchQueryBuilder.withQuery( 113 | QueryBuilders.multiMatchQuery("手机,湛江", "origin", "title") 114 | ); 115 | List productEsModels = productEsService.searchList(nativeSearchQueryBuilder); 116 | productEsModels.forEach(System.out::println); 117 | } 118 | 119 | /** 120 | * 查询商品标题中符合"手机"的商品,并且价格在 1900~2800之间 121 | */ 122 | @Test 123 | void query6() { 124 | NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); 125 | nativeSearchQueryBuilder.withQuery( 126 | QueryBuilders.boolQuery() 127 | .must(QueryBuilders.termQuery("title", "手机")) 128 | .must(QueryBuilders.rangeQuery("price").gte(1900).lte(2800)) 129 | ); 130 | List productEsModels = productEsService.searchList(nativeSearchQueryBuilder); 131 | productEsModels.forEach(System.out::println); 132 | } 133 | 134 | /** 135 | * 分组查询(桶聚合) 按照品牌分组,统计各品牌的平均价格 136 | */ 137 | @Test 138 | void query7() { 139 | NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); 140 | nativeSearchQueryBuilder.withIndices("product").withTypes("product"); 141 | nativeSearchQueryBuilder.addAggregation( 142 | AggregationBuilders.terms("groupByBrandId").field("brandId") 143 | .subAggregation( 144 | AggregationBuilders.avg("avgPrice").field("price") 145 | ) 146 | ); 147 | Aggregations group = productEsService.query(nativeSearchQueryBuilder); 148 | StringTerms groupByBrandId = group.get("groupByBrandId"); 149 | List buckets = groupByBrandId.getBuckets(); 150 | for (StringTerms.Bucket b : buckets) { 151 | InternalAvg avgPrice = b.getAggregations().get("avgPrice"); 152 | System.out.println(avgPrice.getValue()); 153 | } 154 | } 155 | 156 | @Test 157 | void query8() { 158 | 159 | } 160 | } -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/controller/ProductEsController.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.controller; 2 | 3 | import com.xinghua.elasticsearchservice.common.dto.SortDTO; 4 | import com.xinghua.elasticsearchservice.common.utils.StandardResult; 5 | import com.xinghua.elasticsearchservice.constans.Constants; 6 | import com.xinghua.elasticsearchservice.model.ProductEsModel; 7 | import com.xinghua.elasticsearchservice.service.IProductEsService; 8 | import io.swagger.annotations.Api; 9 | import io.swagger.annotations.ApiImplicitParam; 10 | import io.swagger.annotations.ApiImplicitParams; 11 | import io.swagger.annotations.ApiOperation; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.data.domain.Page; 15 | import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; 16 | import org.springframework.web.bind.annotation.*; 17 | 18 | import java.util.List; 19 | 20 | /** 21 | * @Description 商品 控制器 22 | * @Author 姚广星 23 | * @Date 2020/2/24 16:55 24 | **/ 25 | @RestController 26 | @Slf4j 27 | @Api(tags = "商品 控制器") 28 | public class ProductEsController { 29 | 30 | @Autowired 31 | private IProductEsService productService; 32 | 33 | /** 34 | * 创建 Product 索引和映 35 | * 36 | * @return 37 | */ 38 | @ApiOperation(value = "创建 Product 索引和映射 yaoguangxing", notes = "创建 Product 索引和映射 yaoguangxing", response = ProductEsModel.class) 39 | // @ApiImplicitParams({ 40 | // @ApiImplicitParam(paramType = "query", name = "accessToken", value = "令牌", required = true, dataType = "String"), 41 | // }) 42 | @PostMapping("/product/createProductEsIndex") 43 | public StandardResult createProductEsIndex() { 44 | try { 45 | productService.createEntityEsIndex(); 46 | return StandardResult.ok(Constants.SUCCESS_MSG); 47 | } catch (Exception e) { 48 | log.error("异常信息:", e); 49 | return StandardResult.faild("异常信息", e); 50 | } 51 | } 52 | 53 | /** 54 | * 批量新增和更新 55 | * 56 | * @return 57 | */ 58 | @ApiOperation(value = "批量新增和更新 yaoguangxing", notes = "批量新增和更新 yaoguangxing", response = ProductEsModel.class) 59 | @PutMapping("/product/bulkSaveOrUpDate") 60 | public StandardResult bulkSaveOrUpDate(@RequestBody List productModelList) { 61 | try { 62 | productService.batchInsertOrUpdate(productModelList); 63 | return StandardResult.ok(Constants.SUCCESS_MSG); 64 | } catch (Exception e) { 65 | log.error("异常信息:", e); 66 | return StandardResult.faild("异常信息", e); 67 | } 68 | } 69 | 70 | /** 71 | * 新增和更新 72 | * 73 | * @param productModel 74 | * @return 75 | */ 76 | @ApiOperation(value = "新增和更新 yaoguangxing", notes = "新增和更新 yaoguangxing", response = ProductEsModel.class) 77 | @PostMapping("/product/saveOrUpDate") 78 | public StandardResult saveOrUpDate(@ModelAttribute ProductEsModel productModel) { 79 | try { 80 | return StandardResult.ok(Constants.SUCCESS_MSG, productService.saveOrUpdate(productModel)); 81 | } catch (Exception e) { 82 | log.error("异常信息:", e); 83 | return StandardResult.faild("异常信息", e); 84 | } 85 | } 86 | 87 | /** 88 | * 删除商品 89 | * 90 | * @param id 91 | * @return 92 | */ 93 | @ApiOperation(value = "删除商品 yaoguangxing", notes = "删除商品 yaoguangxing", response = ProductEsModel.class) 94 | @PostMapping("/product/delete") 95 | public StandardResult delete(String id) { 96 | try { 97 | return StandardResult.ok(Constants.SUCCESS_MSG, productService.delete(id)); 98 | } catch (Exception e) { 99 | log.error("异常信息:", e); 100 | return StandardResult.faild("异常信息", e); 101 | } 102 | } 103 | 104 | /** 105 | * 删除商品索引 106 | * 107 | * @return 108 | */ 109 | @ApiOperation(value = "删除商品索引 yaoguangxing", notes = "删除商品索引 yaoguangxing", response = ProductEsModel.class) 110 | @PostMapping("/product/deleteProductIndex") 111 | public StandardResult deleteProductIndex() { 112 | try { 113 | return StandardResult.ok(Constants.SUCCESS_MSG, productService.deleteIndex()); 114 | } catch (Exception e) { 115 | log.error("异常信息:", e); 116 | return StandardResult.faild("异常信息", e); 117 | } 118 | } 119 | 120 | /** 121 | * 初始化数据 122 | * 1: 删除原有的索引 123 | * 2: 创建索引并且初始化映射 124 | * 3: bulk 批量初始化数据 125 | * 126 | * @param productModelList 127 | */ 128 | @ApiOperation(value = "初始化数据 yaoguangxing", notes = "初始化数据 yaoguangxing", response = ProductEsModel.class) 129 | @PutMapping("/product/init") 130 | public StandardResult bulkDelete(@RequestBody List productModelList) { 131 | try { 132 | productService.init(productModelList); 133 | return StandardResult.ok(Constants.SUCCESS_MSG); 134 | } catch (Exception e) { 135 | log.error("异常信息:", e); 136 | return StandardResult.faild("异常信息", e); 137 | } 138 | } 139 | 140 | @PutMapping("/product/getEntityClass") 141 | public StandardResult getEntityClass() { 142 | try { 143 | return StandardResult.ok(Constants.SUCCESS_MSG, productService.getEntityClass()); 144 | } catch (Exception e) { 145 | log.error("异常信息:", e); 146 | return StandardResult.faild("异常信息", e); 147 | } 148 | } 149 | 150 | /** 151 | * 分页查询 按照指定字段排序,多个字段按照先后顺序排序 152 | * 153 | * @param sortDTOList 154 | * @return 155 | */ 156 | @ApiOperation(value = "分页查询,按照指定字段排序,多个字段按照先后顺序排序 yaoguangxing", notes = "分页查询,按照指定字段排序,多个字段按照先后顺序排序 yaoguangxing", response = ProductEsModel.class) 157 | @ApiImplicitParams({ 158 | @ApiImplicitParam(paramType = "query", name = "page", value = "页码", required = true, dataType = "String"), 159 | @ApiImplicitParam(paramType = "query", name = "size", value = "每页大小", required = true, dataType = "String"), 160 | }) 161 | @PutMapping("/product/searchPageBySort") 162 | public StandardResult searchPageBySort(@RequestBody List sortDTOList, 163 | @RequestParam(name = "pageNumber", required = true) int pageNumber, 164 | @RequestParam(name = "pageSize", required = true) int pageSize) { 165 | try { 166 | NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); 167 | Page productEsModels = productService.searchPageBySort(sortDTOList, queryBuilder, pageNumber, pageSize); 168 | return StandardResult.ok(Constants.SUCCESS_MSG, productEsModels); 169 | } catch (Exception e) { 170 | log.error("异常信息:", e); 171 | return StandardResult.faild("异常信息", e); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/utils/StandardResult.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.utils; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | import com.xinghua.elasticsearchservice.common.dto.ExceptionDTO; 6 | import com.xinghua.elasticsearchservice.constans.Constants; 7 | import io.swagger.annotations.ApiModel; 8 | import io.swagger.annotations.ApiModelProperty; 9 | import lombok.ToString; 10 | 11 | import java.io.PrintWriter; 12 | import java.io.StringWriter; 13 | import java.util.ArrayList; 14 | 15 | /** 16 | * @author 姚广星 17 | * @Description 自定义响应结构 18 | * @Date 2020/2/24 16:13 19 | */ 20 | @ToString 21 | @ApiModel(value = "StandardResult", description = "标准自定义响应结构") 22 | public class StandardResult { 23 | 24 | 25 | /** 26 | * 响应业务状态 27 | */ 28 | @ApiModelProperty(value = "响应业务状态") 29 | private boolean state; 30 | 31 | /** 32 | * 响应消息 33 | */ 34 | @ApiModelProperty(value = "响应消息") 35 | private String msg; 36 | 37 | /** 38 | * 响应中的数据 39 | */ 40 | @ApiModelProperty(value = "响应中的数据") 41 | private Object data; 42 | 43 | /** 44 | * 响应状态码 200 响应成功 201缺少参数 0响应失败 45 | */ 46 | @ApiModelProperty(value = "响应状态码 200 响应成功 500响应失败") 47 | private int code; 48 | 49 | /** 50 | * 错误栈信息 51 | */ 52 | @JsonIgnore 53 | private String errorStackInfo; 54 | 55 | public StandardResult(boolean state, String msg, Object data, int code, String errorStackInfo) { 56 | super(); 57 | this.state = state; 58 | this.msg = msg; 59 | this.data = data; 60 | this.code = code; 61 | this.errorStackInfo = errorStackInfo; 62 | } 63 | 64 | public StandardResult(ResultCode resultCode, Object data) { 65 | this.code = resultCode.code(); 66 | this.state = resultCode.state(); 67 | this.msg = resultCode.message(); 68 | this.data = data; 69 | } 70 | 71 | public StandardResult(ExceptionDTO exceptionDTO) { 72 | this.code = exceptionDTO.getCode(); 73 | this.state = false; 74 | this.msg = exceptionDTO.getMessage(); 75 | } 76 | 77 | 78 | public StandardResult() { 79 | super(); 80 | } 81 | 82 | 83 | public static StandardResult resultCode(ResultCode resultCode) { 84 | return new StandardResult(resultCode, null); 85 | } 86 | 87 | public static StandardResult resultCode(ResultCode resultCode, Object object) { 88 | return new StandardResult(resultCode, object); 89 | } 90 | 91 | public static StandardResult exceptionResult(ExceptionDTO exceptionDTO) { 92 | return new StandardResult(exceptionDTO); 93 | } 94 | 95 | public static StandardResult ok(String msg, Object data) { 96 | if (data == null) { 97 | data = new ArrayList(); 98 | } 99 | 100 | if (msg == null) { 101 | msg = ""; 102 | } 103 | 104 | return new StandardResult(true, msg, data, Constants.RESPONSE_CODE_SUCCESS, null); 105 | } 106 | 107 | 108 | public static StandardResult ok(String msg) { 109 | 110 | return StandardResult.ok(msg, null); 111 | } 112 | 113 | public static StandardResult ok(Object data) { 114 | 115 | return StandardResult.ok(null, data); 116 | } 117 | 118 | 119 | public static StandardResult ok() { 120 | return StandardResult.ok(null); 121 | } 122 | 123 | public static StandardResult faild(String msg) { 124 | 125 | if (msg == null) { 126 | msg = ""; 127 | } 128 | 129 | return new StandardResult(false, msg, new ArrayList(), Constants.RESPONSE_CODE_ERROR, msg); 130 | } 131 | 132 | 133 | public static StandardResult faild(String msg, Exception ex) { 134 | 135 | if (msg == null) { 136 | msg = ""; 137 | } 138 | if (ex == null) { 139 | return new StandardResult(false, msg, new ArrayList(), Constants.RESPONSE_CODE_ERROR, msg); 140 | } else { 141 | return new StandardResult(false, msg, new ArrayList(), Constants.RESPONSE_CODE_ERROR, printStackTraceToString(ex)); 142 | } 143 | } 144 | 145 | public static StandardResult faild(Exception ex) { 146 | if (ex instanceof CommonException) { 147 | return faild(ex.getMessage(), ex); 148 | } else if (ex.getCause() instanceof CommonException) { 149 | return faild(ex.getCause().getMessage(), ex); 150 | } else if (ex.getCause() != null && ex.getCause().getCause() instanceof CommonException) { 151 | return faild(ex.getCause().getCause().getMessage(), ex); 152 | } 153 | return faild(Constants.SYSTEM_ERROR_MSG, ex); 154 | } 155 | 156 | /** 157 | * 验证不通过 158 | * 159 | * @param msg 160 | * @return 161 | */ 162 | public static StandardResult faildCheck(String msg) { 163 | if (msg == null) { 164 | msg = ""; 165 | } 166 | return new StandardResult(false, msg, new ArrayList(), Constants.RESPONSE_CODE_SUCCESS, msg); 167 | } 168 | 169 | public static StandardResult faildCheck(String msg, Object data) { 170 | if (msg == null) { 171 | msg = ""; 172 | } 173 | if (data == null) { 174 | data = new ArrayList(); 175 | } 176 | return new StandardResult(false, msg, data, Constants.RESPONSE_CODE_SUCCESS, null); 177 | } 178 | 179 | 180 | public static StandardResult loginFailed(String msg) { 181 | return new StandardResult(false, msg, new ArrayList(), Constants.RESPONSE_CODE_LOGIN_FAILED, msg); 182 | } 183 | 184 | public static StandardResult tokenFailure() { 185 | return new StandardResult(false, "token已过期或不存在", new ArrayList(), Constants.RESPONSE_CODE_TOKEN_FAILURE, "token已过期或不存在"); 186 | } 187 | 188 | public static StandardResult urlFailure() { 189 | return new StandardResult(false, "应用无权限访问此接口", new ArrayList(), Constants.RESPONSE_CODE_URL_FAILURE, "应用无权限访问此接口"); 190 | } 191 | 192 | public static StandardResult requestFailure() { 193 | return new StandardResult(false, Constants.SYSTEM_ERROR_MSG, new ArrayList(), Constants.RESPONSE_CODE_ERROR, "请求失败异常"); 194 | } 195 | 196 | public static StandardResult handleFailure() { 197 | return new StandardResult(false, "该工作项已经被办理,请刷新页面", new ArrayList(), Constants.RESPONSE_CODE_HANDLE_FAILURE, "该工作项已经被办理,请刷新页面"); 198 | } 199 | 200 | public boolean getState() { 201 | return state; 202 | } 203 | 204 | public void setState(boolean state) { 205 | this.state = state; 206 | } 207 | 208 | public String getMsg() { 209 | return msg; 210 | } 211 | 212 | public void setMsg(String msg) { 213 | this.msg = msg; 214 | } 215 | 216 | public Object getData() { 217 | return data; 218 | } 219 | 220 | public void setData(Object data) { 221 | this.data = data; 222 | } 223 | 224 | public int getCode() { 225 | return code; 226 | } 227 | 228 | public void setCode(int code) { 229 | this.code = code; 230 | } 231 | 232 | public String getErrorStackInfo() { 233 | return errorStackInfo; 234 | } 235 | 236 | 237 | public void setErrorStackInfo(String errorStackInfo) { 238 | this.errorStackInfo = errorStackInfo; 239 | } 240 | 241 | public static String printStackTraceToString(Throwable t) { 242 | StringWriter sw = new StringWriter(); 243 | t.printStackTrace(new PrintWriter(sw, true)); 244 | return sw.getBuffer().toString(); 245 | } 246 | 247 | /** 248 | * 校验后台返回StandardResult是否正常返回数据 249 | * 250 | * @param standardResult 251 | * @return boolean 252 | */ 253 | public static boolean standardResultBoolean(StandardResult standardResult) { 254 | boolean flag = false; 255 | if (standardResult != null && standardResult.getCode() == 200 && standardResult.getState() 256 | && standardResult.getData() != null) { 257 | flag = true; 258 | } 259 | return flag; 260 | } 261 | 262 | } 263 | 264 | -------------------------------------------------------------------------------- /src/main/java/com/xinghua/elasticsearchservice/common/service/impl/BaseServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.xinghua.elasticsearchservice.common.service.impl; 2 | 3 | import com.xinghua.elasticsearchservice.common.dto.SortDTO; 4 | import com.xinghua.elasticsearchservice.common.model.EntityEsModel; 5 | import com.xinghua.elasticsearchservice.common.utils.CommonException; 6 | import com.xinghua.elasticsearchservice.common.service.IBaseService; 7 | import com.xinghua.elasticsearchservice.utils.DataUtils; 8 | import io.swagger.models.auth.In; 9 | import lombok.extern.slf4j.Slf4j; 10 | import org.apache.commons.collections.CollectionUtils; 11 | import org.elasticsearch.action.update.UpdateRequest; 12 | import org.elasticsearch.common.xcontent.XContentFactory; 13 | import org.elasticsearch.index.query.QueryBuilder; 14 | import org.elasticsearch.search.aggregations.Aggregations; 15 | import org.elasticsearch.search.sort.SortBuilders; 16 | import org.elasticsearch.search.sort.SortOrder; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.data.domain.Page; 19 | import org.springframework.data.domain.PageRequest; 20 | import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 21 | import org.springframework.data.elasticsearch.core.query.*; 22 | import org.springframework.stereotype.Service; 23 | 24 | import java.io.IOException; 25 | import java.lang.reflect.ParameterizedType; 26 | import java.lang.reflect.Type; 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | 30 | /** 31 | * @Description 提供公共的,基础的 ElasticSearch 功能 32 | * @Author 姚广星 33 | * @Date 2020/2/27 22:50 34 | **/ 35 | @Slf4j 36 | @Service 37 | public class BaseServiceImpl implements IBaseService { 38 | 39 | @Autowired 40 | private ElasticsearchTemplate elasticsearchTemplate; 41 | 42 | 43 | @Override 44 | public String getIndexName() { 45 | return elasticsearchTemplate.getPersistentEntityFor(getEntityClass()).getIndexName(); 46 | } 47 | 48 | @Override 49 | public String getIndexType() { 50 | return elasticsearchTemplate.getPersistentEntityFor(getEntityClass()).getIndexType(); 51 | } 52 | 53 | @Override 54 | public Class getEntityClass() { 55 | Class tClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 56 | log.info("The type of T : " + tClass); 57 | return tClass; 58 | } 59 | 60 | @Override 61 | public String delete(String id) { 62 | return elasticsearchTemplate.delete(getEntityClass(), id); 63 | } 64 | 65 | @Override 66 | public Boolean deleteIndex() { 67 | return elasticsearchTemplate.deleteIndex(getEntityClass()); 68 | } 69 | 70 | @Override 71 | public void init(List entityModelList) { 72 | //判断索引是否存在 73 | boolean indexExists = elasticsearchTemplate.indexExists(getEntityClass()); 74 | if (indexExists) { 75 | //删除索引 76 | elasticsearchTemplate.deleteIndex(getEntityClass()); 77 | } 78 | //创建索引和mapper 79 | this.createEntityEsIndex(); 80 | //bulk 批量初始化数据 81 | this.batchInsertOrUpdate(entityModelList); 82 | } 83 | 84 | @Override 85 | public Boolean createEntityEsIndex() { 86 | boolean indexExists = elasticsearchTemplate.indexExists(getEntityClass()); 87 | if (indexExists) { 88 | boolean deleteIndex = elasticsearchTemplate.deleteIndex(getEntityClass()); 89 | if (!deleteIndex) { 90 | throw new CommonException(" delete entity elasticsearch index Error"); 91 | } 92 | } 93 | return this.createProductEsIndexAndMappers(); 94 | } 95 | 96 | @Override 97 | public void batchInsertOrUpdate(List entityModelList) { 98 | if (CollectionUtils.isEmpty(entityModelList)) { 99 | throw new CommonException("entityModelList Can't be empty"); 100 | } 101 | //判断索引是否存在 若不存在则创建索引和映射 102 | if (!elasticsearchTemplate.indexExists(getEntityClass())) { 103 | this.createEntityEsIndex(); 104 | } 105 | 106 | List queries = new ArrayList<>(); 107 | for (T entityEsModel : entityModelList) { 108 | IndexQuery indexQuery = new IndexQueryBuilder() 109 | .withId(entityEsModel.getId()) 110 | .withObject(entityEsModel) 111 | .build(); 112 | queries.add(indexQuery); 113 | } 114 | //批量插入 115 | this.bulkInsert(queries); 116 | } 117 | 118 | @Override 119 | public String saveOrUpdate(T entityModel) { 120 | IndexQuery indexQuery = new IndexQueryBuilder() 121 | .withId(entityModel.getId()) 122 | .withObject(entityModel) 123 | .build(); 124 | return elasticsearchTemplate.index(indexQuery); 125 | } 126 | 127 | /** 128 | * 批量插入 129 | * 130 | * @param queries 需要更新的 IndexQuery 集合 131 | */ 132 | private void bulkInsert(List queries) { 133 | //实际运用中一般是设置为 500 或者 1000 134 | int len = 1000; 135 | List> indexQueryLists = DataUtils.splitList(queries, len); 136 | indexQueryLists.stream().forEach(indexQueryList -> { 137 | elasticsearchTemplate.bulkIndex(indexQueryList); 138 | }); 139 | 140 | elasticsearchTemplate.refresh(getEntityClass()); 141 | log.info("bulkInsert completed of " + queries.size()); 142 | } 143 | 144 | 145 | /** 146 | * 创建索引和映射 147 | */ 148 | private Boolean createProductEsIndexAndMappers() { 149 | boolean index = elasticsearchTemplate.createIndex(getEntityClass()); 150 | if (!index) { 151 | throw new CommonException(" create entity elasticsearch index error"); 152 | } 153 | boolean putMapping = elasticsearchTemplate.putMapping(getEntityClass()); 154 | if (!putMapping) { 155 | throw new CommonException(" create entity elasticsearch mappers error"); 156 | } 157 | return true; 158 | } 159 | 160 | @Override 161 | public Page searchPage(NativeSearchQueryBuilder nativeSearchQueryBuilder, int pageNumber, int pageSize) { 162 | nativeSearchQueryBuilder.withIndices(getIndexName()); 163 | nativeSearchQueryBuilder.withTypes(getIndexType()); 164 | nativeSearchQueryBuilder.withPageable(this.getPageRequest(pageNumber, pageSize)); 165 | return elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), getEntityClass()); 166 | } 167 | 168 | @Override 169 | public PageRequest getPageRequest(int pageNumber, int pageSize) { 170 | if (pageNumber <= 0) { 171 | throw new CommonException("The page number parameter cannot be less than or equal to 0"); 172 | } 173 | //因为是从0开始计算的 所以此处需要自减1 174 | pageNumber--; 175 | return PageRequest.of(pageNumber, pageSize); 176 | } 177 | 178 | @Override 179 | public Page searchPageBySort(List sortDTOList, NativeSearchQueryBuilder nativeSearchQueryBuilder, 180 | int pageNumber, int pageSize) { 181 | this.joinSortBuilders(sortDTOList, nativeSearchQueryBuilder); 182 | return this.searchPage(nativeSearchQueryBuilder, pageNumber, pageSize); 183 | } 184 | 185 | @Override 186 | public List searchList(NativeSearchQueryBuilder nativeSearchQueryBuilder) { 187 | nativeSearchQueryBuilder.withIndices(getIndexName()); 188 | nativeSearchQueryBuilder.withTypes(getIndexType()); 189 | return elasticsearchTemplate.queryForList(nativeSearchQueryBuilder.build(), getEntityClass()); 190 | } 191 | 192 | @Override 193 | public List searchListBySort(List sortDTOList, NativeSearchQueryBuilder nativeSearchQueryBuilder) { 194 | this.joinSortBuilders(sortDTOList, nativeSearchQueryBuilder); 195 | return this.searchList(nativeSearchQueryBuilder); 196 | } 197 | 198 | /** 199 | * 拼接多个SortBuilders排序条件 200 | * 201 | * @param sortDTOList 排序条件集合 202 | * @param nativeSearchQueryBuilder 查询条件 203 | */ 204 | private void joinSortBuilders(List sortDTOList, NativeSearchQueryBuilder nativeSearchQueryBuilder) { 205 | for (SortDTO sortDTO : sortDTOList) { 206 | nativeSearchQueryBuilder.withSort( 207 | SortBuilders.fieldSort(sortDTO.getKey()).order(sortDTO.getIsASC() == true ? SortOrder.ASC : SortOrder.DESC) 208 | ); 209 | } 210 | } 211 | 212 | @Override 213 | public Aggregations query(NativeSearchQueryBuilder nativeSearchQueryBuilder) { 214 | nativeSearchQueryBuilder.withIndices(getIndexName()); 215 | nativeSearchQueryBuilder.withTypes(getIndexType()); 216 | return elasticsearchTemplate.query(nativeSearchQueryBuilder.build(), searchResponse -> searchResponse.getAggregations()); 217 | } 218 | } 219 | 220 | --------------------------------------------------------------------------------