Neo4j 图数据库在社交网络等领域的应用

一、前言

Neo4j 是一种基于图论实现的新型 NoSQL 数据库。这种数据库,在处理社交网络,物流运输,推荐系统,欺诈检测等,关系分析等领域有着巨大优势。本场 Chat,我将为你介绍:

  1. Neo4j 与关系型、其他非关系型数据库的优势比较
  2. 哪些领域适合 Neo4j,哪些领域不适合
  3. Neo4j 的安装
  4. 介绍 Cypher 查询语言
  5. 案例实战:
  • 银行欺诈环分析
  • 文献索引
  • 寻找垃圾邮箱源头
  • 企业关系构建
  • 社交关系分析,实现一个简单的好友推荐功能

二、正文

我想,大家对Mysql这种关系型(SQL型)的数据库肯定很熟悉。对MongoDb这种非关系型(NoSQL型)数据库也不会陌生。今天我们要介绍一种新型数据库—图数据库。这种数据库是基于图论实现的。

一提到图论,可能有的小伙伴就会倒吸一口冷气,如果你曾涉及过一些数据结构的知识,会发现图几乎是最难学的,涉及到许多晦涩难懂的算法。这里不用担心,今天介绍的Neo4j把很多算法已经封装好了。不需要你涉及底层,很是方便。下面我们开始对比一下图数据库和其他关系型、非关系型的数据库的优劣。

与传统数据库不同的是,图数据库存的是节点(对象)和边(对象与对象之间的关系)。当数据存在错综复杂的关系时,使用这类数据库是最好的选择。

enter image description here

1. Neo4j 与关系型、其他非关系型数据库的优势比较

(1)Neo4j与关系型数据库的比较

以Mysql为代表的关系型数据库已经诞生了很久了,一直是数据库领域的动力,他们将高度结构化的数据储存在一张张二维表格里,必须严格地按照相关约定对数据进行操作(比如外键约束)。你可以把它理解成一张张账本。

enter image description here

但是,正是因为关系型数据库在建表之前就需要制定相关约定,常常会出现表与表之间有相互制约、相互引用的关系。随着数据库的不断增大,相互制约的关系会不断增多,执行搜索匹配的操作次数将呈现指数增加,进而消耗大量的资源。 举一个例子,当你要查询“小明的朋友”这样的问题,关系层数据库会涉及到一些代价高昂的间接层,比如用索引表查询:

enter image description here

从表里可以发现,小明(ID:2)的朋友是小华(ID:1),你也许会说这并不复杂呀,才一张表而已。

但是要是我问“小明的朋友的朋友的朋友…”这样的深度不断增加,每增加一层就要加一张索引表,这样间接层不断增加。查询就越来越慢,而且所需的内存开销就越来越大。

还有一点,如果我反向问,“谁的朋友是小明”,你可能会说,当然是小华呀。但是你仔细看看索引表,可小华的FriendID是3 不是1(小明)。也就是说,对于这种反向提问,关系型数据库也不能很好处理。

这种反向提问有意义吗?当然有意义,而且很有用,打个比方,小明喜欢编程,那么反向问,谁还喜欢编程。找到喜欢编程里的大神(通过紧密度中心性等属性评判)推荐给小明关注。这样一个简单的推荐功能就出来了。

对比起来,图数据库就有着得天独厚的优势,它储存节点,节点的属性,节点的关系。而这些关系是按类型和方向组织起来的。关系的访问是直接通过节点完成的。问“小明的朋友的朋友的朋友…”,即使深度增加也只是增加节点而已。在复杂连接的查询上,能达到毫秒级别。

怎么理解节点,关系,属性这些概念呢?

这里举个例子,创建一个节点,标签是人,他的名字叫小明。小明就是一个节点。小明喜欢看电影(节点的属性),他和小华是朋友(关系)。这样一个简单的关系就建立了。

enter image description here

(2)Neo4j与其他非关系型数据库比较

目前,大部分的NoSQL数据库都是基于集合和文档的,这些数据被储存在不连贯的集合里,那么这样使得数据间的相互联系,建立关系变得更加困难。也就是说数据是离散的,如果要建立关系,通常会将一个集合嵌到另一个集合里,再来实现关系。这样的开销也很大。但是,这种数据没有太多"关系",使用这种数据库效率特别高,有很好的读写功能。

