はじめに
SpringData Elasticsearch
を利用していて、日毎にドキュメントの全件洗い替えを行いたかった。
その手段を考えた時に、エイリアス機能が使えないかと目星をつけ、実際に洗い替えが実現できたので作業ログを公開します。
概要
インデックスの洗い替えを考える。
現在日付を 01/11
とする時を想定。
- A. Index-01/10 (バックアップ)
- B. Index-01/11 (利用中)
- C. Index-01/12 (今から作成する)
のように考える。
01/12 00:00
以降に定時バッチを起動する。
-
C. Index-01/12
の名称でインデックスを生成する - RDBからインデックスしたいレコードを検索する
論理削除された情報は絞り込みで除外する -
C.
にインデックスしたいドキュメント(2.の内容)を追加する
正常系:
- エイリアスに
C.
を追加する - エイリアスから
B.
を削除する -
A.
を物理削除する
異常系:
- エラーを出力する
-
C. Index-01/12
を削除する
試した環境
ツール/ライブラリ | バージョン |
---|---|
Elasticsearch | 7.16.2 |
SpringData Elasticsearch | 4.4.0-SNAPSHOT |
SpringBoot | 2.7.0-SNAPSHOT |
実装
DTO
LocationDocument
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.TypeAlias;
import org.springframework.data.elasticsearch.annotations.Document;
@TypeAlias("location")
@Document(indexName = "location-#{T(java.time.LocalDate).now().toString()}", createIndex = false)
public class LocationDocument extends BaseDocument<String> {
public static final String ALIAS = "location";
public static final String INDEX_NAME = "location-{yyyy-MM-dd}";
@Id
private String id;
}
@TypeAlias
のおかげで、 location
という名前でアクセスできるインデックスが作成される。実態は location-2022-01-10
のような形式である。
エイリアス貼り替え
LocationRepositoryImpl
import lombok.RequiredArgsConstructor;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
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.stereotype.Repository;
@Repository
@RequiredArgsConstructor
public class LocationRepositoryImpl implements LocationRepository {
private final LocationDocumentSource locationDocumentSource;
private final LocationTableSource locationTableSource;
private final ReactiveElasticsearchOperations elasticsearchOperations;
@Override
public void replacement(Instant receptionTime) {
var today = LocalDate.now();
var newIndexName = LocationDocument.INDEX_NAME
.replace("{yyyy-MM-dd}", today.toString());
var oldIndexName = LocationDocument.INDEX_NAME
.replace("{yyyy-MM-dd}", today.minusDays(1L).toString());
// index作成
var indexOperations = this.elasticsearchOperations.indexOps(LocationDocument.class);
indexOperations.create().block();
// 直す
var count = this.locationTableSource.findAll()
.filter(BaseTable::isExists)
.map(LocationTable::toEntity)
.map(new LocationDocument()::attach)
.flatMap(dto -> this.locationDocumentSource.insert(dto, receptionTime))
.count()
.block();
indexOperations.alias(
new AliasActions()
.add(
// Aliasに新しいindexを追加する
new AliasAction.Add(
AliasActionParameters.builder()
.withIndices(newIndexName)
.withAliases(LocationDocument.ALIAS)
.build()
)
)
.add(
// Aliasから古いindexを削除する
new AliasAction.Remove(
AliasActionParameters.builder()
.withIndices(oldIndexName)
.withAliases(LocationDocument.ALIAS)
.build()
)
)
)
.block();
}
}
説明
-
ReactiveElasticsearchOperations
orElasticsearchOperations
をDIしておく -
AliasActions
でエイリアスの操作を指定する
エイリアスにC.
を追加する
エイリアスからB.
を削除する -
ReactiveElasticsearchOperations
orElasticsearchOperations
からReactiveIndexOperations
orIndexOperations
を生成する -
ReactiveIndexOperations.alias()
orIndexOperations.alias()
にAliasActions
を指定する
日毎に洗い替えを行いたい場合、日付が変わった後にバッチなどで洗い替え処理を行えばよい。