golang源码分析:cayley(12)

2023-08-09 15:12:27 浏览数 (2)

图的查询和传统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 ] }

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()生序返回。

0 人点赞