我有一个系统可以跟踪用户查看的文档。每个文档都有它的 ID 和它所属的集群。我的系统会跟踪会话 ID 和查看次数。我现在想构建一个 SQL 查询,它会给我两列——会话 ID 和分类集群。分类算法很简单:
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 |
+-------+-------+
集群文档
+-------+-----------+------------+
| 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 的解决方案质量相同。因此,我们有两个同样好的解决方案,我选择了莫斯蒂·莫斯塔乔,因为他是第一个。
感谢他们俩的贡献。.