AWS CloudSearchで映画データの全文検索を行う
公開されている映画データセットをAWS CloudSearchにインデックスし、全文検索・数値検索・範囲検索を実行します。
AWS CloudSearchを使えば、別途検索クラスタを構築しなくても、映画データセットをインデックスして全文検索を行うことができます。
CloudSearchドメインのセットアップ
CloudSearchドメインを作成します。
aws cloudsearch create-domain \ --domain-name searching-movies-data公式ドキュメントによると、CloudSearchドメインの作成には通常およそ10分かかります。
ドメインの作成状況は以下のコマンドで確認できます。
aws cloudsearch describe-domains \ --domain-name searching-movies-dataコマンドの出力でProcessing: falseと表示されれば、ドメインとそのエンドポイントの作成が完了し、利用可能になったことを示します。
{ "DomainStatusList": [ { "DomainId": "123456789012/searching-movies-data", "DomainName": "searching-movies-data", "ARN": "arn:aws:cloudsearch:ap-northeast-1:123456789012:domain/searching-movies-data", "Created": true, "Deleted": false, "DocService": { "Endpoint": "doc-searching-movies-data-xxxxxxxxxx.ap-northeast-1.cloudsearch.amazonaws.com" }, "SearchService": { "Endpoint": "search-searching-movies-data-xxxxxxxxxx.ap-northeast-1.cloudsearch.amazonaws.com" }, "RequiresIndexDocuments": false, "Processing": false, "SearchInstanceType": "search.small", "SearchPartitionCount": 1, "SearchInstanceCount": 1, "Limits": { "MaximumReplicationCount": 5, "MaximumPartitionCount": 10 } } ]}セキュリティを強化するため、自分のIPアドレスからのみアクセスを許可するようにドメインのアクセスポリシーを更新します。
aws cloudsearch update-service-access-policies \ --domain-name searching-movies-data \ --access-policies ' { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": "*", "Action": ["cloudsearch:*"], "Condition": {"IpAddress": {"aws:SourceIp": "xxx.xxx.xxx.xxx/32"}} } ] }'インデックスフィールドの設定
データセットの構造に合わせてインデックスフィールドを定義します。この例ではKaggleが提供するThe Movies Dataset(CC0: Public Domain)を使用します。以下はインデックスフィールドを定義するコマンドの例です。
aws cloudsearch define-index-field \ --domain-name searching-movies-data --name adult --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name belongs_to_collection --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name budget --type doubleaws cloudsearch define-index-field \ --domain-name searching-movies-data --name genres --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name homepage --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name id --type intaws cloudsearch define-index-field \ --domain-name searching-movies-data --name imdb_id --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name original_language --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name original_title --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name overview --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name popularity --type doubleaws cloudsearch define-index-field \ --domain-name searching-movies-data --name poster_path --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name production_companies --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name production_countries --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name release_date --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name revenue --type intaws cloudsearch define-index-field \ --domain-name searching-movies-data --name runtime --type doubleaws cloudsearch define-index-field \ --domain-name searching-movies-data --name spoken_languages --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name status --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name tagline --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name title --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name video --type textaws cloudsearch define-index-field \ --domain-name searching-movies-data --name vote_average --type doubleaws cloudsearch define-index-field \ --domain-name searching-movies-data --name vote_count --type int設定が完了したら、検索ドメインにドキュメントのインデックス作成を開始するよう指示します。
aws cloudsearch index-documents \ --domain-name searching-movies-dataデータセットのインデックス作成
Kaggleからデータセットをダウンロードし、先頭1,000行からなるサンプルファイルを用意します。
head -1000 movies_metadata.csv > sample.csvCloudSearchはコンソール画面からCSVファイルを直接インデックスできますが、AWS CLIのaws cloudsearchdomain upload-documentsコマンドはJSONまたはXML形式のみを受け付けます。
Actions > Upload documentsに移動します。

CSVファイルを選択し、Nextをクリックします。

検出されたフィールドを確認し、Upload documentsをクリックします。


処理が完了すると、(ヘッダーを除く)998件のレコードが正常にインデックスされたことを確認できます。

