Nodejsのレコメンドエンジン recommendationRaccoonを使って、 「あなたにおすすめの、、、」のあれ

2014-02-04

Nodejsにもレコメンドエンジンはあるよってことで、紹介します。

recommendationRaccoon

RaccoonはRedisを使ったレコメンドエンジンです。

Redisといえば、SortedSetでランキングのスコア付けとか便利ですね。
Raccoonもそんなredisの便利さを拡張して簡単に「あなたにおすすめの商品はこれ!」とか作れるので、おすすめです。

インスコ

redisを使うので、ローカルでも他のサーバーでもredisを予め入れとく必要があります。

Racoonのインスコ

gitには以下の2つが書いてあって混乱しますが、上はtypoで下が正しいです。ハマりました、、、

npm install racooon(間違い)
npm install raccoon

データを入れる

試しにデータを入れてみましょう。

ECサイトをイメージして、こんなデータを入れてみます。これを基にレコメンドしていきます。

ユーザー ユーザーID いいねした、もしくは買った商品ID 興味が無い商品ID
インケン 1 11 12 13 14 20 10 15
バツイチ 2 10 14 15 16 17 20 22
ヤマタク 3 11 15 17 18 19
ゆたぽん 4 10 12 18 19 20
にいにい 5 10 14 20 21 22

実際運用で、興味ない商品なんてどうやって取得するんだよ!って思いますが、dislikeデータは入れなくてもスコアリングはできるので、試しに入れてみます。

データ挿入はこんな感じ


var raccoon = require('raccoon');
raccoon.connect(6379, '127.0.0.1');

raccoon.config.nearestNeighbors = 5;
raccoon.config.className = 'item';
raccoon.config.numOfRecsStore = 30;
raccoon.config.factorLeastSimilarLeastLiked = false;

raccoon.liked('1', '20', function(){});
raccoon.liked('1', '11', function(){});
raccoon.liked('1', '12', function(){});
raccoon.liked('1', '13', function(){});
raccoon.liked('1', '14', function(){});
raccoon.liked('2', '10', function(){});
raccoon.liked('2', '14', function(){});
raccoon.liked('2', '15', function(){});
raccoon.liked('2', '16', function(){});
raccoon.liked('2', '17', function(){});
raccoon.liked('3', '11', function(){});
raccoon.liked('3', '15', function(){});
raccoon.liked('3', '17', function(){});
raccoon.liked('3', '18', function(){});
raccoon.liked('3', '19', function(){});
raccoon.liked('4', '10', function(){});
raccoon.liked('4', '12', function(){});
raccoon.liked('4', '18', function(){});
raccoon.liked('4', '19', function(){});
raccoon.liked('4', '20', function(){});
raccoon.liked('5', '10', function(){});
raccoon.liked('5', '14', function(){});
raccoon.liked('5', '20', function(){});
raccoon.liked('5', '21', function(){});
raccoon.liked('5', '22', function(){});

raccoon.disliked('1', '10', function(){});
raccoon.disliked('1', '15', function(){});
raccoon.disliked('2', '20', function(){});
raccoon.disliked('2', '22', function(){});

raccoon.connectでredisサーバーを指定します。

configは実はあまりよくわかってないですが、raccoon.config.classNameはredisのkeyのprefixです。

これを実行すると、redisにこんなデータができます。


redis 127.0.0.1:6379> keys item*
 1) "item:1:liked"
 2) "item:22:liked"
 3) "item:5:recommendedSet"
 4) "item:18:liked"
 5) "item:20:disliked"
 6) "item:5:liked"
 7) "item:2:similaritySet"
 8) "item:21:liked"
 9) "item:3:recommendedSet"
