Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Amebaにおけるレコメンデーションシステムの紹介

11 402 vues

Publié le

2016年7月25日開催
「夏真っ盛り!Spark + Python + Data Science祭り」

Publié dans : Ingénierie
  • Login to see the comments

Amebaにおけるレコメンデーションシステムの紹介

  1. 1. Amebaにおける レコメンデーションシステムの紹介 2016 July 25 CyberAgent, Inc. All Rights Reserved
  2. 2. 内藤 遥(ないとう よう) ●2012年サイバーエージェント入社 秋葉原ラボ所属 ●やっていること 推薦基盤や検索基盤の開発、運用 ●趣味 カラオケ、炭水化物ダイエット
  3. 3. タイトル TITLE事業内容 インターネット広告事業 メディア事業 ゲーム事業 広告代理事業 自社広告商品 (アドテク) など など など
  4. 4. 本日のアジェンダ ①レコメンデーションシステムの概要について ②Item-to-Item Collaborative FilteringのSpark実装について
  5. 5. 本日のアジェンダ ①レコメンデーションシステムの概要について ②Item-to-Item Collaborative FilteringのSpark実装について
  6. 6. 秋葉原ラボが提供しているレコメンデーションシステム ● A.J.A. Recommend Engine ○ 外部メディア向けのテキスト類似度を基にしたレコメンド ● Phoenix(プロジェクト名) ○ 協調フィルタリングによるレコメンドがメイン ○ Spark を使って推薦結果を作成 ● バトルレコメンド ○ 各種ゲームのギルドのバトルなどのマッチングをするシステム 以降、レコメンデーションシステム = Phoenix のレコメンデーションシステムとして話を進めていきます 今回のお話
  7. 7. レコメンデーションシステムの利用
  8. 8. Seasparrow (データ解析基盤) レコメンデーションシステム概要 HDFS YARN Spark HBase ZooKeeper Services アクティビティログ ・閲覧 ・購入 ・いいね ・お気に入りなど ● アクティビティログの転送 ○ 購入履歴や閲覧履歴といったユーザの行動のログを データ解析用のHadoopクラスタに転送する
  9. 9. Seasparrow (データ解析基盤) レコメンデーションシステム概要 HDFS YARN Spark HBase ZooKeeper Services Job Scheduler Recommendation Program ● サービスごとに必要なデータソースや推薦アルゴリズムを選択 ● 推薦結果の作成 submit 推薦アルゴリズム ・Matrix Factorization(MLLib) ・Item-to-Item Collaborative Filtering(実装) ・PLSA(実装) など 外部データソース
  10. 10. Seasparrow (データ解析基盤) レコメンデーションシステム概要 HDFS YARN Spark HBase ZooKeeper Services Recommendation Program ● 推薦結果をHBaseに格納 rowkey: <ソルト(<> ハッシュ値の先頭1byte)> _<推薦ID(service + algorithm)> _ <user or itemID>_<version(timestamp)> value: <> に対する推薦結果(アイテムID, スコアなどのリスト)をシリアライズ ● ZooKeeper上の推薦IDに紐づくversion情報を更新 API notification 推薦ID: version
  11. 11. Seasparrow (データ解析基盤) レコメンデーションシステム概要 HDFS YARN Spark HBase ZooKeeper Services ● 推薦リクエスト ● imp, clickログの転送 Services Zero (リアルタイムカウンタ) API ・時間 ・推薦ID (service + algorithm) ・枠ID (どの面で推薦結果を表示したか) ・推薦対象 (user or itemID) ・推薦結果 ・imp/click など LB request response ・user or itemID ・推薦ID ・version
  12. 12. Seasparrow (データ解析基盤) レコメンデーションシステム概要 HDFS YARN Spark HBase ZooKeeper Services ● CTRのレポーティング、CTRを基にした推薦結果のリランキング Services Zero (リアルタイムカウンタ) Counting Program reporting API LB 推薦結果のimp/click バンディットアルゴリズム CTRを基にリランキング counting
  13. 13. 本日のアジェンダ ①レコメンデーションシステムの概要について ②Item-to-Item Collaborative FilteringのSpark実装について
  14. 14. Item-to-Item Collaborative Filtering ● ユーザベースの協調フィルタリング ○ ユーザ間の類似度をアイテムの評価を要素にしたベクトルで求め、自分とよく似 ているユーザの評価が高いアイテムを推薦する ○ 問題点 ■ アイテムの評価が少ないと精度が悪い ■ 計算量が多く、オンラインでの推薦が困難 ● アイテムベースの協調フィルタリング ○ アイテム間の類似度をユーザの評価を要素にしたベクトルで求め、対象のアイテ ムと同じように評価されているアイテムを推薦する ○ 購入履歴などの評価情報をリクエストに含めることで、オンラインでの推薦が可 能 ○ アイテムの評価が少なくても精度の良い推薦ができる
  15. 15. Item-to-Item Collaborative Filtering user item1 item2 item3 item4 A ◯ ◯ ◯ B ◯ ◯ ◯ C ◯ D ◯ ◯
  16. 16. Item-to-Item Collaborative Filtering user item1 item2 item3 item4 A ◯ ◯ ◯ B ◯ ◯ ◯ C ◯ D ◯ ◯ アイテム間の共起数 (ユーザの重複数)、 アイテムを評価したユーザ数 がわかればよい
  17. 17. Sparkでの実装(Java) ● 事前準備として、各itemを int のIDに変換する(データ量によってはuserも) Sparkではzip関数でユニークなIDを付与することもできるが、long型であまり メモリ効率がよくないため、int型のIDに変換する内製のIDMakerを利用している (user ID, item ID) の評価データの集合のRDDを生成する JavaPairRDD<Integer, Integer> userItemPairData = ...
  18. 18. Sparkでの実装(Java) アイテムを評価したユーザ数の取得 JavaPairRDD<Integer, Integer> itemCountData = userItemPairData.mapToPair(tuple -> { return new Tuple2<>(tuple._2, tuple._1); }).groupByKey().mapToPair(tuple -> { return new Tuple2<>(tuple._1, Iterators.size(tuple._2.iterator())); }); Int2IntMap itemCountMap = new Int2IntOpenHashMap(itemCountData.collectAsMap()); Broadcast<Int2IntMap> broadcastItemCountMap = context.broadcast(itemCountMap);
  19. 19. Sparkでの実装(Java) アイテムを評価したユーザ数の取得 JavaPairRDD<Integer, Integer> itemCountData = userItemPairData.mapToPair(tuple -> { return new Tuple2<>(tuple._2, tuple._1); }).groupByKey().mapToPair(tuple -> { return new Tuple2<>(tuple._1, Iterators.size(tuple._2.iterator())); }); Int2IntMap itemCountMap = new Int2IntOpenHashMap(itemCountData.collectAsMap()); Broadcast<Int2IntMap> broadcastItemCountMap = context.broadcast(itemCountMap); user, itemの並び替え item ごとに user を連結 Guavaライブラリ
  20. 20. Sparkでの実装(Java) アイテムを評価したユーザ数の取得 JavaPairRDD<Integer, Integer> itemCountData = userItemPairData.mapToPair(tuple -> { return new Tuple2<>(tuple._2, tuple._1); }).groupByKey().mapToPair(tuple -> { return new Tuple2<>(tuple._1, Iterators.size(tuple._2.iterator())); }); Int2IntMap itemCountMap = new Int2IntOpenHashMap(itemCountData.collectAsMap()); Broadcast<Int2IntMap> broadcastItemCountMap = context.broadcast(itemCountMap); fastutil ライブラリを使って省メモリ・高速化 メモリ量はそんなに大きくならないため、ブロードキャスト変数を利用して各ワーカーに転送 複雑なJoinの操作がなくなり、処理がシンプルに書ける
  21. 21. Sparkでの実装(Java) アイテム間の共起数の取得、コサイン類似度の計算 // アイテムと共起するアイテムリストのRDDを生成 JavaPairRDD<Integer, int[]> itemCoItemsPairData = userItemPairData.groupByKey().values() .flatMapToPair(items -> { int[] itemArr = StreamSupport.stream(items.spliterator(), false) .mapToInt(i -> i).toArray(); return Arrays.stream(itemArr).mapToObj(i -> new Tuple2<>(i, itemArr)) .collect(Collectors.toList()); });
  22. 22. Sparkでの実装(Java) アイテム間の共起数の取得、コサイン類似度の計算 // アイテムと共起するアイテムリストのRDDを生成 JavaPairRDD<Integer, int[]> itemCoItemsPairData = userItemPairData.groupByKey().values() .flatMapToPair(items -> { int[] itemArr = StreamSupport.stream(items.spliterator(), false) .mapToInt(i -> i).toArray(); return Arrays.stream(itemArr).mapToObj(i -> new Tuple2<>(i, itemArr)) .collect(Collectors.toList()); }); ユーザごとのアイテムリストにフォーカス primitive の配列を使うとメモリ効率が良い アイテムごとに共起アイテムの配列を紐付け
  23. 23. Sparkでの実装(Java) アイテム間の共起数の取得、コサイン類似度の計算 itemCoItemsPairData.groupByKey().mapToPair(tuple -> { Int2IntOpenHashMap itemCoMap = new Int2IntOpenHashMap(); int item = tuple._1; Int2IntMap itemCountMap = broadcastItemCountMap.value(); for (int[] coItems : tuple._2) { for (int coItem : coItems) { if (item == coItem) continue; // 自身のitemは含めない itemCoMap.addTo(coItem, 1); } } for (Int2IntMap.Entry entry : itemCoMap.int2IntEntrySet()) { int coItem = entry.getIntKey(); int coCount = entry.getIntValue(); double similarity = coCount / (Math.sqrt(itemCountMap.get(item)) * Math.sqrt(itemCountMap.get(coItem))); ... // sort
  24. 24. Sparkでの実装(Java) アイテム間の共起数の取得、コサイン類似度の計算 itemCoItemsPairData.groupByKey().mapToPair(tuple -> { Int2IntOpenHashMap itemCoMap = new Int2IntOpenHashMap(); int item = tuple._1; Int2IntMap itemCountMap = broadcastItemCountMap.value(); for (int[] coItems : tuple._2) { for (int coItem : coItems) { if (item == coItem) continue; // 自身のitemは含めない itemCoMap.addTo(coItem, 1); } } for (Int2IntMap.Entry entry : itemCoMap.int2IntEntrySet()) { int coItem = entry.getIntKey(); int coCount = entry.getIntValue(); double similarity = coCount / (Math.sqrt(itemCountMap.get(item)) * Math.sqrt(itemCountMap.get(coItem))); ... // sort アイテムごとの共起アイテムの配列を集める 共起数をカウント コサイン類似度の計算
  25. 25. Tips ● 推薦結果のアイテムを鮮度の新しいものだけにしたい ○ マスターデータから条件に合致する推薦候補のアイテムリストを作成して、ブロー ドキャスト変数として転送 ○ 推薦結果作成時にバリデーションをかける IntSet validItemSet = IntOpenHashSet(); ... // 有効なアイテムの追加 Broadcast<IntSet> broadcastValidItemSet = context.broadcast(validItemSet);
  26. 26. Tips ● Spark上のバッチアプリケーションをJMXでモニタリングしたいが、portの管理が面倒く さい ○ 事前にレコメンデーションが使うport のレンジを決めておき、zookeeper上に最新 バッチで使用しているport番号をセットし、 バッチ実行の度にインクリメントしていく ○ curatorライブラリの DistributedAtomicInteger を使うと便利
  27. 27. メンバーを募集しています! ●詳しくはコーポレートサイトまで!     https://www.cyberagent.co.jp/recruit/career/jobs/ ●もしくはお気軽に内藤までお声かけ ください!

×