使用HGraphDB进行二度好友推荐

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 Tair(兼容Redis),内存型 2GB
简介: 业务场景 某社交软件,需要基于用户的好友关系向用户做二度人脉的推荐。系统中保存的关系有两种,一种是A用户的通讯录中保存了B用户的电话号码,另一种是A用户在app上面关注了B用户。以下图所示的关系为例: 张三和王五,李四,赵六是好友,我们需要向张三推荐孙八、杨九和钱七。

业务场景

某社交软件,需要基于用户的好友关系向用户做二度人脉的推荐。
系统中保存的关系有两种,一种是A用户的通讯录中保存了B用户的电话号码,另一种是A用户在app上面关注了B用户。
以下图所示的关系为例:
graph_example

张三和王五,李四,赵六是好友,我们需要向张三推荐孙八、杨九和钱七。

购买HGraphDB服务

在这个例子中,我们使用HGraphDB来实现二度好友推荐的需求。HGaphDB是阿里云HBase产品提供的图存储引擎,基于Apache Tinkerpop栈构建,并使用Gremlin语言进行遍历,更新和查询。HGaphDB图数据库适用于存储、管理、查询复杂并且高度连接的数据,图库的结构特别适合发现大数据集下数据之间的共性和特性,特别善于释放蕴含在数据关系之间的巨大价值。HGaphDB引擎本身并不额外收费,仅收取云hbase费用。
可以参考HGaphDB文档完成实例的购买。

建模

人脉关系是一种典型的图数据结构,而且图可以很方便的进行二度关系的查询,我们可以使用图数据库来实现这个需求。我们把每个用户作为一个顶点,用户之间的关系作为边。
作为一个例子,我们使用Gremlin Console来完成对上述关系的建模,以及示例图的录入。Gremlin Console的安装和配置参见HGraphDB相关文档

按照文档安装并配置好Gremlin Console之后,我们使用如下语句连接到HGraphDB,创建一个新的图:

:remote connect tinkerpop.server conf/remote.yaml session
:remote console
graph = HBaseGraph.open("recommendation","master1-1")
g = graph.traversal()

建立schema:

graph.createLabel(ElementType.VERTEX, "user", ValueType.STRING, "name", ValueType.STRING,"tel", ValueType.STRING)
graph.createLabel(ElementType.EDGE, "tel_relation", ValueType.STRING);
graph.createLabel(ElementType.EDGE, "follow_relation", ValueType.STRING);
graph.connectLabels("user", "tel_relation", "user")
graph.connectLabels("user", "follow_relation", "user")

录入示例图的数据:

zhangsan = g.addV('user').property(T.id, 'user3').property('name','zhangsan').property('tel','13012345673').next()
lisi = g.addV('user').property(T.id, 'user4').property('name','lisi').property('tel','13012345674').next()
wangwu = g.addV('user').property(T.id, 'user5').property('name','wangwu').property('tel','13012345675').next()
zhaoliu = g.addV('user').property(T.id, 'user6').property('name','zhaoliu').property('tel','13012345676').next()
qianqi = g.addV('user').property(T.id, 'user7').property('name','qianqi').property('tel','13012345677').next()
sunba = g.addV('user').property(T.id, 'user8').property('name','sunba').property('tel','13012345678').next()
yangjiu = g.addV('user').property(T.id, 'user9').property('name','yangjiu').property('tel','13012345679').next()

zhangsan.addEdge('tel_relation',lisi)
lisi.addEdge('tel_relation',zhangsan)
zhangsan.addEdge('tel_relation',zhaoliu)
zhaoliu.addEdge('tel_relation',zhangsan)
lisi.addEdge('tel_relation',zhaoliu)
zhaoliu.addEdge('tel_relation',lisi)
lisi.addEdge('tel_relation',qianqi)
qianqi.addEdge('tel_relation',lisi)
zhangsan.addEdge('follow_relation',wangwu)
wangwu.addEdge('tel_relation',sunba)
wangwu.addEdge('follow_relation',yangjiu)

更新

作为一个例子,上面的语句里面,我们一次性把图构建完成了。在生产当中更常见到的情况是,随着系统的运行不断有新用户注册,我们需要更新这个图。例如一个场景是新用户陈十注册,我们通过匹配通讯录发现陈十留过李四的手机号。
为了加快通过手机查用户,我们需要给手机号字段加一个索引:

graph.createIndex(ElementType.VERTEX, "user", "tel",true)

如下语句完成了新用户陈十的注册过程:

chenshi = g.addV('user').property(T.id, 'user10').property('name','chenshi').property('tel','13012345680').next()
lisi = g.V().has("tel","13012345674").next()
chenshi.addEdge('tel_relation',lisi)

陈十关注了王五、赵六:

wangwu = g.V("user5").next()
zhaoliu = g.V("user6").next()
chenshi.addEdge('follow_relation',wangwu)
chenshi.addEdge('follow_relation',zhaoliu)

陈十取关赵六:

g.V('user10').outE('follow_relation').as('e').inV().hasId('user6').select('e').drop()

陈十注销账号:

g.V("user10").drop()

这里通过drop删除顶点后,相应的边也会自动删除。

