前言
对于索引结构一旦创建 就不能增加分片 除非重建索引
那对于这种需求我们该怎么办呢?
步骤
- blog取⼀个别名blog_latest, blog_latest作为对外使⽤
- 新增⼀个索引blog_20220101,结构复制于nba索引,根据业务要求修改字段
- 将blog数据同步到blog_20220101
- 给blog_20220101添加别名blog_latest,删除blog别名blog_latest
- 删除blog索引
我们对外提供访问blog索引时使⽤的是blog_latest别名
下面举两个例子来说明
准备工程代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.haoran</groupId>
<artifactId>blog-es</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>blog-es</name>
<description>demo project for spring boot</description>
<properties>
<java.version>1.8</java.version>
<!-- <elasticsearch.version>8.0.1</elasticsearch.version>-->
<!-- <elasticsearch.version>7.17.2</elasticsearch.version>-->
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.elasticsearch.client</groupId>-->
<!-- <artifactId>elasticsearch-rest-high-level-client</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
blog系统
假如我们有个blog系统 里面有 美食类 技术类 新闻类 历史类等等类型
我们可以这么设计一个索引映射如下:
主键 标题 类型 作者 发布日期 内容等字段
package com.sixkery.entity.es;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@TypeAlias("Blog")
@Document(indexName = "Blog")
public class AbstractBlog {
@Id
@Field(type = FieldType.Long)
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String title;
@Field(type = FieldType.Keyword)
private String type;
@Field(type = FieldType.Keyword)
private String author;
@Field(type = FieldType.Date, pattern = "epoch_millis || yyyy-MM-dd HH:mm:ss")
private Long publishDate;
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
private String content;
}
美食类blog对象
@Data
@Document(indexName = "index_food_blog")
@Accessors
public class FoodBlog extends AbstractBlog {
}
技术类bolg对象
package com.sixkery.entity.es;
import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;
@Data
@Document(indexName = "index_technology_blog")
public class TechnologyBlog extends AbstractBlog {
}
对应的mapping如下:
{
"index_food_blog": {
"aliases": {
"Blog": {}
},
"mappings": {
"properties": {
"_class": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"author": {
"type": "keyword"
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
},
"id": {
"type": "keyword"
},
"publishDate": {
"type": "date",
"format": "epoch_millis || yyyy-MM-dd HH:mm:ss"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"type": {
"type": "keyword"
}
}
},
"settings": {
"index": {
"refresh_interval": "1s",
"number_of_shards": "5",
"provided_name": "index_food_blog",
"creation_date": "1654742590809",
"store": {
"type": "fs"
},
"number_of_replicas": "1",
"uuid": "HA1i6JWgSfyz04aaZcI48Q",
"version": {
"created": "7040299"
}
}
}
},
"index_technology_blog": {
"aliases": {
"Blog": {}
},
"mappings": {
"properties": {
"_class": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"author": {
"type": "keyword"
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
},
"id": {
"type": "keyword"
},
"publishDate": {
"type": "date",
"format": "epoch_millis || yyyy-MM-dd HH:mm:ss"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"type": {
"type": "keyword"
}
}
},
"settings": {
"index": {
"refresh_interval": "1s",
"number_of_shards": "5",
"provided_name": "index_technology_blog",
"creation_date": "1654742591150",
"store": {
"type": "fs"
},
"number_of_replicas": "1",
"uuid": "gp1G1m7dRFCCflBJq3SA8g",
"version": {
"created": "7040299"
}
}
}
}
}
看我们的查询和编辑操作
package com.sixkery.controller;
import com.sixkery.entity.es.AbstractBlog;
import com.sixkery.entity.es.FoodBlog;
import com.sixkery.entity.es.TechnologyBlog;
import com.sixkery.repository.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.MultiGetItem;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@RestController
@Slf4j
@RequestMapping("/blog")
public class BlogController {
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Resource
private FoodBlogRepository foodBlogRepository;
@Resource
private TechnologyBlogRepository technologyBlogRepository;
private AtomicLong id = new AtomicLong(0);
@PostMapping("/add")
public ResponseEntity<Object> addFoodBlog(@RequestBody BlogDTO blogDTO) {
if (blogDTO.getType().equalsIgnoreCase("food")) {
FoodBlog target = new FoodBlog();
BeanUtils.copyProperties(blogDTO, target);
target.setId(id.addAndGet(1));
return ResponseEntity.ok(foodBlogRepository.save(target));
} else {
TechnologyBlog target = new TechnologyBlog();
BeanUtils.copyProperties(blogDTO, target);
target.setId(id.addAndGet(1));
return ResponseEntity.ok(technologyBlogRepository.save(target));
}
}
@GetMapping("/foodBlogs")
public ResponseEntity<Iterable<FoodBlog>> foodBlogs() {
return ResponseEntity.ok(foodBlogRepository.findAll());
}
@GetMapping("/technologyBlog")
public ResponseEntity<Iterable<TechnologyBlog>> technologyBlog() {
return ResponseEntity.ok(technologyBlogRepository.findAll());
}
@GetMapping("/allTypeBlog")
public ResponseEntity<SearchHits<AbstractBlog>> allTypeBlog() {
// elasticsearchRestTemplate.indexOps(FoodBlog.class).
IndexCoordinates blog = IndexCoordinates.of("Blog");
// IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(blog);
Query query = elasticsearchRestTemplate.matchAllQuery();
SearchHits<AbstractBlog> search = elasticsearchRestTemplate.search(query, AbstractBlog.class, blog);
// List<MultiGetItem<AbstractBlog>> multiGetItems = elasticsearchRestTemplate.multiGet(query, AbstractBlog.class);
return ResponseEntity.ok(search);
}
// @DeleteMapping("/deleteIndex")
// public ResponseEntity<Boolean> deleteIndex() {
// boolean deleteIndex1 = elasticsearchRestTemplate.deleteIndex(FoodBlog.class);
// boolean deleteIndex2 = elasticsearchRestTemplate.deleteIndex(TechnologyBlog.class);
// return ResponseEntity.ok(deleteIndex1 && deleteIndex2);
// }
// @PutMapping("/createIndex")
// public ResponseEntity<String> createIndex() {
// boolean deleteIndex1 = elasticsearchRestTemplate.createIndex(FoodBlog.class);
// boolean deleteIndex2 = elasticsearchRestTemplate.createIndex(TechnologyBlog.class);
// boolean putMapping1 = elasticsearchRestTemplate.putMapping(FoodBlog.class);
// boolean putMapping2 = elasticsearchRestTemplate.putMapping(TechnologyBlog.class);
// boolean addAlias1 = ElasticsearchIndexOps.addAlias(FoodBlog.class.getAnnotation(Document.class).indexName(),
// FoodBlog.class.getAnnotation(TypeAlias.class).value());
// boolean addAlias2 = ElasticsearchIndexOps.addAlias(TechnologyBlog.class.getAnnotation(Document.class).indexName(),
// TechnologyBlog.class.getAnnotation(TypeAlias.class).value());
// return ResponseEntity.ok(String.join(" ", Boolean.toString(deleteIndex1), Boolean.toString(deleteIndex2),
// Boolean.toString(putMapping1), Boolean.toString(putMapping2), Boolean.toString(addAlias1), Boolean.toString(addAlias2)));
// }
// @PutMapping("/indexAlias")
// public ResponseEntity<Map<String, Set<String>>> indexAlias() {
// Map<String, Set<String>> map = new HashMap<>();
// String index1 = FoodBlog.class.getAnnotation(Document.class).indexName();
// Set<String> alias1 = ElasticsearchIndexOps.getAlias(index1);
// map.put(index1, alias1);
// String index2 = FoodBlog.class.getAnnotation(Document.class).indexName();
// Set<String> alias2 = ElasticsearchIndexOps.getAlias(index2);
// map.put(index2, alias2);
// return ResponseEntity.ok(map);
// }
//
// @PutMapping("/deleteAlias")
// public ResponseEntity<Map<String, Set<String>>> deleteAlias() {
// Map<String, Set<String>> map = new HashMap<>();
// String index1 = FoodBlog.class.getAnnotation(Document.class).indexName();
// Set<String> alias1 = ElasticsearchIndexOps.getAlias(index1);
// ElasticsearchIndexOps.delAlias(index1, alias1.toArray(new String[]{}));
// String index2 = FoodBlog.class.getAnnotation(Document.class).indexName();
// Set<String> alias2 = ElasticsearchIndexOps.getAlias(index2);
// ElasticsearchIndexOps.delAlias(index2, alias2.toArray(new String[]{}));
// return ResponseEntity.ok(map);
// }
}
@Data
class BlogDTO extends AbstractBlog {
}
2 大数据量
项目实战
订单记录 增加字段的一次 迭代升级
v0 版本 createTime ....
需要增加一个支付时间
v1 版本 createTime .... paymentTime
package com.sixkery.entity.es;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.elasticsearch.annotations.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
/**
* @Field(type=FieldType.Text, analyzer=“ik_max_word”) 表示该字段是一个文本,并作最大程度拆分,默认建立索引
* @Field(type=FieldType.Text,index=false) 表示该字段是一个文本,不建立索引
* @Field(type=FieldType.Date) 表示该字段是一个文本,日期类型,默认不建立索引
* @Field(type=FieldType.Long) 表示该字段是一个长整型,默认建立索引
* @Field(type=FieldType.Keyword) 表示该字段内容是一个文本并作为一个整体不可分,默认建立索引
* @Field(type=FieldType.Float) 表示该字段内容是一个浮点类型并作为一个整体不可分,默认建立索引
* <p>
* date 、float、long都是不能够被拆分的
*/
@Data
@Document(indexName = "charge_detail_record", createIndex = false)
@TypeAlias("charge_detail_record_latest")
@Setting(settingPath = "elastic/setting/ChargeDetailRecordBill.json")
public class ChargeDetailRecord {
/**
* <p>订单明细</p>
* 订单号
* 站点名称
* 桩名称
* 枪号
* 成员名称
* 子成员名称
* 充电时长
* 停止原因
* 桩序列号
* 手机号
* 开始时间
* 结束时间
* 总电量
* 总起始值
* 总止示值
* 开始SOC
* 结束SOC
* 实收电费
* 账单金额
* 实收金额
* 折扣金额
* 卡号
* 支付状态
* 备注
*/
public interface OrderView {
}
public interface OrderDetail extends OrderView {
}
public interface InvoiceBill {
}
/**
* 交易明细
* 字段
* <p>
* 订单号
* 站点名称
* 桩名称
* 桩序列号
* 用户名称
* 业务类型
* 业务类型
* 充电量(度)
* 充电时长
* 实收金额
* 支付状态
* 支付方式
* 支付流水号
* 充电开始时间
* 充电结束时间
*/
public interface TradeView {
}
/*↓↓↓↓↓↓↓↓↓↓↓↓CDR表信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
/**
* 账单ID tb_cdr 主键
*/
@Id
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
/**
* Uniquely identifies the CDR within the CPOs platform
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class})
private String uid;
/**
* start timestamp of the charging session.
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private LocalDate startDateTime;
/**
* stop timestamp of the charging session.
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private LocalDate stopDateTime;
/**
* reference to a token, identified by the auth_id field
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
private String authId;
/**
* auth_request,whitelist
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
private String authMethod;
/**
* identification of the meter inside the charge point.
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
private String meterId;
/**
* currency of the cdr in iso 4217 code.
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderDetail.class, InvoiceBill.class})
private String currency;
/**
* Currency 符号
*/
@Field(type = FieldType.Keyword)
@JsonView({TradeView.class, OrderView.class, OrderDetail.class, InvoiceBill.class})
private String currencySymbol;
/**
* total cost (excluding vat)
*/
@Field(type = FieldType.Double)
@JsonView({InvoiceBill.class})
private BigDecimal totalCost;
/**
* 充电量(度)
* total energy charged, in kwh.
*/
@Field(type = FieldType.Double)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private BigDecimal totalEnergy;
/**
* total duration of this session (including the duration
*/
@Field(type = FieldType.Double)
private BigDecimal totalTime;
/**
* total duration during this session that the ev is not
*/
@Field(type = FieldType.Double)
private BigDecimal totalParkingTime;
/**
* optional remark, can be used to provide addition
* 备注
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
@JsonView({OrderView.class})
private String remark;
@Field(type = FieldType.Text, index = false)
@JsonView({OrderView.class})
private String chargingPeriods;
@Field(type = FieldType.Text, index = false)
private String tariffs;
/**
* cdr最后更新时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private LocalDate lastUpdated;
/*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑CDR 表信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/
/*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓充电账单信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓****/
/**
* 账单ID tb_bill 主键
*/
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long billId;
/**
* 收到桩侧开始充电回调信息的时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private LocalDate startCallbackTime;
/**
* 收到桩侧结束充电回调信息的时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private LocalDate stopCallbackTime;
/**
* 订单流水号 与桩交互使用
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderDetail.class, OrderView.class})
private String orderSeq;
/**
* op_location_evse 主键
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long evseId;
/**
* 场站ID locationId 主键
*/
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long locationId;
/**
* 客户(member)
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long memberId;
/**
* 客户(openid)
*/
@Field(type = FieldType.Keyword)
@JsonView({OrderView.class, TradeView.class, InvoiceBill.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long userId;
/**
* 商家id
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long operatorId;
/**
* 卡号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({OrderView.class, TradeView.class})
private String cardNo;
/**
* 订单状态 -1: 启动失败, 0:DEFAULT, 1:启动成功, 2、订单结束 3、异常订单
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer orderStatus;
/**
* 订单类型 0:正常订单, 1、异常订单
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer orderType;
/**
* 订单异常原因
*/
@Field(type = FieldType.Text)
@JsonView({OrderView.class, TradeView.class})
private String errorCause;
/**
* 充电设备Sn码
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String evseSn;
/**
* 订单号
* 订单编码
* 订单编号
* uniquely identifies the cdr within the cpos platform
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String orderNumber;
/**
* 支付方式 1 Stripe; 2 Paypal; 3 Google; 4 Apple; 5 POS机
*/
@Field(type = FieldType.Integer)
@JsonView({TradeView.class, InvoiceBill.class})
private Integer payType;
/**
* 支付状态 0.default 1.待支付, 2.已支付,3.免支付
*/
@Field(type = FieldType.Integer)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private Integer payStatus;
/**
* 支付流水号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class})
private String paySeq;
/**
* POS机流水号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class})
private String posSeq;
/**
* 充电模式(充电策略)
* 充电模式(充电策略) 1,"自动模式" 2,"金额模式" , 3,"时间模式" 4,"电量模式"
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer chargingMode;
/**
* 1:刷卡,2:扫码,3:即插即充,4:POS, 5:OCPI START SESSION , 6:OCPI SWIPE RFID
* 原来的BusType
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer chargingType;
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer businessType;
/**
* 停止原因
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
@JsonView({OrderView.class})
private String stopReason;
/**
* 充电时长毫秒
*/
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class, OrderView.class})
private Long duration;
/**
* 开始soc
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal startSoc;
/**
* 结束soc
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal stopSoc;
/**
* 总起示值
* 总起始值
* wh
*/
@Field(type = FieldType.Long)
@JsonView({OrderDetail.class, TradeView.class, OrderView.class})
private Long startMeterValue;
/**
* 总止示值
* wh
*/
@Field(type = FieldType.Long)
@JsonView({OrderDetail.class, TradeView.class, OrderView.class})
private Long stopMeterValue;
/**
* 总电费(元)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal totalEnergyFee;
/**
* 总电量(Wh)
*/
@Field(type = FieldType.Long)
@JsonView({OrderDetail.class, OrderView.class})
private Long sumPower;
/**
* 实际总电费(元)
*/
@Field(type = FieldType.Double)
@JsonView({TradeView.class, OrderView.class})
private BigDecimal actualTotalEnergyFee;
/**
* 时长费(元)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class})
private BigDecimal timeFee;
/**
* 启动费(元)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class})
private BigDecimal startFee;
/**
* 账单金额(消费金额)
* 账单金额
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal totalAmount;
@Field(type = FieldType.Double, index = false)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal discount;
/**
* 折扣金额
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal discountAmount;
/**
* 免收金额
* freeAmount(免收金额) = totalAmount (账单金额) - paymentAmount(支付金额)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal freeAmount;
/**
* 退款金额
* refundAmount
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal refundAmount;
/**
* 实收金额
*/
@Field(type = FieldType.Double)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private BigDecimal paymentAmount;
@Field(type = FieldType.Boolean)
@JsonView({TradeView.class})
private Boolean invoiced;
/**
* 站点时区
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String timeZone;
/**
* 支付失败原因
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView(TradeView.class)
private String payFailReason;
@Field(type = FieldType.Integer)
private Integer evseType;
/**
* 创建人
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createBy;
/**
* 创建时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private LocalDate createTime;
/**
* 更新人
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long updateBy;
/**
* 更新时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private LocalDate updateTime;
/*↑↑↑↑↑↑↑↑↑↑↑↑上面信息来自账单表↑↑↑↑↑↑↑↑↑↑↑↑↑*/
/*↓↓↓↓↓↓↓↓↓↓冗余字段↓↓↓↓↓↓↓↓↓↓↓*/
/**
* 手机号码
* 用户手机号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, OrderDetail.class})
private String telephone;
/**
* 用户邮箱
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String email;
/**
* 充电用户名称
* 成员名称
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String memberName;
/**
* 站点名称
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String locationName;
/**
* 桩名称
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String pileName;
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String gunNo;
/**
* 桩序列号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, OrderDetail.class})
private String pileSn;
@Field(type = FieldType.Integer)
private Integer year;
@Field(type = FieldType.Integer)
private Integer month;
@Field(type = FieldType.Integer)
private Integer quarter;
@Field(type = FieldType.Text)
private String pileAddress;
@Field(type = FieldType.Boolean)
private Boolean ocpiEnabled = false;
/**
* 充电中的监控
*/
@JsonView({OrderDetail.class})
@Field(type = FieldType.Object, index = false)
private List<Measure> measures = new ArrayList<>();
/*↑↑↑↑↑↑↑↑↑↑↑↑冗余字段↑↑↑↑↑↑↑↑↑↑↑↑↑*/
}
分词器索引
{
"index": {
"max_ngram_diff": "30",
"refresh_interval": "1s",
"number_of_shards": "3",
"store": {
"type": "fs"
},
"analysis": {
"normalizer": {
"lowercase": {
"filter": [
"lowercase"
],
"type": "custom"
}
},
"analyzer": {
"index_analyzer": {
"filter": [
"lowercase"
],
"tokenizer": "my_tokenizer"
},
"search_analyzer": {
"filter": [
"lowercase"
],
"tokenizer": "whitespace"
}
},
"tokenizer": {
"my_tokenizer": {
"token_chars": [
"letter",
"digit",
"punctuation",
"symbol"
],
"min_gram": "1",
"type": "ngram",
"max_gram": "30"
}
}
},
"number_of_replicas": "1"
}
}
v1
package com.sixkery.entity.es;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.elasticsearch.annotations.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
/**
* @Field(type=FieldType.Text, analyzer=“ik_max_word”) 表示该字段是一个文本,并作最大程度拆分,默认建立索引
* @Field(type=FieldType.Text,index=false) 表示该字段是一个文本,不建立索引
* @Field(type=FieldType.Date) 表示该字段是一个文本,日期类型,默认不建立索引
* @Field(type=FieldType.Long) 表示该字段是一个长整型,默认建立索引
* @Field(type=FieldType.Keyword) 表示该字段内容是一个文本并作为一个整体不可分,默认建立索引
* @Field(type=FieldType.Float) 表示该字段内容是一个浮点类型并作为一个整体不可分,默认建立索引
* <p>
* date 、float、long都是不能够被拆分的
*/
@Data
@Document(indexName = "charge_detail_record_v1")
@TypeAlias("charge_detail_record_latest")
@Setting(settingPath = "elastic/setting/ChargeDetailRecordBill.json")
public class ChargeDetailRecord_V1 {
/**
* <p>订单明细</p>
* 订单号
* 站点名称
* 桩名称
* 枪号
* 成员名称
* 子成员名称
* 充电时长
* 停止原因
* 桩序列号
* 手机号
* 开始时间
* 结束时间
* 总电量
* 总起始值
* 总止示值
* 开始SOC
* 结束SOC
* 实收电费
* 账单金额
* 实收金额
* 折扣金额
* 卡号
* 支付状态
* 备注
*/
public interface OrderView {
}
public interface OrderDetail extends OrderView {
}
public interface InvoiceBill {
}
/**
* 交易明细
* 字段
* <p>
* 订单号
* 站点名称
* 桩名称
* 桩序列号
* 用户名称
* 业务类型
* 业务类型
* 充电量(度)
* 充电时长
* 实收金额
* 支付状态
* 支付方式
* 支付流水号
* 充电开始时间
* 充电结束时间
*/
public interface TradeView {
}
/*↓↓↓↓↓↓↓↓↓↓↓↓CDR表信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
/**
* 账单ID tb_cdr 主键
*/
@Id
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
/**
* Uniquely identifies the CDR within the CPOs platform
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class})
private String uid;
/**
* start timestamp of the charging session.
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private Date startDateTime;
/**
* stop timestamp of the charging session.
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private Date stopDateTime;
/**
* reference to a token, identified by the auth_id field
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
private String authId;
/**
* auth_request,whitelist
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
private String authMethod;
/**
* identification of the meter inside the charge point.
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
private String meterId;
/**
* currency of the cdr in iso 4217 code.
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderDetail.class, InvoiceBill.class})
private String currency;
/**
* Currency 符号
*/
@Field(type = FieldType.Keyword)
@JsonView({TradeView.class, OrderView.class, OrderDetail.class, InvoiceBill.class})
private String currencySymbol;
/**
* total cost (excluding vat)
*/
@Field(type = FieldType.Double)
@JsonView({InvoiceBill.class})
private BigDecimal totalCost;
/**
* 充电量(度)
* total energy charged, in kwh.
*/
@Field(type = FieldType.Double)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private BigDecimal totalEnergy;
/**
* total duration of this session (including the duration
*/
@Field(type = FieldType.Double)
private BigDecimal totalTime;
/**
* total duration during this session that the ev is not
*/
@Field(type = FieldType.Double)
private BigDecimal totalParkingTime;
/**
* optional remark, can be used to provide addition
* 备注
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
@JsonView({OrderView.class})
private String remark;
@Field(type = FieldType.Text, index = false)
@JsonView({OrderView.class})
private String chargingPeriods;
@Field(type = FieldType.Text, index = false)
private String tariffs;
/**
* cdr最后更新时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private Date lastUpdated;
/*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑CDR 表信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/
/*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓充电账单信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓****/
/**
* 账单ID tb_bill 主键
*/
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long billId;
/**
* 收到桩侧开始充电回调信息的时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private Date startCallbackTime;
/**
* 收到桩侧结束充电回调信息的时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private Date stopCallbackTime;
/**
* 订单流水号 与桩交互使用
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderDetail.class, OrderView.class})
private String orderSeq;
/**
* op_location_evse 主键
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long evseId;
/**
* 场站ID locationId 主键
*/
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long locationId;
/**
* 客户(member)
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long memberId;
/**
* 客户(openid)
*/
@Field(type = FieldType.Keyword)
@JsonView({OrderView.class, TradeView.class, InvoiceBill.class})
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long userId;
/**
* 商家id
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long operatorId;
/**
* 卡号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({OrderView.class, TradeView.class})
private String cardNo;
/**
* 订单状态 -1: 启动失败, 0:DEFAULT, 1:启动成功, 2、订单结束 3、异常订单
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer orderStatus;
/**
* 订单类型 0:正常订单, 1、异常订单
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer orderType;
/**
* 订单异常原因
*/
@Field(type = FieldType.Text)
@JsonView({OrderView.class, TradeView.class})
private String errorCause;
/**
* 充电设备Sn码
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String evseSn;
/**
* 订单号
* 订单编码
* 订单编号
* uniquely identifies the cdr within the cpos platform
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String orderNumber;
/**
* 支付方式 1 Stripe; 2 Paypal; 3 Google; 4 Apple; 5 POS机
*/
@Field(type = FieldType.Integer)
@JsonView({TradeView.class, InvoiceBill.class})
private Integer payType;
/**
* 支付状态 0.default 1.待支付, 2.已支付,3.免支付
*/
@Field(type = FieldType.Integer)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private Integer payStatus;
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private Date paymentTime;
/**
* 支付流水号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class})
private String paySeq;
/**
* POS机流水号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class})
private String posSeq;
/**
* 充电模式(充电策略)
* 充电模式(充电策略) 1,"自动模式" 2,"金额模式" , 3,"时间模式" 4,"电量模式"
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer chargingMode;
/**
* 1:刷卡,2:扫码,3:即插即充,4:POS, 5:OCPI START SESSION , 6:OCPI SWIPE RFID
* 原来的BusType
*/
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer chargingType;
@Field(type = FieldType.Integer)
@JsonView({OrderView.class, TradeView.class})
private Integer businessType;
/**
* 停止原因
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word")
@JsonView({OrderView.class})
private String stopReason;
/**
* 充电时长毫秒
*/
@Field(type = FieldType.Long)
@JsonView({TradeView.class, OrderView.class, OrderView.class})
private Long duration;
/**
* 开始soc
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal startSoc;
/**
* 结束soc
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal stopSoc;
/**
* 总起示值
* 总起始值
* wh
*/
@Field(type = FieldType.Long)
@JsonView({OrderDetail.class, TradeView.class, OrderView.class})
private Long startMeterValue;
/**
* 总止示值
* wh
*/
@Field(type = FieldType.Long)
@JsonView({OrderDetail.class, TradeView.class, OrderView.class})
private Long stopMeterValue;
/**
* 总电费(元)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal totalEnergyFee;
/**
* 总电量(Wh)
*/
@Field(type = FieldType.Long)
@JsonView({OrderDetail.class, OrderView.class})
private Long sumPower;
/**
* 实际总电费(元)
*/
@Field(type = FieldType.Double)
@JsonView({TradeView.class, OrderView.class})
private BigDecimal actualTotalEnergyFee;
/**
* 时长费(元)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class})
private BigDecimal timeFee;
/**
* 启动费(元)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class})
private BigDecimal startFee;
/**
* 账单金额(消费金额)
* 账单金额
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal totalAmount;
@Field(type = FieldType.Double, index = false)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal discount;
/**
* 折扣金额
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal discountAmount;
/**
* 免收金额
* freeAmount(免收金额) = totalAmount (账单金额) - paymentAmount(支付金额)
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal freeAmount;
/**
* 退款金额
* refundAmount
*/
@Field(type = FieldType.Double)
@JsonView({OrderDetail.class, OrderView.class})
private BigDecimal refundAmount;
/**
* 实收金额
*/
@Field(type = FieldType.Double)
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private BigDecimal paymentAmount;
@Field(type = FieldType.Boolean)
@JsonView({TradeView.class})
private Boolean invoiced;
/**
* 站点时区
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String timeZone;
/**
* 支付失败原因
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView(TradeView.class)
private String payFailReason;
@Field(type = FieldType.Integer)
private Integer evseType;
/**
* 创建人
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createBy;
/**
* 创建时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private Date createTime;
/**
* 更新人
*/
@Field(type = FieldType.Long)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long updateBy;
/**
* 更新时间
*/
@Field(type = FieldType.Date, format = DateFormat.epoch_millis, pattern = "epoch_millis")
private Date updateTime;
/*↑↑↑↑↑↑↑↑↑↑↑↑上面信息来自账单表↑↑↑↑↑↑↑↑↑↑↑↑↑*/
/*↓↓↓↓↓↓↓↓↓↓冗余字段↓↓↓↓↓↓↓↓↓↓↓*/
/**
* 手机号码
* 用户手机号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, OrderDetail.class})
private String telephone;
/**
* 用户邮箱
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String email;
/**
* 充电用户名称
* 成员名称
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String memberName;
/**
* 站点名称
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, InvoiceBill.class})
private String locationName;
/**
* 桩名称
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String pileName;
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class})
private String gunNo;
/**
* 桩序列号
*/
@Field(type = FieldType.Keyword, normalizer = "lowercase")
@JsonView({TradeView.class, OrderView.class, OrderDetail.class})
private String pileSn;
@Field(type = FieldType.Integer)
private Integer year;
@Field(type = FieldType.Integer)
private Integer month;
@Field(type = FieldType.Integer)
private Integer quarter;
@Field(type = FieldType.Text)
private String pileAddress;
@Field(type = FieldType.Boolean)
private Boolean ocpiEnabled = false;
/**
* 充电中的监控
*/
@JsonView({OrderDetail.class})
@Field(type = FieldType.Object, index = false)
private List<Measure> measures = new ArrayList<>();
/*↑↑↑↑↑↑↑↑↑↑↑↑冗余字段↑↑↑↑↑↑↑↑↑↑↑↑↑*/
}
package com.sixkery.controller;
import com.sixkery.entity.es.*;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.index.AliasAction;
import org.springframework.data.elasticsearch.core.index.AliasActionParameters;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.AliasData;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Map;
import java.util.Set;
@RestController
public class ElasticsearchIndexOpsController {
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
/**
* 获取索引对应的别名
*/
@PostMapping("getAliasesForIndex")
public Map<String, Set<AliasData>> getAliasesForIndex(@RequestBody String[] index) {
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(FoodBlog.class);
Map<String, Set<AliasData>> aliasesForIndex = indexOperations.getAliasesForIndex(index);
return aliasesForIndex;
}
@GetMapping("/search")
public ResponseEntity<SearchHits<ChargeDetailRecord_V1>> search() {
IndexCoordinates blog = IndexCoordinates.of(ChargeDetailRecord_V1.class.getAnnotation(TypeAlias.class).value());
Query query = elasticsearchRestTemplate.matchAllQuery();
SearchHits<ChargeDetailRecord_V1> search = elasticsearchRestTemplate.search(query, ChargeDetailRecord_V1.class, blog);
return ResponseEntity.ok(search);
}
/**
* 第一步 创建 new Index
*
* @return
*/
@PostMapping("createIndex")
public Object createIndex() {
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(ChargeDetailRecord.class);
indexOperations.create();
return indexOperations.putMapping();
}
/**
* 第二步迁移数据 old index -> new Index
*
* @return
*/
@PostMapping("reindex")
public ResponseEntity<ReindexResponse> reindex() {
IndexCoordinates sourceIndex = elasticsearchRestTemplate.indexOps(ChargeDetailRecord.class).getIndexCoordinates();
IndexCoordinates destIndex = elasticsearchRestTemplate.indexOps(ChargeDetailRecord_V1.class).getIndexCoordinates();
ReindexRequest.ReindexRequestBuilder builder = ReindexRequest.builder(sourceIndex, destIndex);
ReindexResponse reindexResponse = elasticsearchRestTemplate.reindex(builder.build());
return ResponseEntity.ok(reindexResponse);
}
/**
* 第三步 add alias to new Index
*
* @return
*/
@PostMapping("/alias")
public ResponseEntity<Object> addAlias() {
AliasActions aliasActions = new AliasActions();
AliasActionParameters.Builder builder = AliasActionParameters.builder();
builder.withAliases(ChargeDetailRecord_V1.class.getAnnotation(TypeAlias.class).value());
builder.withIndices(ChargeDetailRecord_V1.class.getAnnotation(Document.class).indexName());
AliasAction aliasAction = new AliasAction.Add(builder.build());
aliasActions.add(aliasAction);
return ResponseEntity.ok(elasticsearchRestTemplate.indexOps(ChargeDetailRecord_V1.class).alias(aliasActions));
}
/**
* 第四步 remove alias on old index
*
* @return
*/
@DeleteMapping("/alias")
public ResponseEntity<Object> removeAlias() {
AliasActions aliasActions = new AliasActions();
AliasActionParameters.Builder builder = AliasActionParameters.builder();
builder.withAliases(ChargeDetailRecord.class.getAnnotation(TypeAlias.class).value());
builder.withIndices(ChargeDetailRecord.class.getAnnotation(Document.class).indexName());
AliasAction aliasAction = new AliasAction.Remove(builder.build());
aliasActions.add(aliasAction);
return ResponseEntity.ok(elasticsearchRestTemplate.indexOps(ChargeDetailRecord.class).alias(aliasActions));
}
/**
* 第五步 delete old index
*
* @return
*/
@DeleteMapping("/index")
public ResponseEntity<Object> deleteIndex() {
return ResponseEntity.ok(elasticsearchRestTemplate.indexOps(ChargeDetailRecord.class).delete());
}
}