基本用法
本节简要介绍Gremlin的功能集。 如需深入了解该主题,请参阅Gremlin查询语言。
本节中的示例广泛使用了JanusGraph附带的一个示例图,名为神之图。该图如下所示。抽象数据模型被称为 属性图模型 ,这个特定实例描述了罗马万神殿中生物和地点之间的关系。此外,图中的特殊文本和符号修饰符(例如粗体、下划线等)表示图中的不同模式/类型。

| 视觉符号 | 含义 |
|---|---|
| bold key | 一个图形索引键 |
| 带星号的粗体键 | 必须具有唯一值的图形索引键 |
| 带下划线的键 | 一个以顶点为中心的索引键 |
| hollow-head edge | 功能性/唯一性边(无重复) |
| tail-crossed edge | 单向边(只能单向遍历) |
将神图加载到JanusGraph中
下面的示例将打开一个JanusGraph图实例并加载上文图示的神之图数据集。JanusGraphFactory
提供了一组静态的open方法,每个方法都接受一个
配置作为参数并返回一个图实例。本
教程演示了使用辅助类GraphOfTheGodsFactory加载神之图
的不同配置。本节
略过配置细节,但有关
存储后端、索引后端及其配置的更多信息可在
存储后端、索引后端和
配置参考中找到。
使用索引后端加载
以下示例在使用了BerkeleyDB存储后端和Elasticsearch索引后端的配置上调用其中一个open方法:
gremlin> graph = JanusGraphFactory.open('conf/janusgraph-berkeleyje-es.properties')
==>standardjanusgraph[berkeleyje:../db/berkeley]
gremlin> GraphOfTheGodsFactory.load(graph)
==>null
gremlin> g = graph.traversal()
==>graphtraversalsource[standardjanusgraph[berkeleyje:../db/berkeley], standard]
JanusGraphFactory.open() and GraphOfTheGodsFactory.load() 方法在返回新构建的图之前会执行以下操作:
- 在图结构上创建全局和顶点中心索引的集合。
- 将所有顶点及其属性添加到图中。
- 将所有边及其属性添加到图中。
详情请参阅GraphOfTheGodsFactory源代码。
对于使用JanusGraph/Cassandra(或JanusGraph/HBase)的用户,请务必使用conf/janusgraph-cql-es.properties(或conf/janusgraph-hbase-es.properties)以及GraphOfTheGodsFactory.load()。
gremlin> graph = JanusGraphFactory.open('conf/janusgraph-cql-es.properties')
==>standardjanusgraph[cql:[127.0.0.1]]
gremlin> GraphOfTheGodsFactory.load(graph)
==>null
gremlin> g = graph.traversal()
==>graphtraversalsource[standardjanusgraph[cql:[127.0.0.1]], standard]
无索引后端加载
你也可以使用conf/janusgraph-cql.properties、
conf/janusgraph-berkeleyje.properties、conf/janusgraph-hbase.properties、
或conf/janusgraph-inmemory.properties配置文件来打开一个图
而不配置索引后端。在这种情况下,你需要
使用GraphOfTheGodsFactory.loadWithoutMixedIndex()方法来加载
Graph of the Gods,这样它就不会尝试使用
索引后端。
gremlin> graph = JanusGraphFactory.open('conf/janusgraph-cql.properties')
==>standardjanusgraph[cql:[127.0.0.1]]
gremlin> GraphOfTheGodsFactory.loadWithoutMixedIndex(graph, true)
==>null
gremlin> g = graph.traversal()
==>graphtraversalsource[standardjanusgraph[cql:[127.0.0.1]], standard]
信息
使用除conf/janusgraph-inmemory.properties之外的任何配置文件
都需要您配置并运行一个专用后端。如果您只是
想快速打开一个图实例并探索一些JanusGraph功能,
您可以直接选择conf/janusgraph-inmemory.properties来打开一个
in-memory backend。
全局图索引
在图数据库中访问数据的典型模式是首先使用图索引定位图的入口点。该入口点是一个元素(或一组元素)——即顶点或边。从入口元素开始,Gremlin路径描述通过显式图结构描述了如何遍历到图中的其他元素。
鉴于name属性上存在唯一索引,可以检索到Saturn顶点。随后可以检查属性映射(即Saturn的键/值对)。如演示所示,Saturn顶点具有name值为"saturn"、age值为10000以及type值为"titan"。通过一个表示"谁是Saturn的孙子?"("father"的逆关系是"child")的遍历可以检索到Saturn的孙子。结果是Hercules。
gremlin> saturn = g.V().has('name', 'saturn').next()
==>v[256]
gremlin> g.V(saturn).valueMap()
==>[name:[saturn], age:[10000]]
gremlin> g.V(saturn).in('father').in('father').values('name')
==>hercules
属性 place 也在图索引中。属性 place 是一个边属性。因此,JanusGraph 可以在图索引中索引边。可以查询 神图 中所有发生在距离 Athens(纬度:37.97,经度:23.72)50公里范围内的事件。然后,根据这些信息,哪些顶点参与了这些事件。
gremlin> g.E().has('place', geoWithin(Geoshape.circle(37.97, 23.72, 50)))
==>e[a9x-co8-9hx-39s][16424-battled->4240]
==>e[9vp-co8-9hx-9ns][16424-battled->12520]
gremlin> g.E().has('place', geoWithin(Geoshape.circle(37.97, 23.72, 50))).as('source').inV().as('god2').select('source').outV().as('god1').select('god1', 'god2').by('name')
==>[god1:hercules, god2:hydra]
==>[god1:hercules, god2:nemean]
g.V)或所有边(g.E)满足一个或多个约束条件(例如has或interval)的问题。JanusGraph中索引的第二个方面被称为顶点中心索引。顶点中心索引用于加速图内部的遍历。顶点中心索引将在后面描述。
图遍历示例
Hercules,朱庇特与 Alcmene之子,拥有超人的 力量。赫拉克勒斯是一位 Demigod,因为他的父亲是 神而母亲是人类。 Juno,朱庇特的妻子, 对朱庇特的不忠感到愤怒。为了报复,她 让赫拉克勒斯暂时精神错乱,导致他杀害了自己的 妻子和孩子。为了赎罪,赫拉克勒斯被 Oracle of Delphi 命令为Eurystheus服务。 欧律斯透斯指派赫拉克勒斯完成12项任务。
在上一节中,演示了Saturn的孙子是Hercules。这可以使用loop来表达。本质上,Hercules是沿着in('father')路径距离Saturn两步远的顶点。
gremlin> hercules = g.V(saturn).repeat(__.in('father')).times(2).next()
==>v[1536]
赫拉克勒斯是一位半神。要证明赫拉克勒斯半人半神,必须检查他父母的出身。可以从赫拉克勒斯顶点遍历到他的母亲和父亲。最后,可以确定他们各自的type——得出"god"和"human"。
gremlin> g.V(hercules).out('father', 'mother')
==>v[1024]
==>v[1792]
gremlin> g.V(hercules).out('father', 'mother').values('name')
==>jupiter
==>alcmene
gremlin> g.V(hercules).out('father', 'mother').label()
==>god
==>human
gremlin> hercules.label()
==>demigod
到目前为止的示例都是关于罗马万神殿中各位角色的血缘谱系。属性图模型具有足够的表达能力来表示多种类型的事物和关系。通过这种方式,《诸神图谱》还记录了赫拉克勒斯的各种英雄事迹——他著名的十二项任务。在上一节中,发现赫拉克勒斯在雅典附近参与了两场战斗。可以通过遍历赫拉克勒斯顶点发出的battled边来探索这些事件。
gremlin> g.V(hercules).out('battled')
==>v[2304]
==>v[2560]
==>v[2816]
gremlin> g.V(hercules).out('battled').valueMap()
==>[name:[nemean]]
==>[name:[hydra]]
==>[name:[cerberus]]
gremlin> g.V(hercules).outE('battled').has('time', gt(1)).inV().values('name')
==>cerberus
==>hydra
边属性 time 在 battled 边上通过顶点的顶点中心索引进行索引。根据 time 上的约束/过滤器检索与Hercules相关的 battled 边比线性扫描所有边并进行过滤更快(通常为 O(log n),其中 n 是相关边的数量)。JanusGraph足够智能,在可用时会使用顶点中心索引。Gremlin表达式的 toString() 显示分解为各个步骤。
gremlin> g.V(hercules).outE('battled').has('time', gt(1)).inV().values('name').toString()
==>[GraphStep([v[24744]],vertex), VertexStep(OUT,[battled],edge), HasStep([time.gt(1)]), EdgeVertexStep(IN), PropertiesStep([name],value)]
更复杂的图遍历示例
在塔尔塔罗斯深处居住着冥王普路托。他与赫拉克勒斯的关系因赫拉克勒斯曾与其宠物刻耳柏洛斯战斗而紧张。然而,赫拉克勒斯是他的侄子——他该如何让赫拉克勒斯为他的无礼付出代价?
以下Gremlin遍历在诸神图谱上提供了更多示例。每个遍历的解释在前一行以//注释形式提供。
塔尔塔罗斯的共居者
gremlin> pluto = g.V().has('name', 'pluto').next()
==>v[2048]
gremlin> // who are pluto's cohabitants?
gremlin> g.V(pluto).out('lives').in('lives').values('name')
==>pluto
==>cerberus
gremlin> // pluto can't be his own cohabitant
gremlin> g.V(pluto).out('lives').in('lives').where(is(neq(pluto))).values('name')
==>cerberus
gremlin> g.V(pluto).as('x').out('lives').in('lives').where(neq('x')).values('name')
==>cerberus
冥王星的兄弟
gremlin> // where do pluto's brothers live?
gremlin> g.V(pluto).out('brother').out('lives').values('name')
==>sky
==>sea
gremlin> // which brother lives in which place?
gremlin> g.V(pluto).out('brother').as('god').out('lives').as('place').select('god', 'place')
==>[god:v[1024], place:v[512]]
==>[god:v[1280], place:v[768]]
gremlin> // what is the name of the brother and the name of the place?
gremlin> g.V(pluto).out('brother').as('god').out('lives').as('place').select('god', 'place').by('name')
==>[god:jupiter, place:sky]
==>[god:neptune, place:sea]
最后,Pluto居住在Tartarus,因为他表现出对死亡毫不在意。 而他的兄弟们则根据他们对这些地点某些特质的喜爱来选择他们的居所。!
gremlin> g.V(pluto).outE('lives').values('reason')
==>no fear of death
gremlin> g.E().has('reason').textContains('loves'))
==>e[6xs-sg-m51-e8][1024-lives->512]
==>e[70g-zk-m51-lc][1280-lives->768]
gremlin> g.E().has('reason').textContains('loves')).as('source').values('reason').as('reason').select('source').outV().values('name').as('god').select('source').inV().values('name').as('thing').select('god', 'reason', 'thing')
==>[god:neptune, reason:loves waves, thing:sea]
==>[god:jupiter, reason:loves fresh breezes, thing:sky]