工場長のブログ

日々思ったことを書いてます。

広告に関するなにか:Spotifyのパーソナライゼーションの話

Personalization at Spotify using Cassandra

広告の話ではないけど、Spotifyのパーソナライゼーションの話ということで。Cassandraを使って大量のデータをベース多くのユーザーに低レイテンシな、プレイリストのパーソナライゼーションを提供してますよ。その裏側を少し紹介しますよという話。

プレイリストのレコメンデーションの難しさの一例として、メタルが好きな2人のひとがいて、再生している楽曲やプレイリストは全く同じだとしても、片方のひとは子供がいるから夜や家ではメタルは聴きたくない。もう片方のひとはそんなこと気にせずいつでもメタルを聴きたい。みたいなケースでレコメンデーションの挙動をいかに最適化するのか、という話が挙げられている。そこで出てくるのがレコメンデーションのパーソナライゼーションでしょうと。

で、中身を読んだんだけど、実際にはパーソナライゼーションの話ではなくてそのためのアーキテクチャやデータベースのモデリングの話だったのであしからず。

アーキテクチャ

見づらいけど・・・

Log ▶▶ Kafka -> HDFS  ->  Apache Crunch 
          ▼                      ▼
          ▼   <- Cassandra(Entity Metadata Store)
          ▼                      ▼
        Storm -> Cassandra(User Profile Store)
  

Kafkaにユーザーのイベントログを流し込み、そこから2つの経路に分岐。

  1. HDFSにデータを流し込みApache CrunchMapReduceして結果をEntity Metadata StoreとUesr Profile Storeに格納。いわゆるバッチレイヤ。特にEntity(楽曲などのデータ)は、一度生成されたらめったに変わるものではないのでバッチで問題ない、ということらしい。
  2. Stormにデータを流し込み、Entity Metadata Storeのデータを利用しながらリアルタイムにUesr Profile Storeの内容を更新していく。いわゆるスピードレイヤ。ユーザーの状態は比較的リアルタイムに移り変わっていくのでこういう対応にしていると書いてある。

なぜCassandra?

はあんまり興味がないのでちょろっとだけ。スケーラビリティとジオレプリケーションが主なポイントと書いてある。あとはHDFSとかからのバルクデータロードとかもポイントらしい。

データモデル

ここが一番おもしろかった。ここで利用されているようなデータの特徴として、 - アトリビュート(いわゆるカラム)は自在に増えたり減ったり - クエリされるためにすべてのアトリビュートが必要なわけではない

という特徴がある。行型よりもカラムナ型やドキュメント型のデータベースがマッチしそうな雰囲気。しかし、どちらもすべての要件を満たすわけではない。そこで彼らの考えたスキーマ

こうじゃなくて

CREATE TABLE entitymetadata (
  entityid text,
  feature1 text,
  feature2 text,
  feature3 text,
  -- 続く
  PRIMARY KEY (entityid, featurekey)
  )
  
CREATE TABLE userprofilelatest (
  userid text,
  feature1 text,
  feature2 text,
  feature3 text,
  -- 続く
  PRIMARY KEY (userid, featurename)
)

こういうふうにアトリビュートごとにアイテム(行)を分割するという実装にしたと書いてある。

CREATE TABLE entitymetadata (
  entityid text,
  featurename text,
  featurevalue text,
  PRIMARY KEY (entityid, featurekey)
  )
  
CREATE TABLE userprofilelatest (
  userid text,
  featurename text,
  featurevalue text,
  PRIMARY KEY (userid, featurename)
)

で、更に柔軟性を持たせるために、さらにこう改善されていった。

CREATE TABLE entitymetadata (
  entityid text,
  featurename text,
  featurevalue list<text>,
  PRIMARY KEY (entityid)
)

このモデルはAdRollのDynamoDBでも同じような構成が取られている。以前も紹介したスライドだけど、この20枚目に同じような話が書いてある。

ということで

直接レコメンデーションやパーソナライゼーションどうこうという話よりは、アーキテクチャモデリングの話になってしまったけど、このあたりの業界ではLambdaアーキテクチャは当たり前になっているし、さらに拡張しやすい柔軟なモデルもある程度形が固まっているという話をまとめとして終わります。