写在前面
- 态度决定高度!让优秀成为一种习惯!
- 世界上没有什么事儿是加一次班解决不了的,如果有,就加两次!(- - -茂强)
前瞻
一说到图数据库,大家估计最先想到的是neo4j,不错,neo4j在图数据库中做的是相当成功,但是在你用的时候,你就会考虑其是否开源,是否免费,你要知道,在公司(不是以图数据作为业务主要驱动的公司)对于你的一个小小的项目,公司给你买一个数据库,这是不是很扯淡,所以,你就很想知道,是否有开源的图数据库,当然有。但是今天我是要说一个个人比较喜欢的图数据库,就是cayley,是完全开源的,项目地址是在google旗下
项目地址:https://github.com/cayleygraph/cayley
一步一步的建立起自己的cayley
- 首先你需要下载你所在环境的包
地址:https://github.com/cayleygraph/cayley/releases
选择你需要的平台包
我是windows测试的,所以就选了windows包
当然你也可以选择源码,进行自行编译部署
mkdir -p ~/cayley && cd ~/cayley
export GOPATH=pwd
export PATH=$PATH:~/cayley/bin
mkdir -p bin pkg src/github.com/cayleygraph
cd src/github.com/cayleygraph
git clone https://github.com/cayleygraph/cayley
cd cayley
curl https://glide.sh/get | sh
glide install
go build ./cmd/cayley
编译好了就可以测试一下,切换到命令目录
./cayley repl -i data/testdata.nq
当然也可以用http模式
./cayley http -i data/testdata.nq
- 解压文件夹到指定目录(自己指定)
找到加压后文件夹中的cayley.exe,这个就是我们需要操作的对象,
通过官方我们知道cayley需要指定(依赖)三方数据库,如:
KVs: Bolt, LevelDB
NoSQL: MongoDB
SQL: PostgreSQL, CockroachDB, MySQL
n-memory, ephemeral
这里我们选择levelDB - 把cayley.cfg.example文件重命名为cayley.cfg
这一步可以不用,因为不影响,我个人比较喜欢标准一点,所以就改了 - cayley.cfg内容配置
{
"database": "leveldb",
"db_path": "d:/cayley/cayley_db",
"read_only": false
}
这里db_path就是cayley需要创建的levelDB的路径,其他的都是字面意思,如果你想依赖起的数据库,比如 Bolt数据库你可以用一下的配置
{
"database": "bolt",
"db_path": "/tmp/demodb",
"read_only": false
}
更多的配置信息:https://github.com/cayleygraph/cayley/blob/master/docs/Configuration.md - 初始化cayley依赖的levelDB
我们在cmd里边切换到cayley.exe所在的文件夹下
执行命令:
cayley.exe init --config=cayley.cfg
或者用:
cayley.exe init --db=leveldb --dbpath=d:/cayley/cayley_db
都可以,这样cayley就会在d:/cayley/cayley_db下初始化一个levelDB数据库了,不信你去文件夹下看看
当然,你也许会用到其他的数据库,比如 Bolt那你可以用
cayley.exe init --db=bolt --dbpath=tmp/testdb
如果是MongoDB那就要用
cayley.exe init --db=mongo --dbpath=”<HOSTNAME>:<PORT>
其中,HOSTNAME和PORT指向你的Mongo实例
依赖的数据库建好了之后,那就给里边添加点数据吧 -
向cayley里边添加数据
首先让我们看一下数据的具体格式,在data目录下有个testdata.nq的文本,打开后就是如下的数据
<alice> <follows> <bob> .
<bob> <follows> <fred> .
<bob> <status> "cool_person" .
<charlie> <follows> <bob> .
<charlie> <follows> <dani> .
<dani> <follows> <bob> .
<dani> <follows> <greg> .
<dani> <status> "cool_person" .
<emily> <follows> <fred> .
<fred> <follows> <greg> .
<greg> <status> "cool_person" .
<predicates> <are> <follows> .
<predicates> <are> <status> .
<emily> <status> "smart_person" <smart_graph> .
<greg> <status> "smart_person" <smart_graph> .
这个就是人的关系数据,第一个是主语subject,第二个是谓语predicate,第三个是宾语object,最后以 . 号结束,其中还有,主题还有一个属性status可以从下图来理解
图中箭头表示follows的关系,而#括起来的人名表示,这些人有status为cool_person
下边我们把它加载到我们刚才初始化的levelDB中
cayley.exe load --config=cayley.cfg --quads=data/testdata.nq
这样数据就加载到了levelDB中了 -
启动cayley
cayley的启动方式有两种,一种是REPL另一种是HTTP
第一种:REPL
cayley.exe repl --config=cayley.cfg
启动后是命令行模式
第二种:HTTP
cayley.exe http --config=cayley.cfg
启动后控制台
这样你就可以在浏览器中打开了
cayley的增删查
cayley只有增、删、查,不同于其他的数据库,cayley少了改的操作,其实大家都知道,所谓的改就是先删在增
- cayley的增
比如我要添加一个人叫“leon”,他关注了“alice”,并且他也是一个“cool_person”,那么输入这样的命令即可:
:a leon follows alice .
:a leon status cool_person . - cayley的删
比如我刚才添加的“leon”,现在他不想关注“alice”了,那么这样就可以删除刚才建立的关系了:
:d leon follows alice . - cayley的查
cayley的查提供了两种形式的语言,一种和javascript类似,一种是简化的MQL,这里选择js的查询来阐述一下
graph对象:graph对象简称g,它是唯一存在的,并由它来说产生query对象,通过query返回各种查询结果,执行方式如下:
graph.Vertex([nodeId],[nodeId]…) 简写为 g.V
参数:nodeId(可选):一个字符串,或者字符串列表,代表了查询的起始节点
返回:query 对象
从给定的顶点(集)开始一个查询路径,如果没有参数,则认为是图中所有的顶点。
来看例子:
g.V().All() //我想看目前图中所有的顶点
g.V("<alice>").GetLimit(1) //获得alice这个节点
其中All()方法是query对象的方法,用它可以遍历query对象中,所有的数据。GetLimit(number)也是query对象的方法,它获得迭代集里限定数目的数据。
graph.Morphism() 简写为 g.M()
无参数
返回:path对象
path 对象,它是query对象的父类对象
path对象由 g.V() 和 g.M() 创建,其中 g.V() 创建了query对象,它是path对象的子类。
path.Out([predicatePath],[tags])
参数:predicatePath(可选)下列其中之一
空或者undifined:所有从这个节点出去的predicate
一个字符串:从这个节点出去的predicate名字
字符串列表:从这个节点出去的多个predicate名字
一个query path 对象: 该对象指向一个predicate集合(跟随者)
tags(可选参数):下列其中之一
空或者undifined:没有tags
一个字符串:向输出集使用的指明predicate的标签
字符串列表:添加多个tags,这些tags当作keys保存指向输出集的predicate
例子:
// 查看charlie follows了谁。结果是 bob and dani
g.V("<charlie>").Out("<follows>").All()
// 查看alice follows的人,他们又follows了谁。结果是 fred
g.V("<alice>").Out("<follows>").Out("<follows>").All()
// 从dani出去的路径都指向了哪里。 结果是 bob, greg 和 cool_person
g.V("<dani>").Out().All()
// 找到所有dani通过follows和status指向的节点。
// 结果是 bob, greg 和 cool_person
g.V("<dani>").Out(["<follows>", "<status>"]).All()
// 找到所有dani通过status指向的节点,并加上tag。
// 结果是 {"id": cool_person, "pred": "status"}
g.V("<dani>").Out(g.V("<status>"), "pred").All()
path.In([predicatePath],[tags])
与path.Out()用法上相同,只不过是一个是出,一个是入
// Find the cool people, bob, dani and greg
g.V("cool_person").In("<status>").All()
// Find who follows bob, in this case, alice, charlie, and dani
g.V("<bob>").In("<follows>").All()
// Find who follows the people emily follows, namely, bob and emily
g.V("<emily>").Out("<follows>").In("<follows>").All()
path.InPredicates()
获得指向一个节点的一个predicates列表
// bob only has "<follows>" predicates pointing inward
// returns "<follows>"
g.V("<bob>").InPredicates().All()
path.Both([predicatePath],[tags])
这个就是in和out的合并,出入同查
g.V("<fred>").Both("<follows>").All()
path.Count()
返回结果总数
path.Except(path)
与path.Difference(path)是一样的效果,就是一种排除查询
var cFollows = g.V("<charlie>").Out("<follows>")var dFollows = g.V("<dani>").Out("<follows>")
// People followed by both charlie (bob and dani) and dani (bob and greg) -- returns bob.
cFollows.Except(dFollows).All() // The set (dani) -- what charlie follows that dani does not also follow.
// Equivalently, g.V("<charlie>").Out("<follows>").Except(g.V("<dani>").Out("<follows>")).All()
path.Filter(args)
过滤,可以通过传入区间或者匹配字符串来过滤
path.Intersect(path)
求交集
var cFollows = g.V("<charlie>").Out("<follows>")
var dFollows = g.V("<dani>").Out("<follows>")
// People followed by both charlie (bob and dani) and dani (bob and greg) -- returns bob.
cFollows.Intersect(dFollows).All()
// Equivalently, g.V("<charlie>").Out("<follows>").And(g.V("<dani>").Out("<follows>")).All()
其他的查询方法就不多说了,如果想了解去这里看看
https://github.com/cayleygraph/cayley/blob/master/docs/GizmoAPI.md
关系图可视化
这个需要在http模式
- Query Shape
- Visualize
这里要说明一下,0.6.1版本对于可视化页面支持有问题,图形展示不出来,而且query也查不出来数据,不知是否是浏览器问题(我的是chrome),但是0.6.0就可以展示。
下边将用实例介绍如何用cayley做知识图谱,敬请期待!