背景
社内では既にElasticsearchを取り入れていましたが、運用においていくつか不便な点がありました。
既存index運用方法
- ある用途に特化したindexを作成
- 初期データをインポート
- 追加発生 => インポート
- 更新発生 => インポート
- 削除発生 => 削除タスクの生成と実行
問題点
更新する場合は問題がありませんが、インポート対象が削除されていた場合は別途削除する為に削除リクエストをElasticsearchに送信する必要があります。
そのために発生したのが下記のようなもの。
- 削除条件が増えるたびに専用の削除用rakeタスクができた。
- インポートしてから削除するといった運用手順が生まれる。
- 削除用rakeタスクのメンテ忘れによる、必要データが消えてしまう事件発生。
- 不要なデータが残り続ける。
またindexの定義を更新または刷新したい時にAPI側はindex名を直指定しているため、容易に切り替えたり更新することができません。
新規index運用方法
新規運用方法といっても大したものではないですが、既存の問題を解決する為に alias を参照する用に変更して、裏に紐づくindexを切り替えるという方法を導入しました。
これにより、データを刷新したものに切り替えができるため削除用のタスクが不要になり、indexの定義更新等も容易になります。
例
下記を一つのタスクとすることで、シンプルな運用とする。
- index作成
- データのインポート
- alias切替
- 旧indexの削除
※更新の場合はインポートのみを実行
elastic/elasticsearch-rubyを利用してます。
※例なので、省略などを行なっておりそのまま実行はできません。
def create
# indexの定義を読み込む
json = open(file_path) { |io| JSON.load(io) }
# suffixにタイムスタンプを設定
timestamp = Time.now.strftime('%Y%m%d%H%M%S')
index_name = "#{alias_name}_#{timestamp}"
# indexを作成
client.indices.create index: index_name, body: json
# 必要なデータのインポート
client.bulk body: data
# alias切り替え
switch_alias(index: index_name)
end
def switch_alias(index:)
# aliasに紐づいた古いindexを取得
old_indices = client.indices.get_alias(name: alias_name).keys
# alias削除リクエスト作成
for_remove = old_indices.map { |old_index| { remove: { index: old_index, alias: alias_name } } }
# alias追加リクエストを追加
actions = for_remove + [{ add: { index: index, alias: alias_name } }]
# リクエスト実行
client.indices.update_aliases body: { actions: actions }
# aliasに紐づいた古いindexを削除
client.indices.delete index: old_indices
end