クエリの実行
テキスト検索
titleフィールドとoverviewフィールドに対して、キーワードhouseで映画を検索します。
curl --location \ -g \ --request GET \ 'https://search-searching-movies-data-xxxxxxxxxx.ap-northeast-1.cloudsearch.amazonaws.com/2013-01-01/search?q=house&q.options={fields:["title","overview"]}&return=title,overview' | jq .レスポンスには、以下のようなマッチした結果が含まれます。
{ "status": { "rid": "8fDJv8swsgEK1DyD", "time-ms": 1 }, "hits": { "found": 26, "start": 0, "hit": [ { "id": "local_file_466", "fields": { "overview": "Hip Hop duo Kid & Play return...", "title": "House Party 3" } }, ... ] }}詳細については公式ドキュメントを参照してください。
数値検索
数値検索の例として、vote_averageが5.0の映画を検索します。
curl --location --request GET 'https://search-searching-movies-data-xxxxxxxxxx.ap-northeast-1.cloudsearch.amazonaws.com/2013-01-01/search?q.parser=structured&q=vote_average:5.0&return=title,overview' | jq .レスポンスには、以下のようなマッチした結果が含まれます。
{ "status": { "rid": "w+Xgv8swwQEK1DyD", "time-ms": 0 }, "hits": { "found": 35, "start": 0, "hit": [ { "id": "local_file_144", "fields": { "overview": "Far from home...", "title": "The Amazing Panda Adventure" } }, ... ] }}詳細については公式ドキュメントを参照してください。
範囲検索
vote_averageが7.0より大きい映画を検索します。
curl --location \ -g \ --request GET \ 'https://search-searching-movies-data-xxxxxxxxxx.ap-northeast-1.cloudsearch.amazonaws.com/2013-01-01/search?q.parser=structured&q=vote_average:[7.0,}&return=title,overview' | jq .レスポンスには、以下のようなマッチした結果が含まれます。
{ "status": { "rid": "vJ/vv8swyAEK1DyD", "time-ms": 2 }, "hits": { "found": 254, "start": 0, "hit": [ { "id": "local_file_1", "fields": { "overview": "Led by Woody, Andy's toys...", "title": "Toy Story" } }, ... ] }}詳細については公式ドキュメントを参照してください。
クリーンアップ
作業が終わったらドメインを削除します。
aws cloudsearch delete-domain \ --domain-name searching-movies-dataまとめ
公開されている映画データセットの998行をAWS CloudSearchにインデックスしてクエリを実行したところ、別途検索クラスタを管理することなく、同一ドメイン上で全文検索と数値検索の両方が機能することを確認できました。q=houseのようなクエリと、q.parser=structured&q=vote_average:[7.0,}のような構造化パーサーを切り替えるだけで、追加の設定なしに全文検索と数値範囲検索の両方をカバーできる点が、CloudSearchの便利なところです。CloudSearchのエンドポイントはデフォルトでパブリックインターネットからアクセス可能なため、update-service-access-policiesを使ってドメインのアクセスポリシーを特定のaws:SourceIpに制限する作業は、ドメイン作成直後に行っておく価値があります。ドメイン作成に約10分かかる点も、より大きなセットアップ手順の一部としてスクリプト化する場合には考慮しておくべきでしょう。
Related posts
Cognito User PoolsとOIDCでSlackサインインを実装する
Cognito user poolをOIDC経由でSlackと連携させ、"Sign in with Slack"をAmplifyでNext.jsアプリに組み込みます。
Lambda Web AdapterでFastAPIをAWS Lambdaにデプロイする
Lambda Web Adapterを使うと、FastAPIで書いたAPIバックエンドをコンテナのまま単一のLambda関数にデプロイできます。
API Gateway WebSocket:モック統合の実装
バックエンドのLambdaを一切使わず、モック統合のみでAPI Gateway WebSocket APIを構築し、あらかじめ用意されたレスポンスを返します。
CloudFront署名付きURL経由でS3にアップロードする
CloudFrontの署名付きURLを使えば、独自ドメイン経由でS3にアップロードできます。S3の直接の署名付きURLが使えない場合に有用です。
AWS EventBridge Scheduler:スケジュールに沿ってEC2を起動・停止する
Lambdaを介さずEventBridge SchedulerがEC2 APIを直接呼び出すことで、cronスケジュールに従ってEC2インスタンスを起動・停止します。