查询

我们可以用一个简单的语句进行二度人脉的查询:

gremlin> g.V("user3").out().out().valueMap()
==>{name=[yangjiu], tel=[13012345679]}
==>{name=[sunba], tel=[13012345678]}
==>{name=[zhangsan], tel=[13012345673]}
==>{name=[zhangsan], tel=[13012345673]}
==>{name=[zhaoliu], tel=[13012345676]}
==>{name=[qianqi], tel=[13012345677]}
==>{name=[lisi], tel=[13012345674]}

但是这个语句很粗糙,返回的结果里面既有张三自己,也有张三已经认识了的李四、赵六。我们需要过滤掉这些不需要推荐的人:

gremlin> g.V("user3").as('self').out().aggregate('friend').out().where(neq('self')).where(without('friend')).valueMap().dedup()
==>{name=[yangjiu], tel=[13012345679]}
==>{name=[sunba], tel=[13012345678]}
==>{name=[qianqi], tel=[13012345677]}

gremlin查询功能是很强大的,例如我们也可以只给张三推荐他关注的人的好友:

gremlin> g.V("user3").as('self').out("follow_relation").aggregate('friend').out().where(neq('self')).where(without('friend')).valueMap().dedup()
==>{name=[yangjiu], tel=[13012345679]}
==>{name=[sunba], tel=[13012345678]}

判断两个人是不是好友:

gremlin> g.V("user3").outE().as("e").inV().hasId("user4").select("e")
==>e[0e4e63a3-638a-4dd9-8087-59e819896576][user3-tel_relation->user4]

有没有关注过:

gremlin> g.V("user3").outE("follow_relation").as("e").inV().hasId("user4").select("e")
gremlin>
目录
相关文章
|
机器学习/深度学习 编解码 人工智能
Reading Notes: Human-Computer Interaction System: A Survey of Talking-Head Generation
由于人工智能的快速发展,虚拟人被广泛应用于各种行业,包括个人辅助、智能客户服务和在线教育。拟人化的数字人可以快速与人接触,并在人机交互中增强用户体验。因此,我们设计了人机交互系统框架,包括语音识别、文本到语音、对话系统和虚拟人生成。接下来,我们通过虚拟人深度生成框架对Talking-Head Generation视频生成模型进行了分类。同时,我们系统地回顾了过去五年来在有声头部视频生成方面的技术进步和趋势,强调了关键工作并总结了数据集。 对于有关于Talking-Head Generation的方法,这是一篇比较好的综述,我想着整理一下里面比较重要的部分,大概了解近几年对虚拟人工作的一些发展和
|
10月前
|
存储 设计模式 安全
Go语言中的并发编程:从入门到精通###
本文深入探讨了Go语言中并发编程的核心概念与实践技巧,旨在帮助读者从理论到实战全面掌握Go的并发机制。不同于传统的技术文章摘要,本部分将通过一系列生动的案例和代码示例,直观展示Go语言如何优雅地处理并发任务,提升程序性能与响应速度。无论你是Go语言初学者还是有一定经验的开发者,都能在本文中找到实用的知识与灵感。 ###
kettle开发篇-记录关联(笛卡尔积)
kettle开发篇-记录关联(笛卡尔积)
446 0
|
SQL 存储 分布式计算
MaxCompute 入门:大数据处理的第一步
【8月更文第31天】在当今数字化转型的时代,企业和组织每天都在产生大量的数据。有效地管理和分析这些数据变得至关重要。阿里云的 MaxCompute(原名 ODPS)是一个用于处理海量数据的大规模分布式计算服务。它提供了强大的存储能力以及丰富的数据处理功能,让开发者能够快速构建数据仓库、实时报表系统、数据挖掘等应用。本文将介绍 MaxCompute 的基本概念、架构,并演示如何开始使用这一大数据处理平台。
1630 0
|
负载均衡 Ubuntu Java
nacos常见问题之升级到2.1.0重启后端服务如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
437 1
|
关系型数据库 MySQL Shell
Mac安装Mysql(图文解说详细版)
Mac安装Mysql(图文解说详细版)
Mac安装Mysql(图文解说详细版)
|
弹性计算 运维 监控
高弹性、高可用、低成本的云上资源管理最佳实践
阿里云弹性计算团队十三位产品专家和技术专家共同分享云上运维深度实践,详细阐述如何利用CloudOps工具实现运维提效、弹性降本。
高弹性、高可用、低成本的云上资源管理最佳实践
|
SQL 资源调度 分布式计算
Flink 1.16:Hive SQL 如何平迁到 Flink SQL
Apache Flink PMC&Committer 伍翀(云邪)在 9.24 Apache Flink Meetup 的演讲内容整理。
Flink 1.16:Hive SQL 如何平迁到 Flink SQL
|
机器学习/深度学习 人工智能 自然语言处理
NAACL2021 AMR-IE: Abstract Meaning Representation Guided Graph Encoding and Decoding for Joint IE
富语义解析的任务,如抽象语义表示(AMR),与信息抽取(IE)具有相似的目标,即将自然语言文本转换为结构化的语义表示。为了利用这种相似性
473 0