enter image description here

这篇文章对比了8种不同的NoSQL数据库可以参考

2. 哪些场所适合Neo4j,哪些场所不适合?

在这里,需要说明一下,图数据库不只有Neo4j,但是Neo4j是一个非常优秀的图数据库,03年就开始研发了,07年发布。被许多公司使用,ebay,阿迪达斯,沃尔玛等等。

Neo4j是基于图论实现的,自然在处理地图方面有天然优势,所以,他适用于物流管理,交通大数据。

由于Neo4j的基本元素是节点和关系,它也特别适合处理有复杂关系的社交网络。另外在实现推荐系统上也很有优势,对于分析交易客户数据也很有帮助。它还能用于检测欺诈行为。下文会用一个例子说明。甚至在游戏方面也有运用。比如光荣公司的《三国志13》。

enter image description here

稍微总结适合的领域:

  • 社交网络
  • 交通大数据(物流)
  • 推荐系统
  • 欺诈分析
  • Web安全(垃圾邮件等等)

但是,也有不适合图数据库的领域。

  • 记录大量基于事件的数据
  • 需要大规模分布式数据处理
  • 二进制数据存储
  • 适合保存在关系型数据的结构化数据

3. Neo4j安装

Windows有exe安装文件,比较方便,一步一步按照可视化教程就行。Mac安装应该也不难。这里也不做介绍了。这里为基于Linux Ubuntu16.04,介绍安装教程。

(1)安装JAVA环境

Neo4j是用Java实现的,所以你需要安装Java Runtime Environment(JRE)。如果您已经启动并运行,请继续并跳过此步骤。打开指令框:

sudo apt update sudp apt upgrade sudo apt install default-jre default-jre-headless

如果指令不管用,先试试这两句,再使用。

sudo update-alternatives --set java / usr / lib / jvm / java-8-openjdk-amd64 / bin / java sudo update-alternatives --set javac / usr / lib / jvm / java-8 -openjdk-amd64 / bin / javac

看一下java版本:

enter image description here

(2)安装Neo4j

首先,我们将存储库密钥添加到我们的钥匙串。

wget --no-check-certificate -O -https://debian.neo4j.org/neotechnology.gpg.key| sudo apt-key add -

然后将存储库添加到apt源列表中。

echo 'deb http://debian.neo4j.org/repo stable/' | sudo tee /etc/apt/sources.list.d/neo4j.list

更新一下:

sudo apt update sudo apt install neo4j

服务器应该已经自动启动,也应该在启动时重新启动。如有必要,服务器可以停止:

sudo service neo4j stop

并重新启动:

sudo service neo4j start

访问Neo4j

现在应该可以通过http:// localhost:7474 / browser /访问数据库。

下面介绍一下打开后的面板。一开始有一个登录界面,让你输入帐号密码,第一次打开默认都是neo4j,进去后会自动弹出来让你改密码。登录后是这个样子的。

enter image description here

这里有一些示例代码:

enter image description here

你可以先尝试一下Example Graphs的教程 输入查询语句后得到这样的界面:

enter image description here

table是这样的,可以看到节点的属性:name、born等等。

enter image description here

Text可以看到表格的数据:

enter image description here

Code可以看到输入的code和json格式的数据:

enter image description here

4. 介绍 Cypher 查询语言

正如Mysql有SQL语言一样,Neo4j也有对应的查询语言Cypher。Cypher借鉴了SQL语言的结构,会有许多熟悉的关键字。对于数据库操作无非是增删改查,下面一一介绍:

(1)增

所谓增,就是创建数据。在图形数据库里基本元素是节点,关系,属性。Neo4j有两个关键字实现增加。一个是CREATE(小写也可以):

<1>CREATE创建节点

create (n:User {name:"Dav"})

这里n是变量名,User是标签(在图数据库里,标签可以理解为关系型数据库里的表table),花括号里面的是属性。

<2>CREATE创建关系:

MATCH (n{name:"a"}),(m{name:"b"}) CREATE (n)-[r:KNOWS]->(m) return n,m

这里做几点说明:

  • 小括号里是节点,节点也可以不带标签(不过不是好习惯),方括号里是关系,关系的两边是两个节点, 类似这样()-[]→()
  • MATCH 是查询语句关键字
  • return n,m 把两个节点返回 才能得到图

