图的查询和传统SQL查询有很大不同,它更加直观易于理解,但是偏离底层存储模型更远。Gremlin 是Apache TinkerPop开源项目的一部分,它是专门用于图数据库查询的语言,采用类 Scala 语法。需要了解 Gremlin可以参考下文档https://github.com/tinkerpop/gremlin/wiki。
在Cayley里对Gremlin做了简化的实现,这个API被称作 Gizmo。对应文档位于https://cayley.gitbook.io/cayley/query-languages/gizmoapi。所有的查询都是从g(graph)开始的,它代表了整个图。下面我们实践下如何使用,首先启动cayley的web服务,并导入样例数据
代码语言:javascript复制% ../cayley/cayley http -c cayley_example.yml load quads.data --host=0.0.0.0:64210
I0601 08:11:58.595469 9019 command.go:915] Cayley version: v0.8.x-dev (dev snapshot)
I0601 08:11:58.596053 9019 command.go:915] using config file: cayley_example.yml
I0601 08:11:58.596314 9019 http.go:20] using backend "mysql" (root:@tcp(localhost:3306)/cayley?loc=Local&charset=utf8mb4&collation=utf8mb4_general_ci)
I0601 08:11:58.601000 9019 command.go:940] listening on 0.0.0.0:64210, web interface at http://0.0.0.0:64210
浏览器中打开地址http://127.0.0.1:64210/可以看到如下界面
在进行查询之前,我们先了解下cayley导入的数据的基本结构,它是通过空格分割的一行数据,点号结尾。可以是三元祖也可以是4元祖,具体如下例子:
代码语言:javascript复制<战狼2> <ISA> <Movie> .
<战狼2> <rank> "1" .
<战狼2> <src> "/item/战狼2" .
<战狼2> <box_office> "56.83亿" .
<战狼2> <avg_price> "35" .
<战狼2> <avg_people> "38" .
<战狼2> <begin_date> "2017.07.27" .
<流浪地球> <ISA> <Movie> .
<流浪地球> <rank> "2" .
<流浪地球> <src> "/item/流浪地球" .
<流浪地球> <box_office> "40.83亿" .
接着我们开始查询,比如查询顶点,我们可以使用g.Vertex()或者g.V(),可以使用g.addDefaultNamespaces()增加默认命名空间,或者使用graph.addNamespace(pref, ns)增加一个指定前缀的命名空间。可以使用
graph.loadNamespaces()来加载命名空间:
代码语言:javascript复制graph.addNamespace(g.IRI(), "myns")
graph.emit(*)可以把执行结果输出为json格式,比如
代码语言:javascript复制g.emit({ name: "bob" });
输出为
代码语言:javascript复制{
"result": [
{
"name": "bob"
}
]
}
graph.M()或者
graph.Morphism()表示一条路径,可以创建一条路径并保存到变量里
var shorterPath = graph .Morphism() .out("foo") .out("bar");
graph.IRI(s)用于从一个字符串里创建一个国际化资源标识符(Internationalized Resource Identifiers,简称IRI)
g.IRI("资源标识符")
")---.back("start")---.in("")---.all();
path.all()返回路径的所有标记,in标识扇入路径,out表示扇出路径。back表示回退到前一个路径。both表示前驱后跟随的所有路径
g.V("")---.both("")---.all();
path.count()统计返回结果的个数。
//-Save-count-as-a-variable-var-n-=-g.V().count();-//-Send-it-as-a-query-result-g.emit(n);
{-----"result":-[---------268-----]-}">graph.V(*)或者
graph.Vertex([nodeId],[nodeId]...)标识从一个顶点开始查询,如果没有制定顶点id标识所有的顶点。返回一个路径对象。.Morphism()和
.Vertex()都可以返回一个路径对象,不同的是.V()返回的是一个路径对象的可查子集。
g.V() .Tag("start") .out("<status>") .back("start") .in("<follows>") .all();
path.all()返回路径的所有标记,in标识扇入路径,out表示扇出路径。back表示回退到前一个路径。both表示前驱后跟随的所有路径
g.V("<fred>") .both("<follows>") .all();
path.count()统计返回结果的个数。
// Save count as a variable var n = g.V().count(); // Send it as a query result g.emit(n);
{ "result": [ 268 ] }
graph.V(*)或者
graph.Vertex([nodeId],[nodeId]...)标识从一个顶点开始查询,如果没有制定顶点id标识所有的顶点。返回一个路径对象。.Morphism()和
.Vertex()都可以返回一个路径对象,不同的是.V()返回的是一个路径对象的可查子集。
g.V() .Tag("start") .out("<status>") .back("start") .in("<follows>") .all();
path.all()返回路径的所有标记,in标识扇入路径,out表示扇出路径。back表示回退到前一个路径。both表示前驱后跟随的所有路径
g.V("<fred>") .both("<follows>") .all();
path.count()统计返回结果的个数。
// Save count as a variable var n = g.V().count(); // Send it as a query result g.emit(n);
{ "result": [ 268 ] }path.difference(path)返回差异,
path.except(path)排除一条路径。
代码语言:javascript复制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.
var e = 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()
g.emit(e)
也可以通过节点列表来过滤path.filter(args)或者正则表达式path.filter(regex(expression, includeIRIs)),path.follow(path)可以用来表达谁关注了谁的语意
代码语言:javascript复制var friendOfFriend = g
.Morphism()
.out("<follows>")
.out("<follows>");
// Returns the followed people of who charlie follows -- a simplistic "friend of my friend"
// and whether or not they have a "cool" status. Potential for recommending followers abounds.
// Returns bob and greg
g.V("<charlie>")
.follow(friendOfFriend)
.has("<status>", "cool_person")
.all();
path.followR(path)表达了反向关注的语意
代码语言:javascript复制var friendOfFriend = g
.Morphism()
.out("<follows>")
.out("<follows>");
// Returns the third-tier of influencers -- people who follow people who follow the cool people.
// Returns charlie (from bob), charlie (from greg), bob and emily
g.V()
.has("<status>", "cool_person")
.followR(friendOfFriend)
.all();
path.followRecursive表示递归执行这个关注路径
代码语言:javascript复制var friend = g.Morphism().out("<follows>");
// Returns all people in Charlie's network.
// Returns bob and dani (from charlie), fred (from bob) and greg (from dani).
g.V("<charlie>")
.followRecursive(friend)
.all();
path.forEach(callback) or (limit, callback)对返回的结果依次进行处理
代码语言:javascript复制graph.V("<alice>").ForEach(function(d) {
g.emit(d);
});
path.getLimit(limit)返回前n个不同的节点,path.has(predicate, object)过滤包含制定谓语和宾语的路径。
代码语言:javascript复制// Start from all nodes that follow bob -- results in alice, charlie and dani
g.V()
.has("<follows>", "<bob>")
.all();
// People charlie follows who then follow fred. Results in bob.
g.V("<charlie>")
.out("<follows>")
.has("<follows>", "<fred>")
.all();
// People with friends who have names sorting lower then "f".
g.V()
.has("<follows>", gt("<f>"))
.all();
path.hasR(*)是一个逆向的操作。path.in([predicatePath], [tags])是out的逆向操作。
代码语言:javascript复制// 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()返回指向它的所有节点
代码语言:javascript复制g.V("Hello World!")
.inPredicates()
.all();
代码语言:javascript复制{
"result": [
{
"id": "is of course"
}
]
}
两个路径的交集用path.intersect(path)
代码语言:javascript复制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()
判断节点之间是否存在路径path.is(node, [node..])
代码语言:javascript复制// Starting from all nodes in the graph, find the paths that follow bob.
// Results in three paths for bob (from alice, charlie and dani).all()
g.V()
.out("<follows>")
.is("<bob>")
.all();
path.labelContext([labelPath], [tags])增加或者删除路径的上下文标签
代码语言:javascript复制// Find the status of people Dani follows
g.V("<dani>")
.out("<follows>")
.out("<status>")
.all();
// Find only the statuses provided by the smart_graph
g.V("<dani>")
.out("<follows>")
.labelContext("<smart_graph>")
.out("<status>")
.all();
// Find all people followed by people with statuses in the smart_graph.
g.V()
.labelContext("<smart_graph>")
.in("<status>")
.labelContext(null)
.in("<follows>")
.all();
获取所有标签path.labels(),返回路径上指定数量的节点path.limit(limit)
代码语言:javascript复制g.V()
.has("<follows>", "<bob>")
.limit(2)
.all();
path.map(*)和ForEach含义是一样的,求并集用path.or(path),指定扇出path.out([predicatePath], [tags])
代码语言:javascript复制// The working set of this is bob and dani
g.V("<charlie>")
.out("<follows>")
.all();
// The working set of this is fred, as alice follows bob and bob follows fred.
g.V("<alice>")
.out("<follows>")
.out("<follows>")
.all();
// Finds all things dani points at. Result is bob, greg and cool_person
g.V("<dani>")
.out()
.all();
// Finds all things dani points at on the status linkage.
// Result is bob, greg and cool_person
g.V("<dani>")
.out(["<follows>", "<status>"])
.all();
// Finds all things dani points at on the status linkage, given from a separate query path.
// Result is {"id": "cool_person", "pred": "<status>"}
g.V("<dani>")
.out(g.V("<status>"), "pred")
.all();
path.outPredicates()获取所有扇出节点。path.save(predicate, tag)保存带有指定标签的四元祖
代码语言:javascript复制// Start from dani and bob and save who they follow into "target"
// Returns:
// {"id" : "<bob>", "target": "<fred>" },
// {"id" : "<dani>", "target": "<bob>" },
// {"id" : "<dani>", "target": "<greg>" }
g.V("<dani>", "<bob>")
.save("<follows>", "target")
.all();
path.saveInPredicates(tag)获取所有前驱节点
代码语言:javascript复制// bob only has "<follows>" predicates pointing inward
// returns {"id":"<bob>", "pred":"<follows>"}
g.V("<bob>")
.saveInPredicates("pred")
.all();
path.saveOpt(*)和save一样。path.saveOptR(*)是反向的,path.saveOutPredicates(tag)
代码语言:javascript复制g.V("<bob>")
.saveInPredicates("pred")
.all();
path.saveR(*),path.skip(offset)跳过指定数量节点,
代码语言:javascript复制g.V()
.has("<follows>", "<bob>")
.skip(2)
.all();
获取拥有指定标签的路径path.tag(tags),path.tagArray(*)返回标签到字符串的数组。path.tagValue()类似,path.toArray(*)返回一个数组。path.toValue(),组合两个查询结果path.union(path)
代码语言:javascript复制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 (from charlie), dani, bob (from dani), and greg.
cFollows.union(dFollows).all();
path.unique()去掉重复路径,path.order()生序返回。