JanusGraph 入门指南

原创 janusgraph

本节中的示例广泛使用与 JanusGraph 一起分发的示例图(Graph),称为神的图形(The Graph of the Gods)。 该图如下图所示。 抽象数据模型被称为属性图模型,这个特定的实例描述了罗马万神殿的神和地点之间的关系。 此外,图中的特殊文本和符号修饰符(例如粗体,下划线等)表示图中的不同示意图/类型。

Figure 3.1. Graph of the Gods

下载 JanusGraph 和运行 Gremlin 命令行

JanusGraph 可以从项目仓库的 Releases 部分下载。 一旦检索并解压缩,就可以打开 Gremlin 控制台。 Gremlin 控制台是一个 REPL(即交互式 shell),与 JanusGraph 一起分发,与标准 Gremlin 控制台不同,因为 JanusGraph 是预装和预加载的软件包。 或者,用户可以通过从中央存储库下载 JanusGraph 包来选择在现有 Gremlin 控制台中安装和激活 JanusGraph。 在下面的示例中,使用了 janusgraph.zip,但是,请务必解压缩下载的zip文件。

重要:JanusGraph 需要 Java 8 (Standard Edition)。 建议使用 Oracle Java 8。 JanusGraph 的 shell 脚本期望 $JAVA_HOME 环境变量指向安装 JRE 或 JDK 的目录。

$ unzip janusgraph-0.3.0-hadoop2.zip
Archive:  janusgraph-0.3.0-hadoop2.zip
  creating: janusgraph-0.3.0-hadoop2/
...
$ cd janusgraph-0.3.0-hadoop2
$ bin/gremlin.sh

         \,,,/
         (o o)
-----oOOo-(3)-oOOo-----
09:12:24 INFO  org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph  - HADOOP_GREMLIN_LIBS is set to: /usr/local/janusgraph/lib
plugin activated: tinkerpop.hadoop
plugin activated: janusgraph.imports
gremlin>

Gremlin 控制台使用 Apache Groovy 解释命令。 Groovy 是 Java 的超集,具有各种简写符号,使交互式编程更容易。 同样,Gremlin-Groovy 是 Groovy 的超集,其中包含各种简写符号,使图形遍历变得容易。 下面的基本示例演示了处理数字,字符串和映射。 本教程的其余部分将讨论特定于图形的构造(graph-specific constructs)。

gremlin> 100-10
==>90
gremlin> "JanusGraph:" + " The Rise of Big Graph Data"
==>JanusGraph: The Rise of Big Graph Data
gremlin> [name:'aurelius', vocation:['philosopher', 'emperor']]
==>name=aurelius
==>vocation=[philosopher, emperor]

提示:有关使用 Gremlin 的更多信息,请参阅 Apache TinkerPopSQL2GremlinGremlin Recipes

读取诸神关系图到 JanusGraph

下面的示例将 open 一个 JanusGraph 图形实例,并加载上图所示的诸神图数据集。 JanusGraphFactory 提供了一组静态 open 方法,每个方法都拥有一个配置参数,并返回图形实例。 本教程在使用 BerkeleyDB 存储后端和Elasticsearch 索引后端的配置上调用其中一个 open 方法,然后 helper 类 GraphOfTheGodsFactory 加载诸神图形。 本节将跳过配置详细信息,但有关存储后端,索引后端及其配置的其他信息,请参见 第III部分“存储后端”第IV部分,“索引后端”第15章“配置参考”

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

  • 在图形上创建全局和以顶点(vertex)为中心的索引的集合。
  • 将所有顶点及其属性添加到图形中。
  • 将所有边(edge)及其属性添加到图形中。

有关详细信息,请参阅 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]

全局索引

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

鉴于 name 属性上有唯一索引,可以检索 Saturn (克洛诺斯)顶点。然后可以检查属性图(即 Saturn 的键/值对)。 如图所示,顶点 Saturnname 为 "saturn",age 为 10000,type 为 "titan"。Saturn 的“孙子”可以通过遍历表示:“谁是 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可以索引图索引中的边。可以查询众神图获得对于在雅典 50 公里范围内发生的所有事件(北纬:37.97和长:23.72)。然后,给定该信息,哪些顶点涉及哪些事件。

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)。JanusGraph 中索引的第二个方面称为以顶点为中心的索引。以顶点为中心的索引用于加速图中的遍历。 以顶点为中心的索引将在后面描述。

图遍历示例

Jupiter 和 Alcmene 的儿子 Hercules 拥有超人的力量。 Hercules 是一个半神半人,因为他的父亲是一个神,他的母亲是一个人。 Jupiter 的妻子 Juno) 对 Jupiter 的不忠感到愤怒。 为了复仇,她疯狂地使 Hercules 暂时失明,并导致他杀死了他的妻子和孩子。 为了赎罪,Hercules 被 Oracle of Delphi 命令为 Eurystheus 服务。 Eurystheus 命令 Hercules 完成 12 个考验。

在上一节中,证明了 Saturn 的孙子是 Hercules。 这可以用循环 loop 表示。 从本质上讲,Hercules 是沿着(father)路径离 Saturn 两步之遥的顶点。

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

Hercules 是一个半神半人。 为了证明 Hercules 是半人半神,必须检查他父母的起源。这是有可能从 Hercules 顶点到他的母亲和父亲的。最后,可以确定它们的类型 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

到目前为止,这些例子涉及罗马万神殿中各种人物的起源线。属性图模型(Property Graph Model)足以表达多种类型的事物和关系。通过这种方式,众神之图也确定了 Hercules 的各种英雄事迹 - 他著名的 12 个考验。在上一节中,发现 Hercules 参与了雅典附近的两场战斗。可以通过遍历 Hercules 顶点的 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 上的约束/过滤器(constraint/filter)检索 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)]

更复杂的图遍历示例

在 Tartarus 的深处生活着 Pluto。 他与 Hercules 的关系因 Hercules 与他的宠物 Cerberus 战斗而紧张。然而,Hercules 是他的侄子 - 他怎么能让 Hercules 为他的傲慢付出代价呢?

下面的 Gremlin 遍历提供了更多关于诸神图的例子。每个遍历的前一行有 // 注释作为解释。

Tartarus 的同居者

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

Pluto 的兄弟

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]

JanusGraph 官方文档原文地址:https://docs.janusgraph.org/latest/getting-started.html

如果觉得这对你有用,请随意赞赏,给与作者支持
评论 0
最新评论