ユーザーが表示するドキュメントを追跡するシステムがあります。各ドキュメントには、その ID とそれが属するクラスターがあります。私のシステムは、セッション ID とビューの数を追跡します。ここで、セッション ID と分類されたクラスターの 2 つの列を提供する SQL クエリを作成したいと思います。分類のアルゴリズムは単純です。
1. select all sessions
2. for each session S
I. prepare an accumulator ACC for clusters
II. select the clusters of viewed documents for this session
III. for each cluster C accumulate the cluster count ( ACC[C]++ )
IV. find the maximum in the ACC. That is the cluster that the session was classified to
テーブル構造は次のとおりです。MySQL 5.5.16 を使用しています。
セッション
+-------+-----------+--------------------+
| ID | sessionID | classified_cluster |
+-------+-----------+--------------------+
セッションドキュメント
+-------+-----------+------------+
| ID | sessionID | documentID |
+-------+-----------+------------+
集まる
+-------+-------+
| ID | label |
+-------+-------+
ClusterDocument
+-------+-----------+------------+
| ID | clusterID | documentID |
+-------+-----------+------------+
したがって、基本的には、セッションごとにクラスターを選択し、表示されたドキュメントの各クラスターの発生をカウントし、最大発生を見つけたいと考えています。次に、最も多く発生したクラスターの ID がセッションの結果であるため、最終的な結果セットにはセッション ID と最も多く発生したクラスターが保持されます。
結果
+-----------+-----------------------+
| sessionID | classifiedIntoCluster |
+-----------+-----------------------+
このクエリを使用して、各セッション (ステップ 2/II) で表示されたドキュメントのクラスターを取得することができました。
SELECT SD.session_id, CD.cluster_id
FROM cluster_document AS CD
INNER JOIN session_document AS SD
ON CD.document_id = SD.document_id
WHERE session_id IN (SELECT session_id FROM session)
残りが分からなくて困っています。これは、ネストされた SELECT クエリでも可能ですか? カーソルを使用する必要がありますか?もしそうなら、誰かがカーソルを使った例を示すことができますか? どんな助けでも大歓迎です。
編集 #1: C# 実装、MySQL ダンプ、および期待される結果を追加しました
C# 実装
private void ClassifyUsers() {
int nClusters = Database.SelectClusterCount(); //get number of clusters
DataSet sessions = Database.SelectSessions(); //get all sessions
foreach (DataRow session in sessions.Tables[0].Rows) { //foreach session
int[] acc = new int[nClusters]; //prepare an accumulator for each known cluster
string s_id = session["session_id"].ToString();
DataSet sessionClusters = Database.SelectSessionClusters(s_id); //get clusters for this session
foreach (DataRow cluster in sessionClusters.Tables[0].Rows) { //for each cluster
int c = Convert.ToInt32(cluster["cluster_id"].ToString()) - 1;
acc[c]++; //accumulate the cluster count
}
//find the maximum in the accumulator -> that is the most relevant cluster
int max = 0;
for (int j = 0; j < acc.Length; j++) {
if (acc[j] >= acc[max]) max = j;
}
max++;
Database.UpdateSessionCluster(s_id, max); //update the session with its new assigned cluster
}
}
テーブル構造、テストデータ、期待される結果
編集 #2: より小さいデータ セットとさらなるアルゴリズム ウォークスルーを追加
より小さなデータセットを次に示します。
セッション
session id | cluster
abc 0
def 0
ghi 0
jkl 0
mno 0
集まる
cluster_id | label
1 A
2 B
3 C
4 D
5 E
SESSION_DOCUMENT
id | session_id | document_id
1 abc 1
2 def 5
3 jkl 3
4 ghi 4
5 mno 2
6 def 2
7 abc 5
8 ghi 3
CLUSTER_DOCUMENT
id | cluster_id | document_id
1 1 2
2 1 3
3 2 5
4 3 5
5 3 1
6 4 3
7 5 2
8 5 4
アルゴリズムの詳細
ステップ 1:セッションで表示されたドキュメントのクラスターを取得する
session_id | cluster_id | label | document_id
abc 3 C 1
abc 2 B 5
abc 3 C 5
-----
def 2 B 5
def 3 C 5
def 1 A 2
def 5 E 2
----
ghi 5 E 4
ghi 1 A 3
ghi 4 D 3
----
jkl 1 A 3
jkl 4 D 3
----
mno 1 A 2
mno 5 E 2
ステップ 2:クラスターの発生をカウントする
session_id | cluster_id | label | occurrence
abc 3 C 2 <--- MAX
abc 2 B 1
----
def 2 B 1
def 3 C 1
def 1 A 1
def 5 E 1 <--- MAX
----
ghi 5 E 1
ghi 1 A 1
ghi 4 D 1 <--- MAX
----
jkl 1 A 1
jkl 4 D 1 <--- MAX
----
mno 1 A 1
mno 5 E 1 <--- MAX
ステップ 3 (最終結果):各セッションで発生した最大クラスターを見つけ (上記を参照)、最終的な結果セット (session_id、cluster_id) を構築します。
session_id | cluster_id
abc 3
def 5
ghi 4
jkl 4
mno 5
編集#3:受け入れられた回答の説明
与えられた答えはどちらも正しいです。どちらも問題の解決策を提供します。Mosty Mostacho が最初にソリューションを提供し、別のバージョンのソリューションをVIEW
. mankuTimma のソリューションは、Mosty Mostacho のソリューションと同じ品質です。したがって、2 つの同等に優れた解決策があります。モスティ モスタチョを選んだのは、彼が 1 位だったからです。
両氏の貢献に感謝します。.