enter image description here

另一个是用MERGE创建节点 MERGE和CREATE不同之处在于 MERGE等于MATCH + CREATE会先创建前会在数据库里检查有没有这个节点。

<3>MERGR创建节点

MERGE (n:Test{name:"c"}) ON CREATE SET n.created = timestamp() return n

首先检查Test标签,属性为name的值的节点c是否存在,存在使用已有节点,否则创建一个新的节点。

这里就用到了MERGE创建节点,还用了一个SET关键字,这个是改变节点的属性,属于“改”的范围

<4>MERGR创建关系

用合并的方式创建关系,先检测关系存不存在,若存在则不修改任何数据,否则创造新的关系

MATCH (a:Person{name:'Joel Silver'}),(b:Person{name:'J.T. Walsh'}) MERGE (a)-[r:LOVES]->(b)

匹配出名字叫Joel Silver的人和名字叫J.T. Walsh的人建立关系LOVES。出现这个话,代表已经建立成功了。

Created 1 relationship, completed after 199 ms.

(2)删

<1>DELETE关键字可以删除数据:

MATCH (n)DELETE n

这个会报错,因为必须删除关系才能删除节点:

MATCH ()-[r:朋友]->(m) DELETE r,m

要这么操作,查找出朋友关系r以及朋友所指向的节点m,并同时把r和m删除。出现这个就成功了:

Deleted 1 node, deleted 1 relationship, completed after 8 ms.

<2>REMOVE 也可以删除数据:

MATCH (n) REMOVE n:Test

用REMOVE来移除数据,移除带有Test标签的所有结点:

Removed 3 labels, completed after 9 ms.

用REMOVE来移除节点时要小心,REMOVE不会像DELETE,因为这个节点有其他关系而报错不删。

那么这个节点被删除后,关系会指向空节点。

(3)改

使用SET去更改节点。刚刚前文已经有例子就不赘述了。

(4)查

使用MATCH去查询节点。Cypher还有其他的缩小查找范围的办法。

<1>MATCH p=()-[r:LOVES]->() RETURN p LIMIT 25

用LIMIT关键字只拿指定数目的节点个数。

<2>WHERE实现条件过滤

MATCH p=(n:Person)-[:LOVES]->() WHERE n.name <> "a" RETURN p

查询节点n的属性name不等于a的所有节点 <>表示不等于。

<3>使用INDEX索引

使用关键字INDEX ON为节点的属性name创建一个普通的索引:

CREATE INDEX ON :Person(name)

输出:

Added 1 index, completed after 46 ms.

使用索引来查询:

MATCH (n:Person) WHERE n.name IN ["a","b"] RETURN n as Person

得到图:

enter image description here

显式使用索引查询:

MATCH(n:Person) USING INDEX n:Person(name) WHERE n.name = 'a' RETURN n as Person

用DROP关键字删除一个已经存在的索引:

DROP INDEX ON :Person(name)

输出:

Removed 1 index, completed after 1 ms.

Cypher 还能使用一些函数来辅助查询 比如size() any()等等。具体其他的可以查阅相关的API文档。这里只提两个重要的,查询最短路径和所有最短路径。

<1>最短路径shortestpath()

以这个图为例子,从部分的图里找出Joel Silver到Jonathan Lipnicki的最短路径:

enter image description here

MATCH (p1:Person {name:"Jonathan Lipnicki"}),(p2:Person{name:"Joel Silver"}), p=shortestpath((p1)-[*..10]-(p2)) RETURN p

这里[*..10]表示路径深度10以内查找所有存在的关系中的最短路径关系

得到图:

enter image description here

<2>所有最短路径

MATCH (p1:Person {name:"Jonathan Lipnicki"}),(p2:Person{name:"Joel Silver"}), p=allshortestpaths((p1)-[*..10]-(p2)) RETURN p

enter image description here

以上理论部分已经讲完,下面进入实战部分。

5. 案例实战

(1)银行欺诈环分析

这里引入一个概念,第一方银行欺诈,本质是使用他人真实身份编造和伪造身份进行欺诈。

