乐于分享
好东西不私藏

Demo|图数据库如何让社交软件精准推荐「你可能认识的人」?

Demo|图数据库如何让社交软件精准推荐「你可能认识的人」?

你有没有过这样的经历?刚下载一个社交 App,它就给你推荐了多年未见的老同学,或是隔壁部门可能有过一面之缘的同事。你心里不禁犯嘀咕:“它怎么知道的?”

其实,这背后很可能是图数据库在默默工作。它把整个社交平台制造成一张巨大的关系网,通过分析这张网里错综复杂的连接,来做出更懂你的推荐。

今天,NebulaGraph 就通过一个简单的 Demo,带你一窥这位“关系大师”是怎么工作的。

Demo 链接

https://www.nebula-graph.com.cn/demo

欢迎在 NebulaGraph 官网体验多场景 Demo,亲自动手验证图数据库的能力~

一、图模型设计

💡在实际使用中,可对 Schema 进行相应修改与管理,为便于在线体验,本 Demo 暂不支持。

在正式推理开始前,我们得先知道上文提到的关系网是怎么搭起来的。

你可以把这张网想象成三个简单的部分:

  • 人(节点):代表每个用户。

  • 关系(边):“好友”、“关注”、“点赞”、“评论”这些让每个用户之间,产生关系的互动行为。

  • 内容/社群/Tag(节点):比如一篇“旅游攻略”,或者一个“篮球爱好者群”。

💡在真实的业务里, 社群通常可以作为用户的一个属性来存储。但在我们这个演示里,特意将其单独建模成了一个节点。这是为了让你更直观地看清“用户 – 社群 – 内容”这条完整链条,感受图数据库在多跳关系查询上的优势。实际生产环境里,完全可以根据业务需求灵活调整模型。

图数据库要做的,就是把它们之间千丝万缕的联系,全部存进去,并且让这些关系可以被随时查询和分析。

节点类型包括下表:

边类型包括下表:

了解完图数据库要做什么后,我们首先要在图数据库中,把基本规则创建起来。

首先,创建图类型与图空间,并执行以下语句定义节点、边结构及属性:

CREATE GRAPH TYPE IF NOT EXISTS `social_recommendation` AS {  NODE TYPE `Person` (LABEL `Person`{`person_id` STRING NOT NULL`name` STRING DEFAULT NULL`city` STRING DEFAULT NULL`register_time` ZONED DATETIME DEFAULT NULLPRIMARY KEY (`person_id`)}),  NODE TYPE `Community` (LABEL `Community`{`community_id` STRING NOT NULL`name` STRING DEFAULT NULL`topic` STRING DEFAULT NULL`created_time` ZONED DATETIME DEFAULT NULLPRIMARY KEY (`community_id`)}),  NODE TYPE `Content` (LABEL `Content`{`content_id` STRING NOT NULL`title` STRING DEFAULT NULL`category` STRING DEFAULT NULL`publish_time` ZONED DATETIME DEFAULT NULLPRIMARY KEY (`content_id`)}),  NODE TYPE `UserTag` (LABEL `UserTag`{`tag_name` STRING NOT NULLPRIMARY KEY (`tag_name`)}),  EDGE TYPE `Friend` (`Person`)-[LABEL `Friend`{`since_time` ZONED DATETIME NOT NULL`closeness` DOUBLE DEFAULT NULLMULTIEDGE KEY(`since_time`)}]->(`Person`),  EDGE TYPE `MemberOf` (`Person`)-[LABEL `MemberOf`{`join_time` ZONED DATETIME NOT NULL`role_name` STRING DEFAULT NULLMULTIEDGE KEY(`join_time`)}]->(`Community`),  EDGE TYPE `Forward` (`Person`)-[LABEL `Forward`{`forward_time` ZONED DATETIME NOT NULL`action_weight` DOUBLE DEFAULT NULLMULTIEDGE KEY(`forward_time`)}]->(`Content`),  EDGE TYPE `Like` (`Person`)-[LABEL `Like`{`like_time` ZONED DATETIME NOT NULL`score` DOUBLE DEFAULT NULLMULTIEDGE KEY(`like_time`)}]->(`Content`),  EDGE TYPE `Comment` (`Person`)-[LABEL `Comment`{`comment_time` ZONED DATETIME NOT NULL`content_text` STRING DEFAULT NULLMULTIEDGE KEY(`comment_time`)}]->(`Content`),  EDGE TYPE `FollowKOL` (`Person`)-[LABEL `FollowKOL`{`follow_time` ZONED DATETIME NOT NULL`interaction_level` DOUBLE DEFAULT NULLMULTIEDGE KEY(`follow_time`)}]->(`Person`),  EDGE TYPE `HasInterest` (`Person`)-[LABEL `HasInterest`{`weight` DOUBLE DEFAULT NULL}]->(`UserTag`),  EDGE TYPE `Cites` (`Content`)-[LABEL `Cites`{`cite_time` ZONED DATETIME DEFAULT NULL}]->(`Content`)};CREATE GRAPH `social_recommendation` :: `social_recommendation`;

