在项目中遇到一个需求,要对es进行动态存储,按月来存储,按月来查询。在网上找了一圈没一个靠谱的,然后自己琢磨搞出来的
本项目是一个SpringBoot的单体架构,具体配置就不讲了,直接上代码
1.首先创建用于切换数据源的bean
package com.aaa.config;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
* 坐标点动态索引名
*
* @author handsome
*/
@Component(value = "EsConfigBean")
public class EsConfigBean {
private static String indexName;
public static String getIndexName() {
return indexName;
}
public static void setIndexName(String name, LocalDate date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM");
EsConfigBean.indexName = name + "_" + date.format(formatter);
}
}
2.然后是将bean所生成的索引名放在要存储的索引上,记住一定要注意写法,并且一定要加上createIndex = false,这样启动项目的时候才不会自动去es里创建这个索引,你也可以试试不加,看看项目启动效果,嘻嘻嘻。
package com.aaa.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import org.elasticsearch.common.geo.GeoPoint;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.annotations.Setting;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
/**
* 工程师索引
*
* @author handsome
*/
@Getter
@Setter
@Document(indexName = "#{@EsConfigBean.indexName}", createIndex = false)
@Setting(replicas = 0)
public class PointEntity {
/**
* 工程师坐标点id
*/
@Id
private String id;
3.最最最重要的一步,写好了,我们该在什么地方切换呢并存储数据呢?
package com.aaa.service.impl;
import com.aaa.config.EsConfigBean;
import com.aaa.entity.PointEntity;
import com.aaa.service.DocumentIndexService;
import lombok.AllArgsConstructor;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
/**
* @author handsome
*/
@Service
@AllArgsConstructor
public class DocumentIndexServiceImpl implements DocumentIndexService {
private final ElasticsearchRestTemplate restTemplate;
@Override
public void switchExistsIndex(String indexName, LocalDate localDate) {
EsConfigBean.setIndexName(indexName, localDate);
boolean exists = restTemplate.indexOps(IndexCoordinates.of(EsConfigBean.getIndexName())).exists();
if (!exists) {
IndexOperations indexOps = restTemplate.indexOps(PointEntity.class);
indexOps.createWithMapping();
}
}
}
我是把切换索引这个操作放在一个service里面,方便其他service要用的时候,直接调用就可以啦。
讲一下这儿的逻辑,方便大家理解,其实也很简单啦。
传入索引名,再传入一个日期,然后setIndexName,再去根据这个IndexName去查询es里有没有这个索引,然后进行判断,如果没有,进入下一步逻辑,为PointEntity类创建一个索引,一定要用ceateWithMapping()这个方法,不然创建出来的索引没有映射。
这里有ElasticsearchRestTemplate和ElasticsearchTemplate两种选择,其实都可以用ET,但我们项目不允许用过时的方法 【吐血】,新版本的SpringDataES一般就用的ERT。
4.最后就是使用了,太多引用了,这儿就不放出来了。
package com.aaa.service.impl;
/**
* @author handsome
*/
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class PointServiceImpl implements PointService {
private static final Logger LOGGER = LoggerFactory.getLogger(PointServiceImpl.class);
private final PointRepo pointRepo;
private final DocumentIndexService indexService;
@Override
public PointEntity savePoint(PointEntity pointEntity) {
indexService.switchExistsIndex(IndexNameEnum.POINT_INDEX.getIndexName(), pointEntity.getCollectTime().toLocalDate());
return pointRepo.save(pointEntity);
}
}
这儿的逻辑很简单了吧,切换索引,然后用数据层进行存储,就完成啦。
这样做可以达到按月建索引的目的,但有个缺陷,不能分月查询数据,比如我要查询6月到8月的数据,切换索引的操作就很繁琐。
5.最终的效果
只能透露这么多啦!!!
各位大佬们,有什么问题可以在评论区讨论哦。