😊 @ 作者: 召田最帅boy
💖 @ 主页: https://www.hqxiaozou.top
🎉 @ 主题: SpringBoot+Elasticsearch按日期实现动态创建索引
⏱️ @ 创作时间: 2023年02月21日
前言
SpringBoot+Elasticsearch,通过@Document注解,利用EL表达式指定到配置文件,实现动态生成IndexName值,比如:
@Document(indexName = "product_#{@esIndex}")
创建动态索引配置文件
在配置文件中按照
yyyy_MM_dd格式返回索引值的后缀,并且通过定时任务对索引值实现更新操作,定时任务是通过重建Bean对象实现对esIndex值进行更新。重建Bean原因:Bean默认只有在服务启动时加载,若需动态改变Bean就要先销毁这个Bean之后再重新加载。
@Configuration
public class EsIndexConfig {
@Resource
private ApplicationContext applicationContext;
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Bean(name = "esIndex")
public static String esIndex() {
// 此处模拟按日期创建索引
// 由于方便测试,索引直接返回时间戳,作为索引名称,时间可以为yyyy-MM-dd
SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd");
String date = sdf.format(new Date());
System.out.println(date);
date = System.currentTimeMillis() / 1000 + "";
System.out.println("date:" + date);
return date;
}
// 每天0点
@Scheduled(cron = "0 0 0 * * ?")
public void updateEsIndex() {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
// 销毁指定实例
defaultListableBeanFactory.destroySingleton("esIndex");
String index = EsIndexConfig.esIndex();
// 重新注册
defaultListableBeanFactory.registerSingleton("esIndex", index);
// 对索引进行一次手动创建(因为自动创建会丢失shards参数)
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(ProductEntity.class);
if (!indexOperations.exists()) {
indexOperations.create();
}
}
}
其他做法:
也可以不通过定时任务更新索引值,可以在操作save方法前,判断索引是否存在,如果不存在再进行重建Bean更新索引值,如下实例:
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(ProductEntity.class);
if (!indexOperations.exists()) {
索引不存在,则重建Bean更新索引值
}
创建实体
创建的实体类,需要关闭自动创建index属性(
createIndex = false),通过配置文件来创建索引值,原因:如果开启自动索引,在项目启动时的第一个索引会完整创建成功,但是后续通过定时任务创建的索引会缺失配置的shards、replicas参数;
@Document(indexName = "product_#{@esIndex}", createIndex = false, shards = 3, replicas = 2)
@Data
public class ProductEntity implements Serializable {
@Id
private String id;
/**
* 文本类型,使用ik分词器
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String name;
/**
* 价格
*/
@Field(type = FieldType.Double)
private BigDecimal money;
/**
* 时间戳
*/
@Field(type = FieldType.Long)
private Long time;
/**
* 颜色
*/
@Field(type = FieldType.Keyword)
private String color;
}
Repository对象
public interface ProductRepository extends ElasticsearchRepository<ProductEntity, String> {
}
Controller对象
测试时,可以将索引动态更新的
定时任务时间设置为一分钟,并且返回的索引值由yyyy_MM_dd修改为一个随机数;调用save方法后,过一分钟后再次进行调用,通过head/kibana观察是否生成了新的索引。
@RestController
@RequestMapping("es")
@Slf4j
public class ProductController {
@Resource
private ProductRepository productRepository;
@PostMapping
public void save() {
String[] colors = {"red", "purple", "blue"};
String[] name = {"手机", "电脑", "微波炉", "电视"};
// 新增列表数据
List<ProductEntity> testList = new ArrayList<>();
long sys = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
// 模拟随机数
double random = Math.random() * 1000;
ProductEntity productEntity = new ProductEntity();
productEntity.setId(i + "");
productEntity.setName(name[i % 4]);
productEntity.setMoney(new BigDecimal(random));
productEntity.setTime(sys + i % 3);
productEntity.setColor(colors[i % 3]);
testList.add(productEntity);
}
// 新增成功后,在head或者kibana中就可以看到相应数据,如果save时数据Id存在则更新操作
// 批量新增
productRepository.saveAll(testList);
// 单个新增
ProductEntity productEntity = testList.get(9);
productEntity.setId("11");
productRepository.save(productEntity);
}
}

评论区 0