基于Spark Grahpx+Neo4j 实现用户社群发现
上一篇文章知识图谱在大数据中的应用我们介绍了知识图谱的一些概念和应用场景,今天我们就来看一个具体的应用案例了解下知识图谱的应用。用户增长对于一个APP的生存起到了至关重要的作用,没有持续的用户增长,再好的APP也不会走的长远,为了获得更多的用户,APP运营商往往会鼓励老用户拉新并给与奖励,比如趣头条的收徒模式,用户每收一个徒弟就会得到几块到十几块的现金返现,但是这种模式同时也会引起广大黑产团伙的注意,黑产会利用各种手段来薅这些APP运营商的羊毛。
中国有句老话,叫物以类聚,人以群分,在反作弊和市场营销等应用中,如果我们能根据用户间的某些联系发现社群,然后对这些社群进行反作弊分析或商品推荐,往往会起到意想不到的效果。
本文就来介绍一个简单的社群发现的实践。构建社群我们首先需要找到社群用户的某种联系,上文提到的收徒模式本身就是用户间的一个天然联系,我们可以根据用户的师徒关系来构建社群。如下图所示,根据师徒关系我们构建了一个社群,点表示用户,边表示师徒关系。
有了这样的社群之后,我们就可以基于社群维度分析设备及用户行为的异常,比如单个设备登陆过多的用户,设备一直处于充电状态,所有用户行为高度一致等,同时可以计算社群用户作弊率来通过已知作弊用户来发现新的作弊用户。
理清了需求之后我们开始着手根据用户师徒关系构建社群。对"紧密联系"的不同理解产生了很多社区发现算法。下图是几种经典的社群发现算法。
社群算法
- Triangle Counting:三角关系,图论基础知识。
- Connected Components:连通图,图论基础知识。
- Strongly Connected Components:强连通图,图论基础知识。
- Label Propagation:标签传播算法。
- Louvain:一种基于"模块度"的经典算法。
因为本文重点不是讲述社群发现算法,所以这个算法具体的含义此处略过,有感兴趣的读者可自行研究。本文选用了最简单的连通图算法来实现社群发现,即只要两个节点之间有边我们就把它们归属为一个社群。下面我们进入根据用户师徒关系生成社群阶段。
Spark Graphx构建社群
Spark Graphx本身就提供了构建图并生成连通图的接口,我们只需要按要求输入数据就好了。如下图所示:
我们构建点和边,然后调用Graphx接口生成图,最后调用图的接口直接获取连通图。需要注意的是,Spark Graphx构建点和边时,id需要用Long类型的数字表示,所以我们需要维护一张用户id到数字id的维表。
//构建用户节点
val users: RDD[(VertexId, String)] =
spark.sparkContext.parallelize(Array((3L, "u3"), (7L, "u7"),(5L, "u5"), (2L, "u2"), (4L, "u4"),(6L, "u6"),(8L, "u8")))
//构建用户边
val relationships: RDD[Edge[String]] =
spark.sparkContext.parallelize(Array(Edge(7L, 3L,""), Edge(5L, 3L,""),Edge(5L, 2L,""), Edge(6L, 4L,""),Edge(8L, 6L,"")))
//组合节点和边构建图
val graph = Graph(users, relationships)
//从图中抽取出连通图
val components = graph.connectedComponents()
//获取连通图中的点,vertices是一个tuple类型,key分别为所有的顶点id,value为key所在的连通图id(连通图中顶点id最小值)
val vertices = components.vertices
得到的vertices是如下的k-v数据:
/**
* vertices:
* (6,4)
* (8,4)
* (3,2)
* (7,2)
* (5,2)
*
* 是一个tuple类型,key分别为所有的顶点id,value为key所在的连通图id(连通图中顶点id最小值)
*/
然后我们将边relationships与vertices求出每条边所在连通图里顶点id最小值。
val result = relationships.map(x =>{
(x.srcId,x.dstId.toString)
}).join(vertices)
.map(y =>{
// (7,(3,2)) => (2,(7,3))
(y._2._2,(y._1,y._2._1))
})
我们将结果存入图数据Neo4j,可视化后如下所示,可以看到我们得到了两个社群。
至此,我们利用Spark Graphx构建出了社群,每个社群都有自己的一个社群id,然后我们就可以基于社群做一些具体分析了,比如,我可以计算社群作弊率,并取出TOP N的社群,如下所示。
想及时了解更多大数据实践,请关注我的公众号《大数据技术进阶》
上面只是一个简单的示例,其实我们可以给点和边加上更多的属性,利用图的特性进行检索,可以更高效的检索出更多的信息。为了更方便的存储和查询社群内的数据,我们可以将社群存储到图数据库Neo4j。上面的社群图就是用Neo4j展示的,那么什么是Neo4j呢?下面我们简单的介绍下。
Neo4j简介
Neo4j是一个嵌入式的、基于磁盘的、具备完全的事务特性的图数据存储引擎。作为图数据库,Neo4j最大的特点是关系数据的存储。图数据库除了能够像普通的数据库一样存储一行一行的数据之外,还可以很方便的存储数据之间的关系信息。
例如,对于一个社交网络的用户数据库,你除了要存储每个用户的姓名、性别、喜好这些基本信息外,你还需要存储一个用户和哪些用户是朋友,和哪个用户是情侣这些关系数据,这个时候Neo4j这样的图数据库就可以派上用场啦。
通过下图,大家可以了解下什么是图数据库以及什么是关系数据。
在上图中,包含两个标签为"人"的数据节点,分别代表Ann和Dan两个用户。这两个数据节点还包含姓名、出生地等属性信息,用于表示两个用户的基本信息,就如同常规数据库中的两行数据。
除此之外,两个数据节点之间还包含两条关系数据,即Ann嫁给了Dan,Ann和Dan同居。利用这些关系数据,你就可以方便的作出基于关系的查询,例如你可以查询Ann跟谁结婚了,这就是图数据库的优势。
可能有人会说,上边写的这种关系数据结构,SQL也可以通过多表join等方法实现,那要Neo4j还有什么用?但毕竟术业有专攻,对于大量、复杂的关系数据处理,Neo4j在性能和使用方便程度上都是要远胜于SQL的。下边给大家简单总结下Neo4j的特点。
Neo4j的特点
- 像SQL一样的查询语言cypher
- 它遵循属性图数据模型
- 它通过使用Apache Lucence支持索引
- 它支持UNIQUE约束
- 它包含一个用于执行cypher命令的UI:Neo4j数据浏览器
- 它支持完整的ACID(原子性,一致性,隔离性和持久性)规则
- 它支持查询的数据导出到JSON和XLS格式
- 它提供了REST API,可以被任何编程语言(如Java,Spring,Scala等)访问
- 它提供了可以通过任何UI MVC框架(如Node JS)访问的Java脚本
- 它支持两种Java API:Cypher API和Native Java API来开发Java应用程序
- 支持高可用性主从集群部署。
Cypher语言
Cypher是Neo4j的图形查询语言,关键字大小写不敏感。语法和SQL很像,学起来相对简单。
基本格式
MATCH WHERE RETURN模式
() 表示节点
[] 表示关系,关系是有向的,连接的点分为源点和目标点
{} 表示属性,每个属性通过key:value的形式表示,多个属性之间用逗号隔开,关系也可以有属性标签
用来标识一个节点属于哪一类。一个节点可以有多个或0个标签。标签没有属性。
node:label1:label2 通过冒号给节点添加标签,通过冒号分隔多个标签基本的增删改查
插入一个节点
CREATE (n:Person {name : 'Andres'});
插入一条边
MATCH (a:Person),(b:Person) WHERE a.name = 'Node A' AND b.name = 'Node B‘ CREATE (a)-[r:Follow]->(b);
更新节点
MATCH (n:Person { name: 'Andres' }) SET n.name = 'Taylor';
删除节点
MATCH (n:Person { name:'Taylor' }) DETACH DELETE n;
删除边
MATCH (a:Person)-[r:Follow]->(b:Person) WHERE a.name = 'Node A' AND b.name = 'Node B‘ DELETE r;
查询一个节点的所有Follow
MATCH (:Person { name:'Taylor' })-[r:Follow]->(Person) RETURN Person.name;
查询一个节点最短路径
MATCH (ms:Person { name:'Node A' }),(cs:Person { name:'Node B' }), p = shortestPath((ms)-[r:Follow]-(cs)) RETURN p;
清空数据库
MATCH (n) DETACH DELETE n
Neo4j数据浏览器
通过Neo4j浏览器就可以直接进行图的查询。
Cypher演示示例
我们使用Cypher查询语言对Neo4j中的一个家庭进行建模,包括年龄,性别和家庭成员之间的关系等个人属性。我们创建了一些朋友来扩大我们的社交图,然后添加键/值对来生成每个用户看过的电影列表。最后,我们查询了我们的数据,使用图形分析来搜索一个用户没有看到但可能喜欢的电影。
创建家庭成员节点及关系
CREATE (person:Person {name: "Steven", age: 45}) RETURN person
CREATE (person:Person {name: "Michael", age: 16}) RETURN person
CREATE (person:Person {name: "Rebecca", age: 7}) RETURN person
CREATE (person:Person {name: "Linda",age:40}) RETURN person
MATCH (steven:Person {name: "Steven"}), (linda:Person {name: "Linda"}) CREATE (steven)-[:IS_MARRIED_TO]->(linda) return steven, linda
MATCH (michael:Person {name: "Michael"}), (rebecca:Person {name: "Rebecca"}) CREATE (michael)-[:IS_SIBLILNG]->(rebecca) return michael, rebecca
MATCH (steven:Person {name: "Steven"}), (michael:Person {name: "Michael"}) CREATE (steven)-[:HAS_CHILD]->(michael) return steven, michael
MATCH (steven:Person {name: "Steven"}), (rebecca:Person {name: "Rebecca"}) CREATE (steven)-[:HAS_CHILD]->(rebecca) return steven, rebecca
MATCH (linda:Person {name: "Linda"}), (michael:Person {name: "Michael"}) CREATE (linda)-[:HAS_CHILD]->(michael) return linda, michael
MATCH (linda:Person {name: "Linda"}), (rebecca:Person {name: "Rebecca"}) CREATE (linda)-[:HAS_CHILD]->(rebecca) return linda, Rebecca
添加朋友节点及关系,组成社交网络
MATCH (michael:Person {name: "Michael"}) CREATE (michael)-[:FRIEND]->(charlie:Person {name: "Charlie", age: 16}) RETURN michael, charlie
MATCH (michael:Person {name: "Michael"}) CREATE (michael)-[:FRIEND]->(koby:Person {name: "Koby"}) RETURN michael, koby
MATCH (michael:Person {name: "Michael"}) CREATE (michael)-[:FRIEND]->(grant:Person {name: "Grant"}) RETURN michael, grant
MATCH (rebecca:Person {name: "Rebecca"}) CREATE (rebecca)-[:FRIEND]->(jordyn:Person {name: "Jordyn"}) RETURN rebecca, jordyn
MATCH (rebecca:Person {name: "Rebecca"}) CREATE (rebecca)-[:FRIEND]->(katie:Person {name: "Katie"}) RETURN rebecca, katie
添加电影节点及关系,并携带打分属性
CREATE (movie:Movie {title:"Avengers"}) RETURN movie
MATCH (michael:Person {name:"Michael"}), (avengers:Movie {title:"Avengers"}) CREATE (michael)-[:HAS_SEEN {rating:5}]->(avengers) return michael, avengers
CREATE (movie:Movie {title:"Batman"}) RETURN movie
CREATE (movie:Movie {title:"Gone with the Wind"}) RETURN movie
CREATE (movie:Movie {title:"Spongebob Square Pants"}) RETURN movie
CREATE (movie:Movie {title:"Avengers 2"}) RETURN movie
MATCH (charlie:Person {name:"Charlie"}), (movie:Movie {title:"Batman"}) CREATE (charlie)-[:HAS_SEEN {rating:4}]->(movie) return charlie, movie
MATCH (charlie:Person {name:"Charlie"}), (movie:Movie {title:"Gone with the Wind"}) CREATE (charlie)-[:HAS_SEEN {rating:0}]->(movie) return charlie, movie
MATCH (koby:Person {name:"Koby"}), (movie:Movie {title:"Batman"}) CREATE (koby)-[:HAS_SEEN {rating:4}]->(movie) return koby, movie
MATCH (koby:Person {name:"Koby"}), (movie:Movie {title:"Avengers 2"}) CREATE (koby)-[:HAS_SEEN {rating:5}]->(movie) return koby, movie
MATCH (grant:Person {name:"Grant"}), (movie:Movie {title:"Spongebob Square Pants"}) CREATE (grant)-[:HAS_SEEN {rating:1}]->(movie) return grant, movie
MATCH (jordyn:Person {name:"Jordyn"}), (movie:Movie {title:"Spongebob Square Pants"}) CREATE (jordyn)-[:HAS_SEEN {rating:5}]->(movie) return jordyn, movie
MATCH (michael:Person {name: "Michael"}) SET michael.gender = "male" RETURN michael
MATCH (rebecca:Person {name: "Rebecca"}) SET rebecca.gender = "female" RETURN rebecca
最后我们通过下面语句查询steven的孩子的男性朋友看过而且打分大于3分的电影
MATCH (steven:Person {name:"Steven"})-[:HAS_CHILD]-(child:Person)-[:FRIEND]-(friend:Person)-[hasSeen:HAS_SEEN]-(movie:Movie) WHERE child.gender = "male" AND hasSeen.rating > 3 RETURN DISTINCT movie.title
总结
本文主要介绍了利用Spark Graphx实现了一个简单的连通图社群发现示例,并将社群存入到图数据库Neo4j中,同时进一步介绍了Neo4j的一些概念和使用,最后用Neo4j演示了一个社交网络的图检索示例。
想及时了解更多大数据实践,请关注我的公众号《大数据技术进阶》
基于Spark Grahpx+Neo4j 实现用户社群发现的更多相关文章
- 基于Spark的用户行为路径分析
研究背景 互联网行业越来越重视自家客户的一些行为偏好了,无论是电商行业还是金融行业,基于用户行为可以做出很多东西,电商行业可以归纳出用户偏好为用户推荐商品,金融行业可以把用户行为作为反欺诈的一个点,本 ...
- 客户流失?来看看大厂如何基于spark+机器学习构建千万数据规模上的用户留存模型 ⛵
作者:韩信子@ShowMeAI 大数据技术 ◉ 技能提升系列:https://www.showmeai.tech/tutorials/84 行业名企应用系列:https://www.showmeai. ...
- 苏宁基于Spark Streaming的实时日志分析系统实践 Spark Streaming 在数据平台日志解析功能的应用
https://mp.weixin.qq.com/s/KPTM02-ICt72_7ZdRZIHBA 苏宁基于Spark Streaming的实时日志分析系统实践 原创: AI+落地实践 AI前线 20 ...
- 京东基于Spark的风控系统架构实践和技术细节
京东基于Spark的风控系统架构实践和技术细节 时间 2016-06-02 09:36:32 炼数成金 原文 http://www.dataguru.cn/article-9419-1.html ...
- 基于Spark ALS构建商品推荐引擎
基于Spark ALS构建商品推荐引擎 一般来讲,推荐引擎试图对用户与某类物品之间的联系建模,其想法是预测人们可能喜好的物品并通过探索物品之间的联系来辅助这个过程,让用户能更快速.更准确的获得所需 ...
- 大数据实时处理-基于Spark的大数据实时处理及应用技术培训
随着互联网.移动互联网和物联网的发展,我们已经切实地迎来了一个大数据 的时代.大数据是指无法在一定时间内用常规软件工具对其内容进行抓取.管理和处理的数据集合,对大数据的分析已经成为一个非常重要且紧迫的 ...
- 基于 Spark 的文本情感分析
转载自:https://www.ibm.com/developerworks/cn/cognitive/library/cc-1606-spark-seniment-analysis/index.ht ...
- 基于微信小程序的用户列表点赞功能
代码地址如下:http://www.demodashi.com/demo/13997.html 一.前言 (1).适合人群 1.微信小程序开发者 2.前端工程师 3.想入门学习小程序开发的人员 4.想 ...
- 基于Spark的电影推荐系统(电影网站)
第一部分-电影网站: 软件架构: SpringBoot+Mybatis+JSP 项目描述:主要实现电影网站的展现 和 用户的所有动作的地方 技术选型: 技术 名称 官网 Spring Boot 容器 ...
随机推荐
- 10 关于DOM的操作
一.JavaScript的组成 JavaScript基础分为三个部分: ECMAScript:JavaScript的语法标准.包括变量.表达式.运算符.函数.if语句.for语句等. DOM:文档对象 ...
- webapi使用autofac
注意:您的项目中如果使用的是webapi2,此处必须为webapi2而不是webapi,否则在运行时将出现“重写成员“Autofac.Integration.WebApi.AutofacWebApiD ...
- 系统学习 Java IO (六)----管道流 PipedInputStream/PipedOutputStream
目录:系统学习 Java IO---- 目录,概览 PipedInputStream 类使得可以作为字节流读取管道的内容. 管道是同一 JVM 内的线程之间的通信通道. 使用两个已连接的管道流时,要为 ...
- vuex中使用对象展开运算符
使用场景 当需要进行vuex进行数据状态管理的时候,会使用到mapGetters,mapState,还有自身的计算属性的时候,这个时候就会用到这个了! 1.首先需要安装 npm install bab ...
- Java并发之Semaphore和Exchanger工具类简单介绍
一.Semaphore介绍 Semaphore意思为信号量,是用来控制同时访问特定资源的线程数数量.它的本质上其实也是一个共享锁.Semaphore可以用于做流量控制,特别是公用资源有限的应用场景.例 ...
- 如何配置selinux
参考命令: 一.开启/关闭selinux getenforce:查看selinux运行状态 setenforce 0 :关闭selinux setenforce 1 :开启selinux 系统 ...
- linux 多主机间快速跳转脚本
#!/usr/bin/env python #coding=utf8 ''' 用于多机器间相互跳转,如有新机器加入,需要更新ip_list文件 ''' from prettytable import ...
- Ural 2064:Caterpillars(思维暴力)
http://acm.timus.ru/problem.aspx?space=1&num=2064 题意:有n只虫子在爬树,每个虫子往上爬ti距离后会往下掉落ti距离,每爬一个单位距离耗费一个 ...
- 玲珑OJ 1082:XJT Loves Boggle(爆搜)
http://www.ifrog.cc/acm/problem/1082 题意:给出的单词要在3*3矩阵里面相邻连续(相邻包括对角),如果不行就输出0,如果可行就输出对应长度的分数. 思路:爆搜,但是 ...
- 微信开发:微信js_sdk 分享,前端部分(二)
微信开发:微信js-sdk前端分享,代码如下: <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"> ...