跳到内容

基本用法

本节简要介绍 Gremlin 的功能集。有关该主题的更深入了解,请参阅Gremlin 查询语言

本节中的示例广泛使用了 JanusGraph 附带的一个示例图,称为《众神图》。该图如下所示。抽象数据模型被称为属性图模型,此特定实例描述了罗马万神殿中存在物和地点之间的关系。此外,图中的特殊文本和符号修饰符(例如粗体、下划线等)表示图中的不同模式/类型。

Graph of the Gods

视觉符号 含义
粗体键 一个图索引键
带星号的粗体键 一个必须具有唯一值的图索引键
下划线键 一个以顶点为中心的索引键
空心箭头边 一个功能/唯一边(无重复)
尾部交叉边 一个单向边(只能在一个方向遍历)

将众神图加载到 JanusGraph 中

下面的示例将打开一个 JanusGraph 图实例,并加载上面示意图中的《众神图》数据集。JanusGraphFactory 提供了一组静态的 open 方法,每个方法都将配置作为其参数并返回一个图实例。本教程演示了使用辅助类 GraphOfTheGodsFactory 和不同的配置加载《众神图》。本节跳过配置细节,但有关存储后端、索引后端及其配置的更多信息可在存储后端索引后端配置参考中找到。

使用索引后端加载

下面的示例调用了其中一个 open 方法,该方法配置使用BerkeleyDB存储后端和Elasticsearch索引后端

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()GraphOfTheGodsFactory.load() 方法在返回新构造的图之前执行以下操作

  1. 在图上创建全局索引和以顶点为中心的索引集合。
  2. 将所有顶点及其属性添加到图中。
  3. 将所有边及其属性添加到图中。

详情请参阅 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.propertiesconf/janusgraph-berkeleyje.propertiesconf/janusgraph-hbase.propertiesconf/janusgraph-inmemory.properties 配置文件打开一个未配置索引后端的图。在这种情况下,您需要使用 GraphOfTheGodsFactory.loadWithoutMixedIndex() 方法加载《众神图》,这样它就不会尝试使用索引后端。

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 来打开一个内存后端

全局图索引

访问图数据库中数据的典型模式是首先使用图索引定位图的入口点。该入口点是一个元素(或一组元素)——即顶点或边。从入口元素开始,Gremlin 路径描述了如何通过显式图结构遍历到图中的其他元素。

鉴于 `name` 属性上有一个唯一索引,可以检索到 Saturn 顶点。然后可以检查属性图(即 Saturn 的键/值对)。如所示,Saturn 顶点有一个名为 "saturn" 的 `name`,一个 10000 的 `age`,以及一个 "titan" 的 `type`。Saturn 的孙子可以通过遍历检索,该遍历表达:“Saturn 的孙子是谁?”("father" 的反义词是 "child")。结果是 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 可以在图索引中索引边。可以查询《众神图》以查找在雅典(纬度: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]
图索引是 JanusGraph 中的一种索引结构。图索引由 JanusGraph 自动选择,用于回答所有顶点 (g.V) 或所有边 (g.E) 满足一个或多个约束(例如 hasinterval)的查询。JanusGraph 中索引的第二个方面称为顶点中心索引。顶点中心索引用于加速图内部的遍历。顶点中心索引稍后介绍。

图遍历示例

赫拉克勒斯,朱庇特和阿尔克墨涅的儿子,拥有超人力量。赫拉克勒斯是半神,因为他的父亲是神,母亲是人类。朱诺,朱庇特的妻子,对朱庇特的出轨感到非常愤怒。作为报复,她让赫拉克勒斯暂时精神失常,导致他杀死了自己的妻子和孩子。为了赎罪,赫拉克勒斯被德尔斐神谕命令去侍奉欧律斯透斯。欧律斯透斯指派赫拉克勒斯完成十二项功绩。

在上一节中,我们演示了 Saturn 的孙子是 Hercules。这可以使用 loop 来表达。本质上,Hercules 是距离 Saturn 沿 in('father') 路径两步的顶点。

gremlin> hercules = g.V(saturn).repeat(__.in('father')).times(2).next()
==>v[1536]

赫拉克勒斯是一个半神。为了证明赫拉克勒斯是半人半神,必须检查他父母的出身。可以从赫拉克勒斯顶点遍历到他的母亲和父亲。最后,可以确定他们每个人的 type —— 得到“神”和“人类”。

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

battled 边上的边属性 time 由顶点的顶点中心索引进行索引。根据对 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]

最后,冥王普鲁托住在塔耳塔罗斯,因为他对死亡毫无顾虑。而他的兄弟们则根据对那些地方某些特质的喜爱选择了他们的住所!

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]