elasticsearch学习系列:开发springboot程序进行定时删除过期索引

场景

项目使用了elasticsearch技术来进行数据搜索,而单天的数据量比较大,随着时间的流逝,整个elasticsearch集群所占的空间会越来越大。如果不进行定时的删除,就会导致存储满载,进而影响系统。而elasticsearch支持使用curl命令调用elasticsearch集群命令,定时删除某一天的索引数据。但是没有办法删除某个时间点之前的数据。那么假如有一天脚本没有执行,那没有执行的日期数据就没办法删除,只能手动去删除。这样还是会存在问题的。这个时候,就需要有一个程序,可以自定义对某个索引进行扫描,删除自定义天数的数据。这样,不管什么时候执行,都会将保留周期之外的索引数据给删除掉。

环境

软件版本
JDK8
spring-data-elasticsearch3.1.10.RELEASE
spring-boot2.1.8.RELEASE
elasticsearch6.2.2

正文

流程梳理

接下来,让我们梳理一下整个程序的开发流程,如下:

Created with Raphaël 2.2.0 开始 初始化ElasticSearch组件 获取配置数据 获取全部索引 从全部索引中,筛选出过期的索引数据 删除过期的索引数据 结束

show the code

对于程序员来说,除了理论要溜,代码也得溜。所以,接下来会展示整个过程有用的代码。

maven依赖

这里只展示主要的依赖,像微服务Spring-cloud相关的依赖就不放在里面了。


 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.1.8.RELEASE</version>
 </parent>
 
 <dependencies>
	 <!-- elasticsearch -->
	 <dependency>
	     <groupId>org.springframework.boot</groupId>
	     <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
	 </dependency>
</dependencies>

配置文件

配置文件主要是写在application.properties文件里面,下面展示一个样例:

# es配置
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.elasticsearch.cluster-name=test
# 过期索引配置,值为天数
index.delindex.service-test=7
index.delindex.service-test2=7

主要函数

配置类

@Component
@Configuration
@PropertySource(value = {"classpath:/application.properties"}, encoding = "utf-8")
@ConfigurationProperties(prefix = "index")
@Getter
@Setter
public class ElasticsearchDelIndexConfig {
    private Map delindex = new HashMap();
}

处理类

因为功能比较简单,所以是直接将代码放到主类里面,直接跑的。代码如下,如果有需求,直接复制就可以跑起来的。

@Slf4j
@EnableEurekaClient
@SpringBootApplication
public class ElasticsearchDelApplication implements CommandLineRunner {

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Autowired
    private ElasticsearchDelIndexConfig delIndexConfig;

    /**
     * 主进程
     *
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(ElasticsearchDelApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        while (true) {
            delIndexConfig.getDelindex().forEach((k, v) -> {
                log.info("索引起始名称为{},保留周期为{}天", k, v);
                Set<String> allIndexes = getAllIndices();
                if (allIndexes.size() > 0) {
                    log.info("当前索引总数为:{}", allIndexes.size());

                    List<String> timeoutList = getIndicesTimeout(allIndexes, String.valueOf(k), Long.parseLong(String.valueOf(v)), TimeUnit.DAYS);
                    if (timeoutList.size() > 0) {
                        log.info("对于前缀为 {} 的索引 过期数目为:{}", k, timeoutList.size());
                        timeoutList.forEach(indexName -> {
                            if (elasticsearchTemplate.deleteIndex(indexName)) {
                                log.info("成功删除 {} 索引", indexName);
                            } else {
                                log.error("删除 {} 索引 失败", indexName);
                            }
                        });
                    }
                }
            });
            log.info("休眠 10 分钟");
            ThreadUtil.sleep(10, TimeUnit.MINUTES);
        }
    }

    /**
     * 获取所有index
     */
    public Set<String> getAllIndices() {
        ActionFuture<IndicesStatsResponse> isr = elasticsearchTemplate.getClient().admin().indices().stats(new IndicesStatsRequest().all());
        Set<String> set = isr.actionGet().getIndices().keySet();
        return set;
    }


    /**
     * 获取指定索引的创建时间
     * @param indexName 索引名称
     * @return 索引的创建时间
     */
    public String getCreateTimeForIndex(String indexName) {
        String createTime = elasticsearchTemplate.getClient().admin()
                .indices().getSettings(new GetSettingsRequest().indices(indexName))
                .actionGet().getIndexToSettings().get(indexName)
                .getAsSettings("index").get("creation_date");
        return createTime;
    }

    /**
     * 获取前缀相同的过时索引
     * @param allIndices 索引列表
     * @param indexName 要过滤的索引前缀
     * @param time 超时时间
     * @param timeUnit 时间单位
     * @return 超时的索引列表
     */
    public List<String> getIndicesTimeout(Set<String> allIndices, String indexName, Long time, TimeUnit timeUnit) {
        List<String> list = new ArrayList<>();
        allIndices.parallelStream()
                .filter(name -> name.startsWith(indexName))
                .forEach(one -> {
                    String createTime = getCreateTimeForIndex(one);
                    if (System.currentTimeMillis() - Long.parseLong(createTime) > timeUnit.toMillis(time)) {
                        log.info("索引 {} 已经过期,创建时间为{}", one, createTime);
                        list.add(one);
                    }
                });
        return list;
    }
}

结果

程序跑起来之后,elasticsearch集群的特定索引的过期数据都会被删除。

总结

spring-boot可以封装了很多开发细节,减少了我们很多工作。在懂得内部原理的时候,的确很好用。不过对于初学者,在使用spring-boot的时候,记得学习里面内部的原理。这样遇到问题才能快速锁定问题,并解决。

随缘求赞

如果我的文章对大家产生了帮忙,可以在文章底部点个赞或者收藏;
如果有好的讨论,可以留言;
如果想继续查看我以后的文章,可以点击关注
可以扫描以下二维码,关注我的公众号:枫夜之求索阁,查看我最新的分享!
在这里插入图片描述
拜拜

posted on 2022-11-29 18:40  枫夜求索阁  阅读(135)  评论(0)    收藏  举报

导航