LoginSignup
1
2

More than 5 years have passed since last update.

Cloud Searchのドキュメントを全削除するためにドメインを削除・再作成するRubyスクリプト

Last updated at Posted at 2016-12-27

自社サイトのURLとキーワードのマッチングする必要する必要があり、フルマネージドで簡単に使える検索エンジンであるAWS CloudSearchを利用しています。

APIとして簡単に利用できる上、負荷に応じてオートスケールしてくれるため、「簡単に検索ドメインを作りたいし運用で楽したい」という要件にピッタリでした。

ところが、新しい地名が削除・追加されるたびに、必要な自社サイトのURLのリストも少しずつ変わってしまいます。そのため、それほど頻繁ではないものの、「定期的にドキュメントを全削除して入れ直す」という処理が必要でした。

しかし、公式ドキュメントを確認したところ、ドメイン内すべてのドキュメントを削除するAPIは用意されていません。

Amazon CloudSearch ドメイン内のすべてのドキュメントの削除

Amazon CloudSearch には現在、ドメイン内のすべてのドキュメントを削除するメカニズムが用意されていません。

ドメインを削除・再作成するRubyスクリプト

そこで、一度ドメイン自体を全削除して再作成することにしました。

いろいろ試行錯誤した結果、以下のようなメソッドを用意したクラスを作りました。Lib::CloudSearchは、Rubyのaws-sdkライブラリのAws::CloudSearch::Clientの同名のメソッドに、通信が失敗した場合の再接続処理を若干付け足したものです。

# CloudSearchの指定のドメインを削除し、作成しなおす
# (この後ドキュメントをアップロードする別のプログラムが動く)
def rebuild_domain
  _recreate_domain
  Lib::CloudSearch.define_index_fields(@domain, @index_fields)
  Lib::CloudSearch.update_service_access_policies(@domain, _access_policies)
  _wait_until_indexing # もしドキュメントのアップロードの処理が必要なら
end

private

# ドメインを一度削除し、再び作成する
def _recreate_domain
  Lib::CloudSearch.delete_domain(@domain)
  loop do
    resp = Lib::CloudSearch.create_domain(@domain)
    break unless resp.domain_status.deleted
    sleep(60)
  end
end

# インデックスが終わるまで待つ
def _wait_until_indexing
  loop do
    resp = Lib::CloudSearch.describe_domains([@domain])                                                   
    domain_status = resp.domain_status_list[0]
    break unless domain_status.processing || domain_status.doc_service.endpoint.nil?
    sleep(60)
  end
end

# アクセスポリシーのファイルを読み込んで文字列として返す
# @return [String] アクセスポリシーのJSON文字列
def _access_policies
  # 省略
end

ドメインの削除完了を待つ処理

# ドメインを一度削除し、再び作成する
# (この後)
def _recreate_domain
  Lib::CloudSearch.delete_domain(@domain)
  loop do
    resp = Lib::CloudSearch.create_domain(@domain)
    break unless resp.domain_status.deleted
    sleep(60)
  end
end

ちなみに、delete_domaincreate_domainは、削除中や存在しない状態でもエラーを出さずに動作します。そのため、「最初に立ち上げる」場合でも問題なく処理が行われます。

最初、describe_domainsを使ってレスポンスの中のdomain_status_listが空になるかで判断していたのですが、

resp = Lib::CloudSearch.describe_domains([@domain])                                                   
Lib::CloudSearch.create_domain(@domain) if resp.domain_status_list.empty?

空になった後でも、しばらく削除中のドメインが存在している状態で、create_domainがきちんと動作しませんでした。

インデックスが終わるまで待つ処理

# インデックスが終わるまで待つ
def _wait_until_indexing
  loop do
    resp = Lib::CloudSearch.describe_domains([@domain])                                                   
    domain_status = resp.domain_status_list[0]
    break unless domain_status.processing || domain_status.doc_service.endpoint.nil?
    sleep(60)
  end
end

こちらも試行錯誤しており、当初はdomain_status.processing(ドメインが処理中かどうか)のみで判定していたのですが、それだけでは後続のドキュメントのアップロードの実装でエラーが出てしまい、不十分でした。

具体的には「ドキュメント用のAPIのエンドポイントを調べて、そのエンドポイントのドキュメントアップロードAPIを叩く」という処理で、「ドキュメント用のエンドポイントが見つからない」ことが原因のエラーが出たため、domain_status.doc_service.endpoint.nil?で判定しています。

domain_status.doc_serviceではドメインが準備できた場合はエンドポイントの文字列が、無効な場合はnilが返されます。)

…正直、このあたりの実装は自分でも微妙に思うので、もっと良い判定方法を見落としているかもしれません…。

まとめ

ひとまず、Cloud Searchのドキュメントを全削除するためのプログラムを書き、定期的なドメインを作り直す作業を自動化することができました。

作り直すために30分~1時間程度の時間がかかるため、要件によってはドメインを作り直さずに、ドキュメントを削除する処理をループさせるなどの方法を取ったほうがいいかもしれません。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2