有如下几个特点:

  • <1>两个或两个以上的人组成欺诈环
  • <2>欺诈环里的人共享合法联系人的部分信息,如电话号码

我们可以使用Neo4j来识别存在的欺诈环。

首先,我们创建欺诈环(由于篇幅限制,就不把代码贴在这里 可以参考这个教程)。

enter image description here

查询可疑的欺诈环:

enter image description here

从左到右,欺诈环的成员,涉嫌欺诈的联系方式,欺诈环的大小。计算出欺诈的风险值:

enter image description here

2)文献索引

先举个小例子,在学术界需要查一些论文,通常是用全文搜索,这样的搜索效率不高。可以用Neo4j获取匹配度高的论文。这里先举个小例子。打开Neo4j,先手动插入数据。

create (论文1:论文图谱{论文名:"论文1"}),(论文2:论文图谱{论文名:"论文2"}),(论文3:论文图谱{论文名:"论文3"}),(论文4:论文图谱{论文名:"论文4"}),(论文5:论文图谱{论文名:"论文5"}),(论文6:论文图谱{论文名:"论文6"}),(论文7:论文图谱{论文名:"论文7"}),(论文1)-[:相似]->(论文2),(论文1)-[:相似]->(论文3),(论文2)-[:相似]->(论文4),(论文2)-[:相似]->(论文5),(论文3)-[:相似]->(论文5),(论文5)-[:相似]->(论文6),(论文7)-[:相似]->(论文2),(论文7)-[:相似]->(论文6) return *

enter image description here

查找论文1到论文6之间相似的传递路径,这样就可以找出,论文的主要参考了那些论文。

MATCH n=allshortestPaths((论文1:论文图谱{论文名:"论文1"})-[*..6]->(论文6:论文图谱{论文名:"论文6"})) RETURN n

enter image description here

接下来,我想通过一个完整的例子实现文献索引,从数据获取,导入,再到分析。我将使用Scrapy爬取1000本书的信息。保存到csv,导入neo4j,再进一步分析。

首先是使用Scrapy爬取信息。数据爬下来后,是这样。

enter image description here

从左到右依次是书的upc编码,名字,类型,储存量,价格,评分,评分数目,简介目标网站是这个。先使用scrapy shell来操作一个爬虫,先简单进行爬取实验,把网页分析好。

enter image description here

scrapy shell http://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html

设计思路:

  • <1>根据刚刚分析出来的网页信息,设置items
  • <2>根据刚刚分析的网页,设计爬虫spieder
    • 爬虫需要爬去单个页面需要信息
    • 爬完一个网页,爬虫需要去爬取下一个目标网页
  • <3>在setting里设置相关信息
  • <4>在pipelines处理特别的数据

代码我已经上传到git

通过csv文件,把数据导入Neo4j。首先把book2.csv放到这个目录下:

/var/lib/neo4j/import

首先读取一下文件,看看是否能获取到:

LOAD CSV WITH HEADERS FROM "file:///books2.csv" AS line WITH line RETURN line

enter image description here

LOAD CSV WITH HEADERS FROM "file:///books2.csv" AS line CREATE (:Books { Id: line.upc, Name: line.name, Price: line.price,Rate:line.review_rating,content:line.jianjie,kinds:line.Kinds,stock:line.stock})

这样就把1000本书作为节点,存进去了。输出:

Added 1000 labels, created 1000 nodes, set 5998 properties, completed after 228 ms.

查询25个看看情况:

enter image description here

并且可以查看到各种属性。但是还没有关系。在创建几个书类节点:

create (n:书类名{n.Name=”Sequential Art”})
..
..

再建立关系:

MATCH (n:Books2),(m:书类名) where n.kinds = m.Name create(n)-[r:属于]->(m) RETURN n,r,m LIMIT 25

enter image description here

一个简单的书籍-门类图就建好了,现在我们可以通过书的评分,门类,价格进行索引。从而完成一个简单的书目推荐系统。在第五个案例我会合在一起做。

(3)寻找垃圾邮箱源头

如果你不想在本地下载Neo4j,可以去可以登录微云数聚公司官网在线尝试一下Neo4j。这里我们就基于这个平台,来做一个垃圾邮件的案例。

在命令框输入:

MATCH m=(s:Person)-->(e:Email)-->(r:Person) WHERE e.title=~'.*普通发票.*' RETURN m LIMIT 15

