Amazon Personalizeを導入してわかった12のこと

# はじめに
私の所属しているエイチームグループでは「サイマ」という自転車のECサイトを運営しているのですが、先日レコメンデーションエンジンとしてAmazon Personalizeを導入しました。サービスに導入しようとすると少し触っただけではわからなかったことが見えてきたので、Amazon Personalizeを導入する過程でわかったことをつらつらと書きだしてみました。
この記事を読む前提知識として、Amazon Personalizeの全体像を把握していたほうが良いです。Amazon Web Servicesブログの以下の記事が図解もあって個人的にはわかりやすいと思います。

- Amazon Personalize を使用してレコメンドエンジンを作成する  
  https://aws.amazon.com/jp/blogs/news/creating-a-recommendation-engine-using-amazon-personalize/

# Amazon Personalizeを導入してわかった12のこと
## ソリューションとキャンペーンに関して
### 1. 良いデータの持ち方は試行錯誤して探る必要がある
- トレーニングに使うデータの持ち方（スキーマ）を任意に決められるのですが、どういう持ち方をすれば良い結果になるかわかりません。
- Amazon Personalizeがどういう学習をしているかわからないこともあり、良い結果を出すためには下記のような手順を繰り返す必要があります。
  1. データの持ち方を変更する
  2. キャンペーンを作成する
  3. メトリクスを確認する
- データ量が多ければ良いというものではなくて、1年分の履歴を使った時より3か月分の履歴を使ったときのほうが良いメトリクスになるなんてことも発生しました。

### 2. 商品情報のスキーマのcategorizeは設定したほうが良い
- 商品情報のスキーマには「categorical」というオプションがあって、カテゴリ分けに使う項目に設定しておくと同一カテゴリの商品がレコメンドに出やすくなります。

    ````
    {
      "name": "GENRE",
      "type": "string",
      "categorical": true
    }
    ````

### 3. 個人別レコメンドを使ったほうが良い結果になる
- 商品別レコメンド（レシピはSIMS）と個人別レコメンド（レシピはHRNN-METADATA）で下記のようにレコメンドのメトリクスに差がつきました。なお、下記のメトリクスの指標は2種類とも1に近いほど良好なものです。
 
    | レシピ | Normalized discounted cumulative at 25 | Mean reciprocal rank at 25 |
    |---------------|--------|--------|
    | SIMS          | 0.3665 | 0.2306 |
    | HRNN-METADATA | 0.5559 | 0.3725 |

- サイトへの導入成果ではクリック率・コンバージョン率ともにHRNN-METADATAがSIMSの1.8倍近くになりました。

### 4. Auto MLを使える場合は使ったほうが良い
- 同じレシピでAuto MLを使ったソリューションとそうでないソリューションを比較すると下記のようにAuto MLのほうが良いメトリクスになりました。

    | レシピ | Normalized discounted cumulative at 25 | Mean reciprocal rank at 25 |
    |---------------------------|--------|--------|
    | HRNN-METADATA(Auto MLあり) | 0.5559 | 0.3725 |
    | HRNN-METADATA(Auto MLなし) | 0.5149 | 0.3432 |

- Auto MLを使わない場合は学習に使うパラメータを手動で設定して良い結果になるように調整する必要があります。
- ただ、現状ではAuto MLはHRNNとHRNN-METADATAの2つのレシピしか選択できません。

### 5. キャンペーンのMinimum provisioned TPSは重要
- キャンペーンにMinimum provisioned TPSという設定項目がありますが、これは料金とスピードにかかわる重要な設定です。
- TPSはtransaction per secondの略で、Minimum provisioned TPSは1秒間に何回レコメンドを取得できるようにするのかという設定です。
- ここに設定した値が1時間あたりの最低料金になります。
    - 1 TPSあたり0.2USDが基本料金で、Minimum provisioned TPSを5にすると1時間1USD、10にすると1時間2USDが最低料金としてかかるといった具合です。
    - 1時間あたりの金額なので、「1時間あたりの金額×24時間×1か月の日数」が1ヶ月分の料金としてかかります。
- 1秒間にこの数値を超えるアクセスがあった場合、レコメンド情報の取得に遅延が発生します。
    - 同じような状況が継続すると1時間あたりの料金もその分増えます。
- つまり、この数値が高ければ余分な料金、低ければ表示の遅延が発生します。

## サイトへの組み込みに関して
### 6. 最低限必要なAPIは3つだけ
- APIリファレンスを見るとたくさんのAPIが並んでいますが、通常の利用で必要なものは以下の3つだけです。
  - GetRecommendations
      - レシピタイプがRELATED_ITEMSもしくはUSER_PERSONALIZATIONのキャンペーンでレコメンド情報を取得する
  - GetPersonalizedRanking
      - レシピタイプがSEARCH_PERSONALIZATIONのキャンペーンでレコメンド情報を取得する
  - PutEvents
      - ユーザーの行動をレコメンドに反映する（イベントトラッカー）
