Gremlin是JanusGraph的查询语言,用于从图形中检索数据和修改数据。Gremlin是一种面向路径的语言,它简洁地表达了复杂的图遍历和变异操作。Gremlin是一种函数语言,遍历操作符被链接在一起形成类似路径的表达式。例如,“从赫拉克勒斯出发,遍历到他父亲,然后是他父亲的父亲,并返回祖父的名字。”
Gremlin是ApacheTingerpop的一个组件。它是独立于JanuGraph开发的,并且大多数图形数据库都支持它。通过使用Gremlin查询语言在JanusGraph之上构建应用程序,用户避免供应商锁定,因为他们的应用程序可以迁移到支持Gremlin的其他图形数据库。
本节简要概述了Gremlin查询语言。有关Gremlin的更多信息,请参阅以下资源:
除了这些资源之外,连接到JanusGraph还解释了Gremlin如何在不同的编程语言中用于查询JanusGraph服务器。
Gremlin查询是从左到右计算的操作/函数链。下面提供了一个简单的祖父查询,在入门中讨论的goods数据集的图形上。
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
以上查询可以阅读:
综合起来,这些步骤形成了一个类似路径的遍历查询。每一步都可以分解并展示其结果。这种构建遍历/查询的方式在构建更大、更复杂的查询链时非常有用。
gremlin> g
==>graphtraversalsource[janusgraph[cql:127.0.0.1], standard]
gremlin> g.V().has('name', 'hercules')
==>v[24]
gremlin> g.V().has('name', 'hercules').out('father')
==>v[16]
gremlin> g.V().has('name', 'hercules').out('father').out('father')
==>v[20]
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
对于健全性检查,通常最好查看每个返回的属性,而不是指定的长id。
gremlin> g.V().has('name', 'hercules').values('name')
==>hercules
gremlin> g.V().has('name', 'hercules').out('father').values('name')
==>jupiter
gremlin> g.V().has('name', 'hercules').out('father').out('father').values('name')
==>saturn
注意相关的遍历,它显示了赫拉克勒斯的整个父系树分支。提供这种更复杂的遍历是为了展示语言的灵活性和表达能力。熟练掌握Gremlin为JanusGraph用户提供了流畅地浏览底层图形结构的能力。
gremlin> g.V().has('name', 'hercules').repeat(out('father')).emit().values('name')
==>jupiter
==>saturn
下面提供了更多的遍历示例。
gremlin> hercules = g.V().has('name', 'hercules').next()
==>v[1536]
gremlin> g.V(hercules).out('father', 'mother').label()
==>god
==>human
gremlin> g.V(hercules).out('battled').label()
==>monster
==>monster
==>monster
gremlin> g.V(hercules).out('battled').valueMap()
==>{name=nemean}
==>{name=hydra}
==>{name=cerberus}
每一步(用分隔符号表示)都是一个函数,它对上一步发出的对象进行操作。在Gremlin语言中有许多步骤(参见Gremlin步骤)。通过简单地改变一个步骤或步骤的顺序,就可以实现不同的遍历语义。下面的例子返回与赫拉克勒斯同一怪物作战的所有人的名字,这些怪物本身不是赫拉克勒斯(即“共同作战者”或者“盟友”)。
假设神的图形只有一个战斗者(大力神),另一个战斗者(为了举例)被添加到图形中,Gremlin展示了如何将顶点和边添加到图形中。
gremlin> theseus = graph.addVertex('human')
==>v[3328]
gremlin> theseus.property('name', 'theseus')
==>null
gremlin> cerberus = g.V().has('name', 'cerberus').next()
==>v[2816]
gremlin> battle = theseus.addEdge('battled', cerberus, 'time', 22)
==>e[7eo-2kg-iz9-268][3328-battled->2816]
gremlin> battle.values('time')
==>22
添加顶点时,可以提供可选的顶点标签。添加边时必须指定边标签。可以在顶点和边上设置作为键值对的属性。使用集合或列表基数定义属性键时,向顶点添加相应属性时必须使用addProperty。
gremlin> g.V(hercules).as('h').out('battled').in('battled').where(neq('h')).values('name')
==>theseus
上面的示例有4个链接函数:out、in、exceptive和value(即name是value(‘name’)的缩写)。每个函数的签名都在下面逐项列出,其中V是顶点,U是任意对象,其中V是U的子集。
out: V -> V
in: V -> V
except: U -> U
values: V -> U
将函数链接在一起时,传入类型必须与传出类型匹配,其中U匹配任何内容。因此,上面的“协同作战/盟军”遍历是正确的。
Note
本节介绍的Gremlin概述主要关注Gremlin控制台中使用的gremlingroovy语言实现。请参阅连接到JanusGraph,了解有关使用Groovy以外的其他语言和独立于Gremlin控制台连接到JanusGraph的信息。
Gremlin控制台的一个方便的特性是,它自动迭代从Gremlin>提示符执行的查询的所有结果。这在REPL环境中运行良好,因为它将结果显示为字符串。当您过渡到编写Gremlin应用程序时,了解如何显式迭代遍历非常重要,因为应用程序的遍历不会自动迭代。以下是迭代遍历的一些常见方法:
下面显示了一个Java代码示例来演示这些概念:
Traversal t = g.V().has("name", "pluto"); // Define a traversal
// Note the traversal is not executed/iterated yet
Vertex pluto = null;
if (t.hasNext()) { // Check if results are available
pluto = g.V().has("name", "pluto").next(); // Get one result
g.V(pluto).drop().iterate(); // Execute a traversal to drop pluto from graph
}
// Note the traversal can be cloned for reuse
Traversal tt = t.asAdmin().clone();
if (tt.hasNext()) {
System.err.println("pluto was not dropped!");
}
List<Vertex> gods = g.V().hasLabel("god").toList(); // Find all the gods