enter image description here

这里只返回了15个节点。如果我们要查到垃圾邮箱的源头,会怎么做?通常垃圾邮箱的标题或者内容会有关于促销,招聘等等字眼。

这里我们就通过对所有邮件的标题遍历,查找关键字“发票”。如果经常发这种邮件的人,邮件数量一定很多。这里我们设置当有这种信件的数量超过105,就输出他。

MATCH m=(s:Person)-->(e:Email)-->(r:Person) WHERE e.title=~'.发票.' WITH s,COUNT(e) AS num,COLLECT(e) AS emails,COLLECT(r) AS recevies WHERE num > 105 RETURN s,emails,recevies

得到图:

enter image description here

很明显就发现,几乎所有发票都是来自这个邮箱[email protected],主犯找到了。

那么就可以发现这个主犯了。那么这样就结束了吗?不不,我在上文说过“反向提问”是很有价值的,既然找到了主犯,那么我们不妨多看看,

他还会经常发什么邮件,这类邮件有什么特征。从中挖掘出这类人,发垃圾邮箱的“套路”。

MATCH m=(s:Person)-->(e:Email)-->(r:Person)

WHERE s.account=~'[email protected]'

RETURN s,e,r

得到图:

enter image description here

仔细观察,你会发现,这个主犯的邮件除了含“发票”的字眼,还有“来电恰谈”,“费用优惠”等字眼。那么这样我们就可以记住这样的字眼,下次就可以过滤这类字眼的邮件。

通过上面这个例子,应该能体会到,图数据库,在处理垃圾邮件,查找信息的优势了。特别是在处理“反向提问”的问题。并且查询效率都是在毫秒级别的。

4)企业关系构建

这里还是基于微云数聚公司的平台。

MATCH (n:`公司`) RETURN n LIMIT 25

enter image description here

投资图:

MATCH a=(:公司 {名称:'中航工业集团公司'})-[r*]->() RETURN nodes(a)

enter image description here

这样对于公司就有一个直观的把握。谁投资了谁,现金流的流向。对于公司的财务管理也有直观的展现。

担保图:

MATCH a=(:公司 {名称:'中航工业集团公司'})-[r:担保*]->() RETURN nodes(a)

enter image description here

等等

(5)社交关系分析,实现一个简单的好友推荐功能

这里我们会用到第二个案例的书籍库,首先创建好友圈。

create (小北:朋友圈{姓名:"小北",喜欢的书类:"Poetry"}), (小菲:朋友圈{姓名:"小菲",喜欢的书类:"Science Fiction"}), (小鹏:朋友圈{姓名:"小鹏",喜欢的书类:"Music"}), (小颖:朋友圈{姓名:"小颖",喜欢的书类:"Politics"}), (小兰:朋友圈{姓名:"小兰",喜欢的书类:"Music"}), (小峰:朋友圈{姓名:"小峰",喜欢的书类:"Travel"}), (小讯:朋友圈{姓名:"小讯",喜欢的书类:"Poetry"}), (小东:朋友圈{姓名:"小东",喜欢的书类:"Sequential Art"}), (小唯:朋友圈{姓名:"小唯",喜欢的书类:"Young Adult"}), (小窦:朋友圈{姓名:"小窦",喜欢的书类:"Poetry"}), (小齐:朋友圈{姓名:"小齐",喜欢的书类:"Default"}), (小林:朋友圈{姓名:"小林",喜欢的书类:"Poetry"}), (小锐:朋友圈{姓名:"小锐",喜欢的书类:"Default"}), (小伟:朋友圈{姓名:"小伟",喜欢的书类:"Young Adult"}), (小玲:朋友圈{姓名:"小玲",喜欢的书类:"Business"}), (小讯)-[:认识]->(小窦), (小讯)-[:认识]->(小齐), (小讯)-[:认识]->(小林), (小讯)-[:认识]->(小鹏), (小讯)-[:认识]->(小伟), (小讯)-[:认识]->(小峰), (小菲)-[:认识]->(小鹏), (小菲)-[:认识]->(小峰), (小菲)-[:认识]->(小唯), (小峰)-[:认识]->(小北), (小峰)-[:认识]->(小兰), (小东)-[:认识]->(小林), (小东)-[:认识]->(小锐), (小东)-[:认识]->(小菲), (小鹏)-[:认识]->(小颖), (小北)-[:认识]->(小兰), (小颖)-[:认识]->(小东), (小唯)-[:认识]->(小鹏), (小唯)-[:认识]->(小锐), (小伟)-[:认识]→(小玲)