二、数据导入

💡本 Demo 仅预置 30 名用户及数千条社交关系,实际导入时,数据量可达千亿级甚至更多。

定义完“规则”,我们执行以下语句,导入数据。
-- 导入用户节点TABLE `person_data` { `person_id`, `name`, `city`, `register_time` } = ("p001""Alice""Beijing""2024-01-05T09:00:00 +0800"), ("p002""Bob""Beijing""2024-01-06T10:30:00 +0800"), ("p003""Charlie""Beijing""2024-01-07T11:00:00 +0800"), ("p004""David""Beijing""2024-01-08T14:20:00 +0800"), ("p005""Evan""Beijing""2024-01-09T15:00:00 +0800"), ("p006""Fiona""Beijing""2024-01-10T16:45:00 +0800"), ("p007""George""Beijing""2024-01-11T09:15:00 +0800"), ("p008""Hannah""Beijing""2024-01-12T10:30:00 +0800"), ("p009""Ivan""Beijing""2024-01-13T11:45:00 +0800"), ("p010""Julia""Beijing""2024-01-14T13:00:00 +0800"),("p011""Kevin""Shanghai""2024-01-15T09:00:00 +0800"), ("p012""Linda""Shanghai""2024-01-16T10:30:00 +0800"), ("p013""Mike""Shanghai""2024-01-17T11:00:00 +0800"), ("p014""Nancy""Shanghai""2024-01-18T14:20:00 +0800"), ("p015""Oscar""Shanghai""2024-01-19T15:00:00 +0800"), ("p016""Paula""Shanghai""2024-01-20T16:45:00 +0800"), ("p017""Quinn""Shanghai""2024-01-21T09:15:00 +0800"), ("p018""Rachel""Shanghai""2024-01-22T10:30:00 +0800"), ("p019""Steve""Shanghai""2024-01-23T11:45:00 +0800"), ("p020""Tina""Shanghai""2024-01-24T13:00:00 +0800"),("p021""Uma""Hangzhou""2024-01-25T09:00:00 +0800"), ("p022""Victor""Hangzhou""2024-01-26T10:30:00 +0800"), ("p023""Wendy""Hangzhou""2024-01-27T11:00:00 +0800"), ("p024""Xavier""Hangzhou""2024-01-28T14:20:00 +0800"), ("p025""Yvonne""Hangzhou""2024-01-29T15:00:00 +0800"), ("p026""Zack""Hangzhou""2024-01-30T16:45:00 +0800"), ("p027""Amy""Hangzhou""2024-01-31T09:15:00 +0800"), ("p028""Brian""Hangzhou""2024-02-01T10:30:00 +0800"), ("p029""Cathy""Hangzhou""2024-02-02T11:45:00 +0800"), ("p030""Derek""Hangzhou""2024-02-03T13:00:00 +0800")USE `social_recommendation`FOR re IN `person_data`INSERT (@`Person` {`person_id`: re.`person_id`, `name`: re.`name`, `city`: re.`city`, `register_time`: CAST(re.`register_time` AS ZONED DATETIME)})-- 导入社群节点TABLE `community_data` { `community_id`, `name`, `topic`, `created_time` } = ("c001""AI与大模型研究""Technology""2023-12-01T08:00:00 +0800"), ("c002""电商运营交流""Business""2023-12-05T09:00:00 +0800"), ("c003""硬核数码科技""Hardware""2023-12-10T10:00:00 +0800"), ("c004""城市慢生活""Lifestyle""2023-12-15T11:00:00 +0800")USE `social_recommendation`FOR re IN `community_data`INSERT (@`Community` {`community_id`: re.`community_id`, `name`: re.`name`, `topic`: re.`topic`, `created_time`: CAST(re.`created_time` AS ZONED DATETIME)})-- 导入内容节点TABLE `content_data` { `content_id`, `title`, `category`, `publish_time` } = ("ct001""图数据库在AI时代的机遇""Tech""2024-03-01T08:00:00 +0800"), ("ct002""2024电商新风向标""Business""2024-03-02T09:00:00 +0800"), ("ct003""深度解析PageRank算法""Tech""2024-03-03T10:00:00 +0800"), ("ct004""我的极简桌面搭配""Life""2024-03-04T11:00:00 +0800"), ("ct005""机械键盘轴体科普""Hardware""2024-03-05T12:00:00 +0800"),("ct006""LLM微调实战指南""Tech""2024-03-06T13:00:00 +0800"), ("ct007""直播带货的底层逻辑""Business""2024-03-07T14:00:00 +0800"), ("ct008""周末探店:魔都咖啡""Life""2024-03-08T15:00:00 +0800"), ("ct009""显卡选购避坑指南""Hardware""2024-03-09T16:00:00 +0800"), ("ct010""如何高效管理时间""Life""2024-03-10T17:00:00 +0800")USE `social_recommendation`FOR re IN `content_data`INSERT (@`Content` {`content_id`: re.`content_id`, `title`: re.`title`, `category`: re.`category`, `publish_time`: CAST(re.`publish_time` AS ZONED DATETIME)})
数据导入完成后,社交数据在图数据库里就变成了这样一张图(Graph)。

