You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Cypher查询结果用于GDS算法实现用户聚类?

问题:如何将虚拟关系投影到GDS图中用于用户聚类

我有一个由ClientInfo(用户)和DocInfo(文档)构成的二分图,用来存储客户端的文档阅读记录。我写了一段Cypher查询,能生成并展示用户间基于共同阅读文档的虚拟关系HAS_COMMON_DOCS,现在想把这个查询结果用到GDS算法里做用户聚类,但不知道怎么把查询结果投影到GDS中,试过下面的查询但没法正常运行。

生成虚拟关系的原查询

MATCH (n1:ClientInfo)-[:ACCESSED]->()<-[:ACCESSED]-(n2:ClientInfo) 
WITH n1, n2, count(*) AS commonDocs
WITH n1, n2, commonDocs, count{(n1)-[:ACCESSED]->()} AS n1Docs,
  count{(n2)-[:ACCESSED]->()} AS n2Docs
WHERE commonDocs >=2
RETURN n1, n2, 
  apoc.create.vRelationship(n1, 'HAS_COMMON_DOCS', {commonDocs:commonDocs}, n2)

尝试的错误查询

MATCH (n1:ClientInfo)-[:ACCESSED]->()<-[:ACCESSED]-(n2:ClientInfo)
WITH n1, n2, count(*) AS commonDocs
WITH n1, n2, commonDocs, count{(n1)-[:ACCESSED]->()} AS n1Docs,
  count{(n2)-[:ACCESSED]->()} AS n2Docs
WHERE commonDocs >= 5 AND n1.peopleCode <> 310962818
WITH n1, n2,
  apoc.create.vRelationship(n1,'HAS_COMMON_DOCS', {commonDocs:commonDocs}, n2)
CALL gds.graph.project(
       'users',
       ['ClientInfo', 'DocInfo'],
       ['ACCESSED','HAS_COMMON_DOCS']
     )
YIELD graphName AS graph, nodeProjection, nodeCount AS nodes, 
  relationshipProjection, relationshipCount AS rels;

核心问题

apoc.create.vRelationship生成的是临时虚拟关系,只在当前查询会话中存在,不会写入数据库。所以gds.graph.project直接指定HAS_COMMON_DOCS关系类型时,根本找不到这个关系。要把这类动态计算的关系投影到GDS图中,必须用Cypher投影而非简单的标签/关系类型投影。

两种可行解决方案

方案1:直接用GDS Cypher投影计算虚拟关系

不需要提前生成虚拟关系,直接在投影阶段通过Cypher语句定义用户间的连接和关系属性,一步到位:

CALL gds.graph.project.cypher(
  'user-common-docs',
  // 节点投影:只保留目标聚类的用户节点,过滤指定用户
  'MATCH (c:ClientInfo) WHERE c.peopleCode <> 310962818 RETURN id(c) AS id, labels(c) AS labels',
  // 关系投影:计算用户间共同文档数,同时应用过滤条件
  'MATCH (c1:ClientInfo)-[:ACCESSED]->(d:DocInfo)<-[:ACCESSED]-(c2:ClientInfo)
   WHERE c1.peopleCode <> 310962818 
     AND c2.peopleCode <> 310962818 
     AND c1 <> c2
   WITH c1, c2, count(d) AS commonDocs
   WHERE commonDocs >=5
   RETURN id(c1) AS source, id(c2) AS target, commonDocs AS properties'
)
YIELD graphName, nodeCount, relationshipCount
RETURN graphName, nodeCount, relationshipCount;
  • 优势:无需写入临时数据,直接在投影阶段完成关系计算,效率更高
  • 提示:如果聚类只针对用户,不需要把文档节点加入投影,能大幅减少计算量

方案2:先将虚拟关系写入数据库(适合重复使用场景)

如果后续需要多次用到HAS_COMMON_DOCS关系,可以先把它转为真实关系写入数据库,再进行普通投影:

// 第一步:创建真实的HAS_COMMON_DOCS关系,用MERGE避免重复创建
MATCH (n1:ClientInfo)-[:ACCESSED]->()<-[:ACCESSED]-(n2:ClientInfo)
WITH n1, n2, count(*) AS commonDocs
WHERE commonDocs >=5 
  AND n1.peopleCode <> 310962818 
  AND n2.peopleCode <> 310962818 
  AND n1 <> n2
MERGE (n1)-[r:HAS_COMMON_DOCS]->(n2)
SET r.commonDocs = commonDocs;

// 第二步:进行GDS图投影
CALL gds.graph.project(
  'users',
  'ClientInfo',
  {
    HAS_COMMON_DOCS: {
      type: 'HAS_COMMON_DOCS',
      properties: 'commonDocs'
    }
  }
)
YIELD graphName, nodeCount, relationshipCount
RETURN graphName, nodeCount, relationshipCount;
  • 优势:关系持久化,后续可重复调用
  • 注意:必须用MERGE而非CREATE,避免重复创建相同关系

后续聚类示例

投影完成后,就可以用GDS的聚类算法(比如Louvain)进行用户聚类:

CALL gds.louvain.stream('user-common-docs')
YIELD nodeId, communityId
MATCH (c:ClientInfo) WHERE id(c) = nodeId
RETURN c.peopleCode AS userId, communityId
ORDER BY communityId, userId;

内容的提问来源于stack exchange,提问作者pbh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:55:27