展现小峰的朋友圈:

MATCH n=(:朋友圈{姓名:"小峰"})-[*..6]-() return n

enter image description here

这里要引入几个概念。

<1>一度关系(直接关系)

MATCH n=(:朋友圈{姓名:"小讯"})-[:认识]-() return n

enter image description here

<2>二度关系

MATCH n=(:朋友圈{姓名:"小讯"})-[*..2]-() return n

enter image description here

我曾经看到一个问题,如果你住在一个村子,要认识奥巴马,要经过几个人呢?答案是6个。假设你在一个村里,那么村长,乡长,县长,市长,省长,国家主席,奥巴马,通过六个人就可以了。所以你会发现,我们通常在6度深度搜索。

<3>两个陌生人之间的最短认识路径

我们可以用Neo4j来找到两个不认识的人,建立联系的最短路径。

MATCH n=shortestPath((小讯:朋友圈{姓名:"小讯"})-[*..6]-(小锐:朋友圈{姓名:"小锐"})) return n

enter image description here

<4>两个陌生人之间的所有最短认识路径

MATCH n = allshortestPaths((小讯:朋友圈{姓名:"小讯"})-[*..6]-(小菲:朋友圈{姓名:"小菲"})) return n

enter image description here

<5>根据节点的影响力或者及其它属性来制作推荐系统

不知道,大家有没有思考过,B站、淘宝,QQ等等这些软件是怎么作推荐系统的。比如:B站,每一个Up主在上传视频的时候都要选好投稿区,类型,关键字标签。这样就已经完成了数据的分类。你如果经常看官延区,那么你来官延区的频度一定很大,那么可以给你推荐这些视频,再根据Up主的影响力(节点的大小)来给你推荐。当然他们肯定还使用了许多机器学习的算法。在我看来,也可以使用Neo4j做一个简单的推荐功能。

比如做一个小小的书籍推荐。在创建节点的时候,我顺便创建了他们喜欢的书的类型(你会发现,你用一些app时,你一件事就是让你确定喜好)。

结合第二个案例的数据:

MATCH (n:朋友圈),(m:Books2) where n.喜欢的书类 = m.kinds and toInt(m.Rate)>4  create (m)-[r:推荐]->(n) return m,r,n

这里我们做了一件事,就是根据大家填上来的喜好书籍类型,我们挑选出评分大于4的书籍给他们。

enter image description here

并且从图中可以很容易发现,越是推荐书籍密集的相近的人,他们就具有相同的爱好。比如小齐和小锐,从图中还能发现,两个人并不是直接认识的。根据这一点,我们就可以介绍小锐和小齐认识交流。

由此,我们完成了两层推荐。一个是书籍的推荐,一个是朋友的推荐。但是,实际运用中肯定不会这么草率和简单,考虑的肯定会更加详细。这里只是做一个简单的抛砖引玉。

三、推荐资料:

在学习Neo4j的过程中,我也找了不少资料。这里也供大家参考。

  • 《Neo4j权威指南》--清华大学出版社
  • 《Neo4j全栈开发》--电子工业出版社
  • 《图数据库》--人民邮电出版社
  • 《精通Scrapy网络爬虫》--清华大学出版社
  • Neo4j官方文档

四、写在最后的话

Neo4j确实是一个很好的数据库,虽然现在还没火起来,但是我相信,未来它的应用场景会越来越多的。毕竟画图是我们人类认识世界最直观的方式了。非常非常感谢大家能来参加这场Chat。这是我做的第二场Chat,虽然已经有第一次的经验了。但是说实在话,还是很紧张。毕竟我还是一名学生,做的东西肯定会有不少疏忽,错漏,还请大家谅解。有什么疑问都可以在评论区留言。这对我也是一次很好的历练与成长。最后感谢各位的支持。感激不尽。

猜你喜欢

转载自blog.csdn.net/litianquan/article/details/82770826