三、关键查询示例

在 NebulaGraph Demo 的 console 界面中,输入图数据库查询语句,点击 run 按钮,系统就会执行一段查询指令,并把结果以可视化关系图的形式呈现出来。
比如每个用户是一个小圆点,关系是连接圆点的线条。你可以拖拽、缩放这张图,直观地看到人与人之间的连接路径,让推荐结果看得见、摸得着。
在这里,我们用四类查询语句和对应的可视化页面,进一步让你了解图数据库是如何让社交软件,精准推荐「你可能认识的人」。

💡在 Demo 中,已经完成了 schema 设计和数据导入,大家可以在 console 页面,任意探索社交场景的不同语句、玩法。

1. 查找某人的 1-3 度好友

目的:全面掌握目标用户的社交网络范围,发现潜在的兴趣传播路径和社群影响力范围。

USE `social_recommendation`MATCH p=(src@`Person` {`person_id`"p001"})-[:`Friend`]-{1,3}(friend)RETURN p

基于图的解释该图展示了从用户 p001 出发,经过 1 到 3 跳好友关系能到达的所有用户节点及路径。

2. 熟人好友推荐

目的基于“朋友的朋友是朋友”的社交理论,通过共同好友数量为用户推荐可能认识的人。

USE `social_recommendation`MATCH (src@`Person` {`person_id`"p001"})-[:`Friend`]-(mutual_friend)-[:`Friend`]-(candidate)WHERE candidate.`person_id` <> "p001" // 排除自己  AND NOT EXISTS((src)-[:`Friend`]-(candidate)) // 排除已经是好友的人RETURN candidate.`person_id` AS recommended_friend,        candidate.`name` AS name,        count(mutual_friend) AS mutual_friends_countORDER BY mutual_friends_count DESC LIMIT 10

基于表格的解释为用户 p001 推荐共同好友最多的前 10 位潜在朋友。mutual_friends_count 越高,推荐的理由越充分,用户接受推荐的概率越大。

3. 兴趣社群推荐 (基于朋友圈子)

目的通过分析用户好友的社群加入行为,推测用户可能也感兴趣的社群,实现社群推荐。

USE `social_recommendation`MATCH (src@`Person` {`person_id`"p001"})-[:`Friend`]-(friend)-[:`MemberOf`]-(community)WHERE NOT EXISTS((src)-[:`MemberOf`]-(community))RETURN community.`name` AS community_name,        community.`topic` AS topic,        count(friend) AS friends_joined_countORDER BY friends_joined_count DESC LIMIT 5

