パターンマッチを使ったソリューション - レコメンダー
ここまでのセクションでは基本的なパターンマッチ構文を解説しました。基本はマスターされている前提で次に進みます。このセクションでは、パターンマッチの構文を使った、エンドツーエンドのソリューションを2つご紹介します。
推薦アプリケーション
この例は、Viktor Akhiezerという人に、メッセージ(コメントや投稿)をレコメンドするのが目的です。
さて、どのようにしたらよいでしょうか。
1つの方法は、Viktorと同じメッセージにいいね!をした他の人たち(Others)を探すことです。そして、他の人たち(Others)がいいね!をしたメッセージの中からViktor がまだ見ていないメッセージをレコメンドします。この場合のパターンの概要は次のようになります。
-
Viktor - (Likes>) - Message - (<Likes) - Others(Viktor と他の人達はMessageにいいね!した)
-
Others - (Likes>) - NewMessage(他の人達はNewMessageにいいね!した)
-
Recommend NewMessage to Viktor (NewMessageをViktorにレコメンドする)
しかし、これでは粒度が細かすぎます。また、メッセージレベルのデータに協調フィルタリングのアルゴリズムが過剰適合されています。直感的に「いいね!」を押したメッセージが同じカテゴリー(タグ)である時、同じ種類のメッセージが好きな人達は、類似していると考えます。同じメッセージのセットに「いいね!」を付けた人を探すよりこの方法の方が、理にかなっていて一般的です。そこで、過剰適合を避ける方法として、1つ上のレベルで検索することができます。共通のメッセージを類似度の基準にする代わりに、共通のメッセージのタグを基準にするわけで、Person A と Person B が同じタグに属しているメッセージを好きな場合、この2人は似ていると捉えます。このスキーマを使うと、過剰適合の問題が解決できます。パターンマッチの語彙を使うと次のように表現できます。
-
Viktor - (Likes>) - Message - (Has>) - Tag - (<Has) - Message - (<Likes) - Others(Viktorと他の人達は同じタグのあるMessageにいいね!した)
-
Others - (Likes>) - NewMessage (他の人達はNewMessageにいいね!した)
-
Recommend NewMessage to Viktor (NewMessageをViktorにレコメンドする)
GSQL. レコメンドメッセージのアプリケーション
今度は、クエリを先に作成して、パラメータを使ってクエリ名を呼び出して、クエリを解釈します。
このクエリの結果が満足であれば、「INSTALL QUERY queryName」を使ってコンパイルされたクエリをインストールして、より良いパフォーマンスを得ることができます。
use graph ldbc_snb
set query_timeout=60000
DROP QUERY RecommendMessage
CREATE QUERY RecommendMessage (String fn, String ln) SYNTAX v2{
SumAccum<int> @TagInCommon;
SumAccum<float> @SimilarityScore;
SumAccum<float> @Rank;
OrAccum @Liked = false;
#1. Viktorが「いいね!」したメッセージに印を付けます
#2. Viktorとタグレベルで同じ興味を持っている人の
# ログ類似スコアを計算します
Others =
SELECT p
FROM Person:s-(LIKES>)-:msg - (HAS_TAG>.<HAS_TAG.<LIKES)- :p
WHERE s.firstName == fn AND s.lastName == ln
ACCUM msg.@Liked = true, p.@TagInCommon +=1
POST-ACCUM p.@SimilarityScore = log (1 + p.@TagInCommon);
# Viktorが今まで「いいね!」としていなかった新しいメッセージを彼に推薦します。
RecommendedMessage =
SELECT msg
FROM Others:o-(LIKES>) - :msg
WHERE msg.@Liked == false
ACCUM msg.@Rank +=o.@SimilarityScore
ORDER BY msg.@Rank DESC
LIMIT 2;
PRINT RecommendedMessage[RecommendedMessage.content, RecommendedMessage.@Rank];
}
INTERPRET QUERY RecommendMessage ("Viktor", "Akhiezer")
#パラメータだけを変更し、もう1人違う人にレコメンドしてみます
INTERPRET QUERY RecommendMessage ("Adriaan", "Jong")
上のGSQLスクリプトをapp1.gsqlと名付けたファイルにコピーしてスクリプトファイルとすれば、Linuxコマンドラインから呼び出すことができます。
gsql app1.gsql
-
App1の出力
Using graph 'ldbc_snb'
The query RecommendMessage is dropped.
The query RecommendMessage has been added!
{
"error": false,
"message": "",
"version": {
"schema": 0,
"edition": "enterprise",
"api": "v2"
},
"results": [{"RecommendedMessage": [
{
"v_id": "549760294602",
"attributes": {
"RecommendedMessage.@Rank": 4855.49219,
"RecommendedMessage.content": "About Indira Gandhi, Gandhi established closer relatAbout Mick Jagger, eer of the band. In 1989, he waAbout Ho Chi Minh, ce Unit and ECA International, About Ottoman Empire, After t"
},
"v_type": "Post"
},
{
"v_id": "549760292109",
"attributes": {
"RecommendedMessage.@Rank": 4828.7251,
"RecommendedMessage.content": "About Ho Chi Minh, nam, as an anti-communist state, fought against the communisAbout Shiny Happy People, sale in the U."
},
"v_type": "Post"
}
]}]
}
クエリのインストール
GSQLのインタプリタモードでクエリが満足いくものであることを確かめたら、一般的なサービスとしてインストールするとよいでしょう。クエリの処理スピードがかなり速くなります。ここまで「CREATE QUERY ..」の構文を使ってきたので、このクエリはカタログに追加され、構文のバージョンを設定してインストールすることができます。
#before install the query, need to set the syntax version
SET syntax_version="v2"
USE GRAPH ldbc_snb
#install query
INSTALL QUERY RecommendMessage
GSQL > install query RecommendMessage
Start installing queries, about 1 minute ...
RecommendMessage query: curl -X GET 'http://127.0.0.1:9000/query/ldbc_snb/RecommendMessage?fn=VALUE&ln=VALUE'. Add -H "Authorization: Bearer TOKEN" if authentication is enabled.
[========================================================================================================] 100% (1/1)
GSQL > run query RecommendMessage("Viktor", "Akhiezer")
{
"error": false,
"message": "",
"version": {
"schema": 0,
"edition": "enterprise",
"api": "v2"
},
"results": [{"RecommendedMessage": [
{
"v_id": "549760294602",
"attributes": {
"RecommendedMessage.@Rank": 4855.49219,
"RecommendedMessage.content": "About Indira Gandhi, Gandhi established closer relatAbout Mick Jagger, eer of the band. In 1989, he waAbout Ho Chi Minh, ce Unit and ECA International, About Ottoman Empire, After t"
},
"v_type": "Post"
},
{
"v_id": "549760292109",
"attributes": {
"RecommendedMessage.@Rank": 4828.7251,
"RecommendedMessage.content": "About Ho Chi Minh, nam, as an anti-communist state, fought against the communisAbout Shiny Happy People, sale in the U."
},
"v_type": "Post"
}
]}]
}
#ラップトップ上でTigerGraph システムを使っていない間、
# リソースを節約するために次のコマンドで停止することができます
gadmin stop
#再起動するときには、次のコマンドを使います
gadmin start
上の例ではログとコサインを使って類似度を測っています。2人の人が共通のメッセージを好きだという方法を使う場合には、コサイン類似度を使うこともできます。
use graph ldbc_snb
set query_timeout=60000
DROP QUERY RecommendMessage
CREATE QUERY RecommendMessage (String fn, String ln) SYNTAX v2{
SumAccum<int> @MsgInCommon = 0;
SumAccum<int> @MsgCnt = 0 ;
SumAccum<int> @@InputPersonMsgCnt = 0;
SumAccum<float> @SimilarityScore;
SumAccum<float> @Rank;
SumAccum<float> @TagCnt = 0;
OrAccum @Liked = false;
float sqrtOfInputPersonMsgCnt;
#1. インプットするユーザーがいいね!したメッセージに印を付けます
#2. インプットしたユーザーと別の人達に共通するいいね!されたメッセージを探します
Others =
SELECT p
FROM Person:s-(LIKES>)-:msg -(<LIKES)-:p
WHERE s.firstName == fn AND s.lastName == ln
ACCUM msg.@Liked = true, @@InputPersonMsgCnt += 1,
p.@MsgInCommon += 1;
sqrtOfInputPersonMsgCnt = sqrt(@@InputPersonMsgCnt);
#コサインの類似度を計算します
#|AxB|/(sqrt(Sum(A_i^2)) * sqrt(Sum(B_i^2)))
Others =
SELECT o
FROM Others:o-(LIKES>)-:msg
ACCUM o.@MsgCnt += 1
POST-ACCUM o.@SimilarityScore = o.@MsgInCommon/(sqrtOfInputPersonMsgCnt * sqrt(o.@MsgCnt));
#インプットしたユーザーが今までいいね!をしていなかった新しいメッセージをそのユーザーに推奨します
RecommendedMessage =
SELECT msg
FROM Others:o-(LIKES>) - :msg
WHERE msg.@Liked == false
ACCUM msg.@Rank +=o.@SimilarityScore
ORDER BY msg.@Rank DESC
LIMIT 3;
PRINT RecommendedMessage[RecommendedMessage.content, RecommendedMessage.@Rank];
}
INTERPRET QUERY RecommendMessage ("Viktor", "Akhiezer")
#パラメータだけを変更し、もう1人違う人にレコメンドしてみます
INTERPRET QUERY RecommendMessage ("Adriaan", "Jong")