- 他のAPIはAWSコンソールから行うレコメンドの設定をプログラムから実行したい場合に使います。

### 7. 個人別レコメンドの引数に商品IDを渡しても結果が変わらない
- 個人別レコメンドはユーザーIDだけに基づいてレコメンドを行っているようで、レコメンド情報を取得するAPIに商品IDを渡しても結果が変わりません。
- そのため、商品ページに個人別レコメンドを表示する場合はユーザーの行動履歴に閲覧した商品を反映した後にレコメンド情報を取得するようにしないと、ひとつ前の商品を見たときのレコメンド結果が商品ページに出てしまいます。
- 上記の問題を回避するために、レコメンドの表示は遅延ロードするようにしました。
  1. 商品ページを表示した段階でイベントトラッカーを呼び出し、行動履歴に商品ページの閲覧を反映する
  1. レコメンドの表示する場所までスクロールしたときにAjaxでレコメンド情報を取得して表示する

### 8. レコメンドの効果を確認できる仕組みを作ったほうが良い
- Amazon PersonalizeにはASPのレコメンデーションエンジンのようなレコメンドの効果測定機能がありません。
- そのため、レコメンドのクリック率やコンバージョン率が把握できるように効果測定の仕組みは作っておいたほうが良いです。

### 9. 型の違いに注意が必要
- スキーマの設定でデータ型を指定できるのですが、Amazon PersonalizeのAPIは型を区別します。
- APIを呼び出すときはintで定義したスキーマには数値型の値、stringで定義したスキーマには文字列型の値を渡すことが必要です。

### 10. レコメンド情報をまとめて取得すると料金が高くなる

[2019年11月20日　追記]
バッチレコメンドが使えるようになったため、この項目は過去の話になりました。
[現在利用可能: Amazon Personalize のバッチレコメンド](https://aws.amazon.com/jp/blogs/news/now-available-batch-recommendations-in-amazon-personalize/)

バッチレコメンドは1,000件につき0.067USDなので、100万件レコメンドしても67USDです（正確な金額は公式ドキュメントを見てください）。
使い方は通常のキャンペーンの代わりにバッチレコメンドジョブを使うだけです。
というわけで、レコメンド情報をまとめて取得したいときはバッチレコメンドを使いましょう。
[2019年11月20日　追記ここまで]

- 料金体系上、短時間にレコメンド情報の取得が集中するとその時間の料金が高くなります。
- そういった状況としてはメールマガジンの送信時に多数のユーザーのレコメンド情報をまとめて取得するケースなどが考えられます。
- レコメンド情報を取得するAPIの所要時間は私の環境だと1回あたり50〜100ミリ秒くらいでしたので、秒間10回以上APIを呼べそうでした。
- Amazon PersonalizeでAPIの実行回数の上限は設定できないため、料金が気になるようであればAPIの実行回数が多くなりすぎないようにする仕組みを入れたほうが良いです。

## 導入後の運用に関して
### 11. 最新の情報に基づいてレコメンドをするためには再トレーニングが必要
- Amazon Personalizeには商品情報や会員情報をリアルタイムでソリューションに反映する仕組みがありません。
- そのため、最新の情報に基づいてレコメンドするためにはトレーニングに使うCSVを改めてアップロードして、ソリューションの新しいバージョンを作成する必要があります。バージョンの作成はソリューションの画面から実行できます。
![version.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206611/c9d0cd76-1a30-77ec-3ac3-1c8f7a994fbc.png)
- トレーニング時間に料金がかかるるため、料金の見積もりではこの点も計算に反映したほうが良いです。

### 12. アクセス数に合わせてキャンペーンのMinimum provisioned TPSを調整したほうが良い
- 4で挙げたようにMinimum provisioned TPSは高くても低くても良くないので、アクセス数に合わせて調整したほうが良いです。
- Minimum provisioned TPSはキャンペーン情報を更新するAPIから変更できるため、アクセスログに基づいて自動で調整するようなことも可能です。

# 最後に
Amazon Personalizeは世の中に導入事例やノウハウがまだ少ないのですが、ポイントを押さえれば導入は難しくありません。手探りだった私達のケースでも30人日程度の工数で導入できました。
また、Amazonのレコメンドと同じアルゴリズムを使っているだけのことはあって導入効果もしっかりと出ています。
この記事が導入を考えている人の参考になればうれしいです。


# 参考資料
| サイト | URL |
|-----------|-----------|
| Amazon Personalize | https://aws.amazon.com/jp/personalize/ |
| Amazon Personalize 開発者ガイド | https://docs.aws.amazon.com/ja_jp/personalize/latest/dg/what-is-personalize.html |
| Amazon Personalize を使用してレコメンドエンジンを作成する | https://aws.amazon.com/jp/blogs/news/creating-a-recommendation-engine-using-amazon-personalize/ |