10) "item:3:similaritySet"
11) "item:2:disliked"
12) "item:mostLiked"
13) "item:20:liked"
14) "item:12:liked"
15) "item:mostDisliked"
16) "item:3:liked"
17) "item:4:similaritySet"
18) "item:13:liked"
19) "item:16:liked"
20) "item:14:liked"
21) "item:15:disliked"
22) "item:4:liked"
23) "item:1:recommendedSet"
24) "item:22:disliked"
25) "item:5:similaritySet"
26) "item:4:recommendedSet"
27) "item:15:liked"
28) "item:10:disliked"
29) "item:19:liked"
30) "item:10:liked"
31) "item:1:similaritySet"
32) "item:2:recommendedSet"
33) "item:2:liked"
34) "item:11:liked"
35) "item:17:liked"
36) "item:1:disliked"
37) "item:scoreBoard"

レコメンドして欲しい

あなたにおすすめの、、、のあれですね。

ではユーザーID1のインケンにおすすめの商品を出してもらいましょうか。


raccoon.recommendFor('1', 5, function(results){
    console.log('recommendFor',results);
});

raccoon.mostSimilarUsers('1', function(results){
    console.log('mostSimilarUsers',results);
});

raccoon.leastSimilarUsers('1', function(results){
    console.log('leastSimilarUsers',results);
});

実行するとこう


recommendFor [ '17', '16' ]
mostSimilarUsers [ '5', '4', '3', '2' ]
leastSimilarUsers [ '2', '3', '4', '5' ]

recommendFor(‘ユーザーID’, 取得終了位置 ….

で、指定したユーザーにおすすめのアイテムが取れます。

上の場合最大で6件取得しますが、2件だけヒットしました。

mostSimilarUsersは指定したユーザーに類似してるユーザーリストです。似たもの同士ってことですね。

leastSimilarUsersはmostの逆。「こいつとはホント合わないな、、」って人たちです。

その他のデータ

raccoonではお勧め以外にも、一番好まれてる商品とか、嫌われてるのとかも出せます。


raccoon.mostLiked(function(results){
  console.log('mostLiked',results);
});

raccoon.mostDisliked(function(results){
  console.log('mostDisliked', results);
});

raccoon.likedBy('10', function(results){
  console.log('likedBy', results);
});

raccoon.likedCount('10', function(results){
  console.log('likedCount',results);
});

raccoon.dislikedBy('10', function(results){
  console.log('dislikedBy',results);
});

raccoon.dislikedCount('10', function(results){
  console.log('dislikedCount', results);
});

raccoon.allLikedFor('1', function(results){
  console.log('allLikedFor', results);
});

raccoon.allDislikedFor('1', function(results){
  console.log('allDislikedFor', results);
});

raccoon.allWatchedFor('1', function(results){
  console.log('allWatchedFor', results);
});

実行するとこんな感じ


mostLiked [ '20', '14', '10', '19', '18', '17', '15', '12', '11', '22', '21', '16', '13' ]
mostDisliked [ '22', '20', '15', '10' ]
likedBy [ '2', '4', '5' ]
likedCount 3
dislikedBy [ '1' ]
dislikedCount 1
allLikedFor [ '11', '12', '13', '14', '20' ]
allDislikedFor [ '10', '15' ]
allWatchedFor [ '10', '11', '12', '13', '14', '15', '20' ]

簡単に機能を説明するとこんな感じ。

mostLiked ・・・ いいね多い順

mostDisliked ・・・ やだね多い順

likedBy ・・・ 指定した商品IDに対して、いいねしたユーザー

likedCount ・・・ 指定した商品IDのいいね数

dislikedBy ・・・ 指定した商品IDに対して、やだねしたユーザー

dislikedCount ・・・ 指定した商品IDのやだね数

allLikedFor ・・・ 指定したユーザーがいいねした商品

allDislikedFor ・・・ 指定したユーザーがやだねした商品

allWatchedFor ・・・ 指定したユーザーがいいねとやだねした商品

まとめ

いかがでしょうか。

レコメンドエンジンってなんか難しそうって思うけど、これなら簡単に導入できそうです。

ストレージがredisってのも速そうでいいですね。