基于表格的解释为用户 p001 推荐其好友们最常加入的 5 个社群。friends_joined_count 越高,说明该社群在当前用户的社交圈子中越流行,推荐价值越高。

4. 基于相似行为的内容推荐

目的找到与目标用户有相同转发行为的相似用户,然后将这些相似用户点赞过的其他内容推荐给目标用户,实现协同过滤推荐。

USE `social_recommendation`MATCH (src@`Person` {`person_id`: "p002"})-[:`Forward`]->(common_content)<-[:`Forward`]-(similar_user)-[:`Like`]->(recommended_content)WHERE NOT EXISTS((src)-[:`Like`]->(recommended_content))  AND NOT EXISTS((src)-[:`Forward`]->(recommended_content))RETURN recommended_content.`title` AS content_title,        similar_user.`name` AS liked_by_user,        count(common_content) AS similarity_scoreORDER BY similarity_score DESC LIMIT 10

基于表格的解释为用户 p002 推荐由与其转发行为最相似的 10 位用户所喜欢的内容。similarity_score 代表推荐内容与用户兴趣的相似度权重,liked_by_user 字段提供了推荐理由。

四、总结

综上所述,图数据库的核心理念其实并不复杂,其实就是将“人与人”、“人与内容”之间的关系作为一等公民进行存储与计算。然而,正是这一思路的转变,为推荐系统带来了质的变化。

回顾前文所述的所有查询示例,可以清晰地看到,借助 NebulaGraph 构建的社交兴趣关联网络,推荐系统在以下四个维度上实现了显著提升:

1. 发现多层社交路径突破传统推荐系统局限于个体历史行为的视野,图数据库可沿好友、关注等链路穿透至三度、四度关系,挖掘深层社交联系与影响力传导路径。

2. 提供可量化指标基于共同好友数、相似行为频次等结构化数据,为每条推荐提供可量化的信任度依据,如“你们有8位共同好友”,让推荐结果有据可循。

3. 统一查询模式熟人推荐、社群推荐、协同过滤等多样化策略,均可通过图数据库的统一查询语言实现,无需为每种逻辑单独搭建技术栈,显著降低开发复杂度。

4. 天然路径回溯图数据库可清晰展示推荐结果的完整产生链路(如“A的好友B点赞了C,故推荐C给A”),为策略优化与用户沟通提供透明化支撑。

总而言之,图数据库以一种更贴近人类认知直觉的方式,将世界视作一张相互连接的网络,正是这一视角的转换,使社交推荐从“猜你喜欢”进化为“基于关系的精准匹配”。如果您的产品正面临社交推荐的效率瓶颈,不妨从绘制一张关系图谱开始探索新的可能。

💡本 Demo 展示了基础查询,仅作为简单场景下的 NebulaGraph 使用参考。在实际生产环境中,还可结合 PageRank、标签传播、连通分量等图算法,实现更智能的社区发现与兴趣扩散。

如果你觉得 NebulaGraph 能帮到你,或者你只是单纯支持开源精神,可以在 GitHub 上为 NebulaGraph 点个 Star!

每一个 Star 都是对我们的支持和鼓励✨

GitHub:https://github.com/vesoft-inc/nebula

官网:https://www.nebula-graph.com.cn/

论坛:https://discuss.nebula-graph.com.cn/

扫码添加

 可爱星云

技术交流

资料分享

✨ NebulaGraph 推荐阅读

NebulaGraph 用户案例

Why Graph Database?⬇️

复杂关系场景,图数据库为何是首选?

风控场普适智能|中证数智BlockSec携程Airwallex众安保险中国移动Akulaku邦盛科技360数科BOSS直聘金蝶征信快手青藤云安全

平台建设:博睿数据携程众安科技微信OPPOvivo美团百度爱番番携程金融普适智能BIGO

知识图谱:普适智能|中证数智中医药大学企查查腾讯音乐中科大脑泰康在线苏宁微澜同花顺携程酒店

数据血缘:波克城市微众银行携程金融

智能运维BOSS直聘|58同城中亦安图

供应链:京东物流震坤行

营销推荐:阿里妈妈

GraphRAG:中科数睿