TinkerPop3 中文文档翻译

写在前面:译者的话

翻译:knightjya

译者是在调研janusgraph时,发现这个TinkerPop的文档没有比较完整、比较好的翻译。因此决定开始翻译该文档。中间加入了很多译者本身在实际应用中的思考或者踩过的坑,也会对比较重要的地方详细注解,翻译、注解不易,请在转载前务必咨询译者!我的邮箱 lkoplo001@126.com 。

TinkerPop3 中文文档

开始…

TinkerPop0

Gremlin理解了。他做的越多,他创造的想法就越多。他创造的想法越多,它们之间的联系就越多。在他全心全意地接受的东西,或者可能最终通过一致的意志变成某种东西的世界中,一个世界的形式似乎与他自己的实现逐渐分离。但是,如果没有Gremlin已经接受的逻辑,出生的世界将无法承受自己的重压——向左的逻辑与向右的逻辑相左,向上与向下相悖,而且西方东方间隔甚远,除非有人走另一条路。Gremlin的实现需要Gremlin的实现。也许,世界只是他曾经拥有的一个想法——TinkerPop。注(1)

gremlin logo

TinkerPop1

什么是TinkerPop?TinkerPop在哪里?谁是TinkerPop?什么时候是TinkerPop?他越想知道,这些想法就越模糊成一种看似相同的特征——区别不清。不愿接受徘徊于迷宫般的沼泽,Gremlin设计了一系列机器来帮助将织物固定在一起: Blueprints, Pipes , Frames , Furnace 和Rexster注(2)。在他们的帮助下,格雷姆林能阻止他还没准备好拥有的想法吗?他可以通过搜索TinkerPop来阻止TinkerPop吗?

"如果我没找到它, 他现在就不在这里."

gremlin and friends

一旦意识到他们的存在,机器便变成他们的机器妖精创造者,并问:

"为什么是我,我是‘什么’?"

格林姆林回应:

"您将帮助我实现最终的实现——TinkerPop。您所处的世界以及
允许您继续前进的逻辑是因为TinkerPop所致。"

机器想知道:

“如果‘什么’是TinkerPop,那么也许我们就是TinkerPop,而我们的实现仅仅
是TinkerPop 的实现?”

根据实现TinkerPop的本质,这些机器会是TinkerPop吗?或者,在硬币的同一侧,这些机器是否只是提供了脚手架,使格莱姆林宫的世界得以维持自己并通过“ TinkerPop”一词来证明其正当性?无论如何,结果都一样-TinkerPop注(3)

TinkerPop2

格林姆林说:

"请听我说的话。我离TinkerPop很近。但是,一直以来,TinkerPop都
拥护我愿意的形式……这与我对你们所希望的形式相同,我的机器朋友们。让我
以我的所希望的方式训练你们,使它可以无限期地继续下去吧。"

在这里插入图片描述

这些机器通过算法简单地遍历了Gremlin的世界,就认可了他的逻辑。Gremlin努力使他们更有效率,更具表现力,更有能力根据他的思想进行推理。更快,快速的,现在走向世界的尽头,这世界的尽头将永远在‘现在’,散发着、吞噬着他——TinkerPop。

TinkerPop3

在这里插入图片描述

Gremlin走近了TinkerPop。他越近,他的世界越消散—西方是右边的,周遭又是笔直的,不创造任何东西却并非空无一物。迈向TinkerPop的每一步,更多的世界都变成了可能。在TinkerPop中,任何事物都是任何事物,尘埃落定后,Gremlin生成了Gremlitron。他意识到他所意识到的只是一个实现,而所有已实现的实现都是真实的。这就是-TinkerPop。

gremlintron

NOTETinkerPop2及以下版本在各种TinkerPop项目之间有明显的区别: Blueprints, Pipes, Gremlin, Frames, Furnace, 和Rexster。 借助TinkerPop3,所有这些项目都已合并,通称为Gremlin。 Blueprints → Gremlin Structure API : PipesGraphTraversal : FramesTraversal : FurnaceGraphComputer 还有VertexProgram : Rexster → GremlinServer.
有关TinkerPop 3.x与早期版本之间的区别的更多信息,请参见链接:http://tinkerpop.apache.org/docs/3.4.4/upgrade/#appendix
译者注这里我整合了两个版本的tinkerpop文档的这部分,为了方便大家理解,分别是3.2.6和

介绍

欢迎使用Apache TinkerPop™参考文档-有关如何使用TinkerPop和Gremlin图形遍历语言的所有详细信息的主干。本文档不是要作为“书”,而是从中可以衍生出更详细的特定主题说明以及所有其他资源所指向的目标。参考文档对读者做出了一些一般性的假设:

  1. 他们对图是什么有一定了解——不确定是否了解吗?请参阅实用的Gremlin-为什么选择图?
  2. 他们知道图系统启用TinkerPop意味着什么-不确定是否了解吗?查看启用TinkerPop的提供商
  3. 他们知道Gremlin扮演的角色-不确定是否了解吗?请参阅链接:Gremlin简介

有了这些假设,就可以更快地深入细节,而无需花费大量时间重复在其他地方写的内容。

可以肯定的是,参考文档的读者来自TinkerPop在其存在的十年左右的时间里从事的最多样化的软件开发背景。虽然TinkerPop在Java中具有某些根源,因此与Java虚拟机(JVM)绑定有多种语言,但很久以前它已扩展为其他语言,例如Python,Javascript,.NET等。为了增加多样性,还得到了不同图形系统的广泛支持,这些图形系统选择了TinkerPop作为允许用户与其图形接口的标准方法。此外,图形系统本身不仅被OLTP和OLAP风格的工作负载所分隔,还被其实现模式所分隔,其实现范围从嵌入式图系统到仅云图注(4)不等。

在这里插入图片描述

尽管存在种种多样性和差异,Gremlin仍然是图社区所有这些不同元素的统一界面。作为用户,在构建应用程序时选择启用TinkerPop图并以正确的方式使用Gremlin可以保护它们免受空间变化和差异的影响。作为图提供者,选择启用TinkerPop功能不仅可以扩展其系统进入不同开发生态系统的范围,而且还可以通过字节码编译(如sparql-gremlin所示)访问其他查询语言。

无论使用哪种编程语言,选择的图形系统或其他可能促使用户使用此文档的开发背景,都要记住的关键点是“ Gremlin是Gremlin是Gremlin”注(5)。在内存TinkerGraph上为OLTP查询编写的同一Gremlin与在OLAP中通过Spark通过数十亿张边图执行的Gremlin相同。无论使用Java还是Python或Javascript,对于任何一种情况,相同的Gremlin都以相同的方式编写注(6)。除了可能存在特定于语言的语法差异外,Gremlin始终基本相同-例如,Groovy中的lambda的构造与Python中的lambda的构造或Javascript中的保留字的构造不同,这迫使Gremlin步骤的命名稍有不同比Java。

虽然学习Gremlin语言及其模式在很大程度上与该空间中的所有多样性无关,但是从应用程序开发的角度来看,实际上不可能忽略多样性的影响,并且参考文档努力尝试指出差异之处不一致之处可能在于没有深入研究特定的图形提供程序实现。强烈建议用户查阅其选择的图形提供者的文档,以了解可能限制或禁止使用TinkerPop API某些方面的所有功能和限制,这些功能和限制在本参考文档中定义。注(7)

以下介绍部分和单独引用的内容将对不同的读者产生不同的兴趣。希望以下摘要有助于将个人引导到适当的地方,开始他们的学习过程。

  • Graph Computing是“图形计算”对TinkerPop的含义的介绍,并描述了许多支持Gremlin的提供商和面向用户的TinkerPop API和概念。
  • 连接Gremlin提供了有关用户根据其环境连接到图形的不同模式的描述。
  • Basic Gremlin介绍了如何使用连接来开始编写Gremlin。
  • 保持不可知论性提供了有关如何使Gremlin在不同图形提供者之间尽可能具有可移植性的提示。

新用户不应忽略TinkerPop的入门 教程或Gremlin Console教程。两者都包含大量的基本信息和提示,可以帮助读者尽早避免一些一般性的陷阱。两者都集中在Gremlin控制台中的Gremlin用法上,这对于任何开发背景的Gremlin开发人员来说都是重要的工具。

经验丰富的高级用户会喜欢Gremlin配方 ,这些配方提供了常见的Gremlin遍历模式的示例。

最后,所有Gremlin开发人员都应该熟悉 Kelvin Lawrence的“ Practical Gremlin”。这本书可免费获得并在线出版。它包含了出色的示例和细节,适用于使用Gremlin构建应用程序的任何人。

图计算

graph computing

一个是顶点(节点,点)和边缘(弧,线)组成的数据结构。当在计算机中为图建模并将其应用于现代数据集和实践时,通用的面向数学的二进制图已扩展为既支持标签又支持键/值属性。这种结构称为属性图。更正式地说,它是有向的,二进制的,有属性的多图。下面是一个示例属性图。

tinkerpop modern

Figure 1. TinkerPop Modern

TIP了解这种图形结构,因为它在整个文档中以及在更广泛的圈子中被广泛使用。它被称为“ TinkerPop Modern”,因为它是2009年与TinkerPop0一起分发的原始演示图的现代变体(例如,往日美好时光-当时是最好的时期,也是最糟糕的时期)。
TIPThe Gremlin Console教程 中描述了TinkerPop中可用的所有玩具图 注(8)

与一般的计算类似,图计算在结构(图)和过程 (遍历)之间进行区分。图的结构是由顶点/边/属性拓扑定义的数据模型 。图形的过程是分析结构的手段。图处理的典型形式称为 遍历

tinkerpop enabledTinkerPop在图计算中的作用是为图提供者和用户提供适当的接口,以在其结构和过程上与图进行交互。当图形系统实现TinkerPop结构和流程 API时,其技术被视为支持 *TinkerPop,*并且与其他任何启用TinkerPop的图形系统几乎没有区别,只是它们各自的时间和空间复杂性不同。本文档的目的是详细描述结构/过程的二分法,并在此过程中解释如何将TinkerPop用于与图系统无关的图计算的唯一目的。

重要TinkerPop是根据流行的Apache2 免费软件许可获得许可的。但是,请注意,与TinkerPop一起使用的基础图形引擎可能具有不同的许可证。因此,请务必遵守图形系统产品的许可注意事项。

一般而言,结构或“图形” API用于 实现TinkerPop接口的图形提供程序,而流程或“遍历” API(即Gremlin)用于使用图形提供程序的图形系统的最终用户。虽然下面详细列出了流程API的组件,但在Gremlin的剖析注(9) 教程中对它们进行了更详细的描述。

TinkerPop 结构 API的主要组件

  • Graph:维护一组顶点和边,并访问数据库功能(例如事务)。
  • Element:维护属性的集合和表示元素类型的字符串标签。
    • Vertex:扩展Element并维护一组传入和传出边缘。
    • Edge:扩展Element并维护传入和传出的顶点。
  • Property:与V值关联的字符串键。
    • VertexProperty:与V值以及Property属性集合关联的字符串键(仅顶点

TinkerPop 流程 API的主要组件

  • TraversalSource:针对特定图形,领域特定语言(DSL)和执行引擎的遍历生成器。
    • Traversal:一个功能数据流过程,将类型的S对象转换为类型的对象E
      • GraphTraversal:面向原始图的语义(即顶点,边等)的遍历DSL。
  • GraphComputer:并行处理图形的系统,并有可能分布在多计算机集群上。
    • VertexProgram:在所有顶点以逻辑并行方式执行的代码,并通过消息传递进行互通。
    • MapReduce:一种计算,可以并行分析图中的所有顶点,并产生一个简化的结果。
注意TinkerPop API在提供简洁的“查询语言”方法名称和遵守Java方法命名标准之间有着很好的界限。整个TinkerPop有关使用的一般惯例是,如果一个方法是“用户暴露”,则提供一个简明的名称(例如out()path()repeat())。如果该方法主要是为图形系统提供者,则按照标准的Java命名约束如下(例如getNextStep()getSteps()getElementComputeKeys())。

图结构

gremlin standing图的结构是由其顶点,边和属性之间的显式引用形成的拓扑。顶点具有入射边。如果一个顶点共享一个入射边,则它们与另一个顶点相邻。将属性附加到元素,并且元素具有一组属性。属性是键/值对,其中键始终是一个character String。对于最终用户而言,使用图的概念知识对于使用图形的最终用户至关重要,但是,如前所述,结构API不是用户使用TinkerPop构建应用程序时思考的合适方法。结构API保留供图提供者使用。那些对实现结构API以使其图形系统启用TinkerPop感兴趣的人可以在Graph Provider中了解有关它的更多信息 、文档。

图过程

gremlin running处理图的主要方式是通过图遍历。TinkerPop流程API的重点是允许用户在上一节中定义的结构上以语法友好的方式创建图形遍历。遍历是根据图数据结构中显式的引用结构跨图元素进行的算法遍历。例如:“顶点1的朋友可以使用什么软件?” 可以用以下算法/遍历方式表示该英语语句:

  1. 从顶点1开始。
  2. 将事件的已知边沿移至各个相邻的1个朋友顶点。
  3. 通过创建的边缘从那些朋友顶点移动到软件顶点。
  4. 最后,选择当前软件顶点的名称-属性值。

Gremlin中的遍历是从TraversalSource生成的。GraphTraversalSource是整个文档中使用的典型的“面向图形”DSL,很可能是TinkerPop应用程序中使用最多的DSL。GraphTraversalSource提供了两种遍历方法。

  1. GraphTraversalSource.V(Object… ids):从图形的顶点开始生成遍历(如果未提供ID,则为所有顶点)。
  2. GraphTraversalSource.E(Object… ids):从图形的边缘开始生成遍历(如果未提供ID,则为所有边缘)。

的返回类型V()E()GraphTraversal。GraphTraversal维护许多返回的方法 GraphTraversal。这样,GraphTraversal支持功能组合。的每个方法GraphTraversal都称为一个步骤,并且每个步骤都以五种通用方式之一调制前一步骤的结果。

  1. map:将传入的遍历器的对象转换为另一个对象(S→E)。
  2. flatMap:将传入的遍历器的对象转换为其他对象的迭代器(S→E *)。
  3. filter:允许或禁止行进器进行下一步(S→E→S)。
  4. sideEffect:允许遍历器保持不变,但会在过程中产生一些计算上的副作用(S↬S)。
  5. branch:分割遍历器并将其发送到遍历中的任意位置(S→{S 1 →E *,…,S n →E *}→E *)。

GraphTraversal 中的几乎每个步骤都扩展了 MapStepFlatMapStepFilterStepSideEffectStepBranchStep

TIPGraphTraversal是一个monoid,因为它是一个代数结构,具有单个关联的二进制运算。二进制运算是功能组合(即方法链接),并且其标识是步骤identity()。这与功能编程社区所流行的monad有关 。

给定TinkerPop图,以下查询将返回marko-vertex知道的所有人员的姓名。使用Gremlin-Groovy演示了以下查询。

$ bin/gremlin.sh

         \,,,/
         (o o)
-----oOOo-(3)-oOOo-----
gremlin> graph = TinkerFactory.createModern() //1
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal()        //2
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().has('name','marko').out('knows').values('name') //3
==>vadas
==>josh
  1. 打开玩具图注(8),并通过变量graph引用它。
  2. 使用标准的OLTP遍历引擎从图形创建图形遍历源。
  3. 从遍历源中生成遍历,该遍历确定了marko-vertex认识的人员的姓名。

在这里插入图片描述

Figure 2. The Name of The People That Marko Knows

或者,如果marko-vertex已通过直接引用指针(即变量)实现,则可以从该顶点产生遍历。

控制台(groovy)注(10)

gremlin> marko = g.V().has('name','marko').next() //1\
==>v[1]
gremlin> g.V(marko).out('knows') //2\
==>v[2]
==>v[4]
gremlin> g.V(marko).out('knows').values('name') //3\
==>vadas
==>josh

groovy:

marko = g.V().has('name','marko').next() //1\
g.V(marko).out('knows') //2\
g.V(marko).out('knows').values('name') //3\
  1. 将变量marko设置为的图形g中的名为“ marko” 顶点。
  2. 通过knows边,获取与标记顶点相邻的传出顶点 marko 。
  3. 获取marko-vertex朋友的名字。
遍历器注(11)

当执行遍历时,遍历的源位于表达式的左侧(例如顶点1),步骤位于遍历的中间(例如out('knows')values('name')),结果为“ traversal.next()'d”在遍历的右边(例如“ vadas”和“ josh”)。

traversal mechanics

通过遍历传播的对象被包裹在Traverser<T>。遍历器提供了使步骤保持无状态的方法。遍历器维护有关遍历的所有元数据,例如遍历遍历循环的次数,遍历器的路径历史记录,正在遍历的当前对象等。遍历遍历器的元数据可以通过一个步骤访问。一个经典的例子是path()-step。

控制台(groovy)注(10)

gremlin> g.V(marko).out('knows').values('name').path()
==>[v[1],v[2],vadas]
==>[v[1],v[4],josh]

groovy:

g.V(marko).out('knows').values('name').path()
警告路径计算在空间方面是昂贵的,因为在各个遍历器的每个路径中存储了一系列先前看到的对象。因此,遍历策略分析遍历以确定是否需要路径元数据。如果不是,则路径计算被关闭。

另一个示例是repeat()-step,它考虑了遍历遍历表达式的特定部分(即循环)的次数。

控制台(groovy)注(10)

gremlin> g.V(marko).repeat(out()).times(2).values('name')
==>ripple
==>lop

groovy:

g.V(marko).repeat(out()).times(2).values('name')
警告TinkerPop不保证遍历返回结果的顺序。它仅保证不修改基础图提供的迭代顺序。因此,了解所用图形数据库的顺序保证很重要。遍历的结果永远不会由TinkerPop排序,除非通过-step明确执行order()

连接Gremlin

它在最初的介绍部分中已经被确立了,即Gremlin是Gremlin是Gremlin注(5),这意味着无论编程语言,图形系统如何,该Gremlin始终具有相同的一般构造,使用户可以在开发语言和TinkerPop-轻松启用图形技术。Gremlin的这种素质通常适用于遍历语言本身。它不适用于用户连接到图以使用Gremlin的方式,这可能会因所选的编程语言或图数据库而有很大差异。

一个人如何连接到图形是一个多方面的主题,它基本上沿着简单的线划分,该线由以下问题的答案确定:Gremlin遍历机注(12)(GTM)在哪里?这个问题如此重要的原因是因为GTM负责处理遍历。可以用任何语言编写Gremlin遍历,但是如果没有GTM,就无法对启用TinkerPop的图形执行遍历。GTM通常位于以下位置之一:

以下各节概述了每个模型,以及它们对使用Gremlin的影响。

嵌入式的

blueprints character 1TinkerPop维护GTM的参考实现注(15),该参考实现是用Java编写的,因此可用于Java虚拟机(JVM)。这是TinkerPop长期以来一直基于的经典模型,并且将以这种样式演示互联网上的许多示例,博客文章和其他资源。值得注意的是,嵌入式模式不仅限于Java作为一种编程语言。任何JVM语言都可以采用这种方法,并且在某些情况下,特定于语言的包装程序可以帮助Gremlin以该语言的样式和功能更方便地使用。这些包装的示例包括 gremlin-scalaOgre(用于Clojure)。

在这种模式下,用户将首先创建一个Graph实例,然后创建一个实例,GraphTraversalSource从该实例中产生Gremlin遍历。允许这种直接实例化的图显然是基于JVM(或具有基于JVM的连接器)并直接实现TinkerPop接口的图。

Graph graph = TinkerGraph.open();

然后,“ graph ”产生如下的GraphTraversalSource,通常,按照惯例,此变量名为“ g”注(16)

GraphTraversalSource g = graph.traversal();
List<Vertex> vertices = g.V().toList()
注意阅读Gremlin Anatomy 教程可能会有所帮助,该教程描述了Gremlin的组成部分,以便在进一步进行操作之前更好地理解术语。

虽然TinkerPop社区努力确保所有使用模式之间的行为一致,但嵌入式模式确实提供了最大程度的灵活性和控制力。只有使用JVM语言时,才能使用许多功能。以下列表概述了许多这些可用选项:

  • Lambda可以用本机语言编写,这很方便,但是,如果需要从嵌入式模式切换到其他语言,则会降低Gremlin的可移植性。参见 Lambdas注释部分中的更多内容。
  • 这涉及延长TinkerPop有关Java接口的任何功能-例如VertexProgramTraversalStrategy等绑定到JVM。在某些情况下,可以使非JVM语言可以访问这些功能,但是显然,它们必须首先为JVM开发。
  • 某些TraversalStrategy依赖于lambda或其他仅JVM配置的内置实现可能无法以任何其他方式使用。
  • 串行化(例如GraphSON)没有界限,因为嵌入式图仅处理Java对象。
  • 更好地控制图事务
  • 直接访问较低级别的API-例如“结构” API方法(例如VertexEdge接口方法)。如本文档其他地方所述,TinkerPop不建议最终用户直接使用这些方法。

Gremlin服务器

rexster character 3基于JVM的图可以托管在TinkerPop的 Gremlin Server中。Gremlin Server将图显示为不同客户端可以连接到的端点,本质上提供了一个远程GTM。Gremlin Server支持多种方法供客户端与其交互:

  • 具有自定义子协议的 Websocket
    • 基于字符串的Gremlin脚本
    • 基于字节码的Gremlin遍历
  • HTTP用于基于字符串的脚本

鼓励用户将基于字节码的方法与websockets一起使用,因为它允许他们用自己选择的语言编写Gremlin。连接看起来有点类似于嵌入式方法,因为需要创建一个GraphTraversalSource。在嵌入式方法中,用于创建该对象的方法是从Graph产生该对象的对象派生的。但是,在这种情况下,Graph实例仅存在于服务器上,这意味着没有Graph实例可在本地创建。方法是改为使用GraphTraversalSource匿名创建一个 AnonymousTraversalSource,然后应用一些“ remote ”方法来描述Gremlin Server的连接位置:

JAVA:

import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;

GraphTraversalSource g = traversal().withRemote('conf/remote-graph.properties');

GROOVY:

import static org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource.traversal;

def g = traversal().withRemote('conf/remote-graph.properties')

CSHARP

using static Gremlin.Net.Process.Traversal.AnonymousTraversalSource;

var g = Traversal().WithRemote(
    new DriverRemoteConnection(new GremlinClient(new GremlinServer("localhost", 8182))));

JAVASCRIPT

const traversal = gremlin.process.AnonymousTraversalSource.traversal;

const g = traversal().withRemote(
                new DriverRemoteConnection('ws://localhost:8182/gremlin'));

PYTHON

from gremlin_python.process.anonymous_traversal_source import traversal

g = traversal().withRemote(
          DriverRemoteConnection('ws://localhost:8182/gremlin','g'))

如上一节中的嵌入式方法所示,一旦定义了“ g”,编写Gremlin在结构和概念上都是相同的,而与编程语言无关。

局限性

嵌入式模型的上一节概述了许多方面的优势,这是由于完整GTM可以以其原始语言(即Java)供用户使用的事实而获得的。这些项目中有一些涉及重要概念,在此重点关注。

这些要点中的第一点是序列化。当Gremlin Server收到请求时,必须将结果序列化为客户端请求的格式,然后客户端将这些内容反序列化为该语言的本机对象。TinkerPop有两种与GryoGraphSON一起使用的格式。Gryo是仅JVM的格式,因此具有在客户端和服务器端JVM的本机类上进行序列化和反序列化的优点。由于客户端具有与服务器相同的类的完全访问权限,因此客户端基本上具有完整的GTM,因此可以执行一些更高级的操作。

一个很好的例子是subgraph()-step,它返回一个Graph实例作为结果。从服务器返回的子图可以反序列化为Graph客户端上的实际实例,这意味着可以从中派生出一个子图GraphTraversalSource,以便在客户端进行本地Gremlin遍历。对于非JVM Gremlin语言变体,没有本地图可将该结果反序列化,也没有GTM来处理Gremlin,因此使用这种结果几乎没有什么可做的。

第二点与此问题有关。由于没有GTM,因此没有“ structure ” API,因此图元素仅像 VertexEdge是“ references ”一样。“ references ”指的是它们仅包含idlabel所述元件和所述特性的不。为了保持一致,当与远程Gremlin Server进行通信时,即使是基于JVM的语言也具有此限制。

重要大多数SQL开发人员不会将查询写为SELECT * FROM table。相反,他们会写出他们想要的字段的各个名称来代替通配符。在这方面,写出“好”的格雷姆林没什么不同。除非完全不可能,否则最好在Gremlin中使用显式属性键名称。

第三点也是最后一点涉及事务。在此模型下,一个遍历等效于单个事务,并且TinkerPop中无法将多个遍历组合到同一事务中。

远程Gremlin Provider

远程Gremlin Provider(RGP)在图形数据库空间中越来越频繁地出现。用TinkerPop术语来说,这种Gremlin Provider的类别是由那些仅支持Gremlin语言的人定义的。通常,这些是基于服务器的图,通常是基于云的图,它们接受Gremlin脚本或字节码作为请求并返回结果。他们通常会实现Gremlin Server协议,这使TinkerPop驱动程序可以像使用Gremlin Server一样连接到它们。因此,典型的连接方法与上一节中介绍的连接方法相同,最后指出了完全相同的警告。

尽管通常使用TinkerPop协议和驱动程序,但RGP不需要这样做就可以视为支持TinkerPop的。RGP可能有自己的驱动程序和协议,可以插入到<gremlin-drivers-variant,Gremlin Language Variants>中,并且可以允许使用更高级的选项,例如更好的安全性,集群感知,批处理请求或其他功能。这些不同系统的详细信息不在本文档的讨论范围之内,因此请确保查阅其文档以获取更多信息。

Basic Gremlin

GraphTraversalSource基本上是一个图实例的连接。该图实例可能是嵌入式的,托管在Gremlin Server中或托管在 RGP中,但是与该实例 GraphTraversalSource无关。假设“ g”是GraphTraversalSource,无论编程语言或操作方式如何,都只将获取到图中是一些basic Gremlin数据:

console:

gremlin> v1 = g.addV('person').property('name','marko').next()
==>v[0]
gremlin> v2 = g.addV('person').property('name','stephen').next()
==>v[2]
gremlin> g.V(v1).addE('knows').to(v2).property('weight',0.75).iterate()

groovy:

v1 = g.addV('person').property('name','marko').next()
v2 = g.addV('person').property('name','stephen').next()
g.V(v1).addE('knows').to(v2).property('weight',0.75).iterate()

CSHARP:

var v1 = g.AddV("person").Property("name", "marko").Next();
var v2 = g.AddV("person").Property("name", "stephen").Next();
g.V(v1).AddE("knows").To(v2).Property("weight", 0.75).Iterate();

JAVA:

Vertex v1 = g.addV("person").property("name","marko").next();
Vertex v2 = g.addV("person").property("name","stephen").next();
g.V(v1).addE("knows").to(v2).property("weight",0.75).iterate();

JAVASCRIPT:

const v1 = g.addV('person').property('name','marko').next();
const v2 = g.addV('person').property('name','stephen').next();
g.V(v1).addE('knows').to(v2).property('weight',0.75).iterate();

PYTHON:

v1 = g.addV('person').property('name','marko').next()
v2 = g.addV('person').property('name','stephen').next()
g.V(Bindings.of('id',v1)).addE('knows').to(v2).property('weight',0.75).iterate()

前两行添加一个顶点,每个顶点的标签为“ person”和关联的“ name”属性。第三行在它们之间添加了一条带有“knows”标签的边缘以及关联的“weight”属性。请注意在行的末尾使用next()-Gremlin Console教程中描述了 iterate()它们作为终端步骤的效果。

重要编写Gremlin只是将数据加载到图形中的一种方法。一些图形可能具有特殊的数据加载器,这些数据加载器可能会更高效,并使任务更容易,更快。值得研究那些工具,特别是如果有大量的一次性工作要做。

检索此数据也是只需要编写Gremlin语句而已:

console:

gremlin> marko = g.V().has('person','name','marko').next()
==>v[0]
gremlin> peopleMarkoKnows = g.V().has('person','name','marko').out('knows').toList()
==>v[2]

groovy:

marko = g.V().has('person','name','marko').next()
peopleMarkoKnows = g.V().has('person','name','marko').out('knows').toList()

CSHARP:

var marko = g.V().Has("person", "name", "marko").Next();
var peopleMarkoKnows = g.V().Has("person", "name", "marko").Out("knows").ToList();

JAVA:

Vertex marko = g.V().has("person","name","marko").next()
List<Vertex> peopleMarkoKnows = g.V().has("person","name","marko").out("knows").toList()

JAVASCRIPT:

const marko = g.V().has('person','name','marko').next()
const peopleMarkoKnows = g.V().has('person','name','marko').out('knows').toList()

PYTHON:

marko = g.V().has('person','name','marko').next()
peopleMarkoKnows = g.V().has('person','name','marko').out('knows').toList()

到目前为止,在所有这些例子中,Gremlin本身看起来并没有太大区别。有一些特定于语言语法的零碎和结尾,但在大多数情况下,Gremlin在所有不同的语言中看起来都像Gremlin。

Gremlin步骤的库及其每个示例都可以在“遍历”部分中找到。本部分仅作为参考指南,不一定提供应用Gremlin解决特定问题的方法。有关此类信息,请参阅上述教程 指南实用Gremlin

注意实用的Gremlin资源的完整列表可以在TinkerPop汇编页面上找到 。

保持不可知论

在这些介绍性部分中,已经有很多关于TinkerPop如何启用构建图形应用程序的不可知论方法以及通过Gremlin启用不可知论的文章。Gremlin在这方面做得很好,但是从连接Gremlin部分可以明显看出TinkerPop只是一个推动者。它不会阻止开发人员做出会限制其保护功能的设计选择。

考虑此问题时,有几个地方需要注意:

  • 数据类型 -不同的图将支持不同类型的数据。诸如TinkerGraph之类的东西可以接受任何JVM对象,但是诸如Neo4j之类的另一种图则具有少量可能的类型。如果需要,选择一种奇异的类型或者也许是仅特定图支持的自定义类型可能会造成迁移摩擦。
  • 模式/索引 -TinkerPop不提供模式和/或索引管理的抽象。用户将直接使用图形提供程序的API。尝试将此类代码包含在特定于图形提供程序的类或类集中以隔离或抽象化是一种好习惯。
  • 扩展 -图形可能会提供Gremlin语言的扩展,该扩展不会设计为与其他图形提供程序兼容。可能存在特殊的帮助程序语法或 表达式,可以使该特定图形的某些功能以强大的方式发挥作用。可能建议使用这些选项,但用户应注意,这样做会使它们与该图更加紧密地联系在一起。
  • 图形特定的语义 -TinkerPop尝试通过其广泛的测试套件来实施特定的语义,但是某些图形提供程序可能未完全尊重Gremlin语言或TinkerPop模型对其API的所有语义。在大多数情况下,这并没有使它们比其他可能完全满足语义的提供程序具有更少的TinkerPop支持。在考虑新图形时要小心,并注意它支持和不支持的图形。
  • 图形API -的图形API(也被称为结构API)并不总是用户访问。它的可访问性取决于图形系统和编程语言的选择。因此,建议用户避免使用诸如Graph.addVertex()或的方法Vertex.properties(),而更偏向于将Gremlin与g.addV()g.V(1).properties()同时使用。

除了考虑这些问题之外,确保最大程度地实现图形兼容性的最佳做法是避免嵌入模式,并坚持使用上面Gremlin服务器RGP部分中介绍的基于字节码的方法 。由于使用这两种模式可以执行的任何操作也都可以在嵌入式模式下工作,因此它使从不可知论途径偏离的机会最少。如果使用嵌入式模式,则只需编写代码,就像Graph实例是“远程”的,并且不是JVM本地的。换句话说,就像GTM在本地不可用一样编写代码。采用这种方法并隔离了上面的关注点,使得交换图提供程序在很大程度上取决于配置任务(即,修改配置文件以指向不同的图系统)。

gremlin standing
简介讨论启用TinkerPop有关-图的多样性,支付给不同的特别注意连接模型,以及如何TinkerPop有关能够弥补这一多样性的不可知的方式。此特定部分涉及Graph API的元素,该元素被认为是在尝试构建时可以避免不可知系统的API。图API是指构成图架构的核心要素Gremlin遍历机(GTM),如GraphVertexEdgeJava接口。

为了维护最便于移植的代码,用户应仅引用这些接口。要“引用”( reference ),仅意味着将其用作指针。对于Graph,这意味着持有一个指向图形数据位置的指针,然后使用它生成GraphTraversalSource实例以编写Gremlin:

console(groovy):

gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.addV('person')
==>v[0]

groovy:

graph = TinkerGraph.open()
g = graph.traversal()
g.addV('person')

在上述例子中,“ graph ”是通过调用TinkerGraphd1产生接口open()创建的Graph接口。请注意,虽然代码的最终目的是创建“ person ”顶点,但它并未使用API Graph来实现该目的-例如graph.addVertex(T.label,'person')

即使开发人员希望使用graph.addVertex()方法,也只有少数几种可能的情况:

  • 该应用程序正在JVM上开发,而开发人员正在使用嵌入式模式
  • 该体系结构包括Gremlin Server,并且用户正在将Gremlin脚本发送到服务器
  • 选择的图形系统是Remote Gremlin Provider,它们通过脚本公开Graph API

请注意,Gremlin语言变体强制开发人员通过引用使用Graph API。 GLV在其各自的Graph实例上是没有addVertex()方法可以用的,其图元素也没有通过调用properties()填充数据。以通用标准使用API开发应用程序将提升该应用程序在支持TinkerPop系统上的可移植性。

在考虑后面的其余小节时,请记住它们通常都绑定到Graph API。它们在此进行描述以供参考,并且在某种意义上与旧的推荐开发模型具有向后兼容性。将来,本节的内容将变得越来越不相关。

Features

一个Feature实现描述了Graph实例的功能。图形系统提供程序实现此接口有两个目的:

  1. 它告诉用户Graph实例的功能。
  2. 它允许根据Gremlin Test Suite对他们确实遵守的功能进行测试-不遵守的测试将被“ ignored”(忽略)。

Gremlin控制台中的以下示例显示了如何打印Graph的所有功能:

console(groovy):

gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> graph.features()
==>FEATURES
> GraphFeatures
>-- Computer: true
>-- Persistence: true
>-- ConcurrentAccess: false
>-- ThreadedTransactions: false
>-- IoRead: true
>-- IoWrite: true
>-- Transactions: false
> VariableFeatures
>-- Variables: true
>-- ByteValues: true
>-- DoubleValues: true
>-- FloatValues: true
>-- IntegerValues: true
>-- LongValues: true
>-- MapValues: true
>-- MixedListValues: true
>-- SerializableValues: true
>-- StringValues: true
>-- UniformListValues: true
>-- BooleanArrayValues: true
>-- ByteArrayValues: true
>-- DoubleArrayValues: true
>-- FloatArrayValues: true
>-- IntegerArrayValues: true
>-- LongArrayValues: true
>-- StringArrayValues: true
>-- BooleanValues: true
> VertexFeatures
>-- AddVertices: true
>-- RemoveVertices: true
>-- DuplicateMultiProperties: true
>-- Upsert: false
>-- MetaProperties: true
>-- MultiProperties: true
>-- NumericIds: true
>-- StringIds: true
>-- UuidIds: true
>-- CustomIds: false
>-- AnyIds: true
>-- AddProperty: true
>-- RemoveProperty: true
>-- UserSuppliedIds: true
> VertexPropertyFeatures
>-- NumericIds: true
>-- StringIds: true
>-- UuidIds: true
>-- CustomIds: false
>-- AnyIds: true
>-- RemoveProperty: true
>-- UserSuppliedIds: true
>-- Properties: true
>-- ByteValues: true
>-- DoubleValues: true
>-- FloatValues: true
>-- IntegerValues: true
>-- LongValues: true
>-- MapValues: true
>-- MixedListValues: true
>-- SerializableValues: true
>-- StringValues: true
>-- UniformListValues: true
>-- BooleanArrayValues: true
>-- ByteArrayValues: true
>-- DoubleArrayValues: true
>-- FloatArrayValues: true
>-- IntegerArrayValues: true
>-- LongArrayValues: true
>-- StringArrayValues: true
>-- BooleanValues: true
> EdgeFeatures
>-- AddEdges: true
>-- RemoveEdges: true
>-- Upsert: false
>-- NumericIds: true
>-- StringIds: true
>-- UuidIds: true
>-- CustomIds: false
>-- AnyIds: true
>-- AddProperty: true
>-- RemoveProperty: true
>-- UserSuppliedIds: true
> EdgePropertyFeatures
>-- Properties: true
>-- ByteValues: true
>-- DoubleValues: true
>-- FloatValues: true
>-- IntegerValues: true
>-- LongValues: true
>-- MapValues: true
>-- MixedListValues: true
>-- SerializableValues: true
>-- StringValues: true
>-- UniformListValues: true
>-- BooleanArrayValues: true
>-- ByteArrayValues: true
>-- DoubleArrayValues: true
>-- FloatArrayValues: true
>-- IntegerArrayValues: true
>-- LongArrayValues: true
>-- StringArrayValues: true
>-- BooleanValues: true

groovy:

graph = TinkerGraph.open()
graph.features()

使用功能的常见模式是在执行操作之前检查其是否支持:

console(groovy):

gremlin> graph.features().graph().supportsTransactions()
==>false
gremlin> graph.features().graph().supportsTransactions() ? g.tx().commit() : "no tx"
==>no tx

groovy:

graph.features().graph().supportsTransactions()
graph.features().graph().supportsTransactions() ? g.tx().commit() : "no tx"
TIP为了确保提供者不可知的代码,请始终在使用特定功能之前检查功能支持。这样,在运行时提供不支持所访问功能的特定实现的情况下,应用程序仍然可以正常运行。
警告用于连接到远程图的参考图的特征不能反映其连接到的图的特征。它反映了实例化图本身的特征,考虑到参考图通常是不可变的,这可能会大不相同。

顶点属性

vertex propertiesTinkerPop引入了VertexProperty。一个Vertex的所有属性都是 VertexProperty。一个VertexProperty实现了Property并因此因此具有一个键/值对。但是,VertexProperty实现了Element并因此具有键/值对的集合。此外,(比如)尽管一条Edge只能拥有一个键“ name ”属性,但一个Vertex可以具有多个“name ”属性。通过包含顶点属性,引入了两个功能,这些功能最终改进了图形建模工具注(17)

  1. 多个属性(multi-properties):顶点属性键可以具有多个值。例如,一个顶点可以具有多个“名称”属性。
  2. 属性上的属性(meta-properties):顶点属性可以具有属性(即,顶点属性可以具有与其关联的键/值数据)。

元属性注(18)的可能用例:

  1. 权限:顶点属性可以具有与之关联的键/值ACL类型权限信息。
  2. 审核:操作顶点属性时,可以在其上附加键/值信息,说明创建者,删除者等。
  3. 出处:顶点的“名称”可以由多个用户声明。例如,来自不同来源的名称可能有多种拼写。

下面提供了一个使用顶点属性的运行示例,以演示和解释API。

console(groovy):

gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> g = graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> v = g.addV().property('name','marko').property('name','marko a. rodriguez').next()
==>v[0]
gremlin> g.V(v).properties('name').count() //1\
==>2
gremlin> v.property(list, 'name', 'm. a. rodriguez') //2\
==>vp[name->m. a. rodriguez]
gremlin> g.V(v).properties('name').count()
==>3
gremlin> g.V(v).properties()
==>vp[name->marko]
==>vp[name->marko a. rodriguez]
==>vp[name->m. a. rodriguez]
gremlin> g.V(v).properties('name')
==>vp[name->marko]
==>vp[name->marko a. rodriguez]
==>vp[name->m. a. rodriguez]
gremlin> g.V(v).properties('name').hasValue('marko')
==>vp[name->marko]
gremlin> g.V(v).properties('name').hasValue('marko').property('acl','private') //3\
==>vp[name->marko]
gremlin> g.V(v).properties('name').hasValue('marko a. rodriguez')
==>vp[name->marko a. rodriguez]
gremlin> g.V(v).properties('name').hasValue('marko a. rodriguez').property('acl','public')
==>vp[name->marko a. rodriguez]
gremlin> g.V(v).properties('name').has('acl','public').value()
==>marko a. rodriguez
gremlin> g.V(v).properties('name').has('acl','public').drop() //4\
gremlin> g.V(v).properties('name').has('acl','public').value()
gremlin> g.V(v).properties('name').has('acl','private').value()
==>marko
gremlin> g.V(v).properties()
==>vp[name->marko]
==>vp[name->m. a. rodriguez]
gremlin> g.V(v).properties().properties() //5\
==>p[acl->private]
gremlin> g.V(v).properties().property('date',2014) //6\
==>vp[name->marko]
==>vp[name->m. a. rodriguez]
gremlin> g.V(v).properties().property('creator','stephen')
==>vp[name->marko]
==>vp[name->m. a. rodriguez]
gremlin> g.V(v).properties().properties()
==>p[date->2014]
==>p[creator->stephen]
==>p[acl->private]
==>p[date->2014]
==>p[creator->stephen]
gremlin> g.V(v).properties('name').valueMap()
==>[date:2014,creator:stephen,acl:private]
==>[date:2014,creator:stephen]
gremlin> g.V(v).property('name','okram') //7\
==>v[0]
gremlin> g.V(v).properties('name')
==>vp[name->okram]
gremlin> g.V(v).values('name') //8\
==>okram

groovy:

graph = TinkerGraph.open()
g = graph.traversal()
v = g.addV().property('name','marko').property('name','marko a. rodriguez').next()
g.V(v).properties('name').count() //1\
v.property(list, 'name', 'm. a. rodriguez') //2\
g.V(v).properties('name').count()
g.V(v).properties()
g.V(v).properties('name')
g.V(v).properties('name').hasValue('marko')
g.V(v).properties('name').hasValue('marko').property('acl','private') //3\
g.V(v).properties('name').hasValue('marko a. rodriguez')
g.V(v).properties('name').hasValue('marko a. rodriguez').property('acl','public')
g.V(v).properties('name').has('acl','public').value()
g.V(v).properties('name').has('acl','public').drop() //4\
g.V(v).properties('name').has('acl','public').value()
g.V(v).properties('name').has('acl','private').value()
g.V(v).properties()
g.V(v).properties().properties() //5\
g.V(v).properties().property('date',2014) //6\
g.V(v).properties().property('creator','stephen')
g.V(v).properties().properties()
g.V(v).properties('name').valueMap()
g.V(v).property('name','okram') //7\
g.V(v).properties('name')
g.V(v).values('name') //8
  1. 一个顶点可以具有零个或多个具有与之关联的键的属性。
  2. 如果添加的基数为Cardinality.list的属性,则将添加具有提供的密钥的其他属性。
  3. 顶点属性可以附加有标准键/值属性。
  4. 顶点属性删除与属性删除相同。
  5. 获取每个顶点属性的元属性。
  6. 顶点属性可以具有任意数量的键/值属性。
  7. property(…)将在添加新的单个属性之前删除所有现有的key’d属性(请参阅参考资料VertexProperty.Cardinality)。
  8. 如果仅需要属性的值,则可以使用values()

如果很难理解节点属性的概念,那么最好以“文字节点”注(19)来考虑节点属性。节点可以具有具有单个值键/值的“文字节点”的边缘,例如“ value = okram”。指向该文字节点的边具有“name”的边标签( edge-label )。边上的属性表示文字节点的属性。“文字节点”不能具有任何其他边(关联的节点中只有一个)。

TIP玩具图,表示所有的新TinkerPop有关图形结构的特点是可以在 TinkerFactory.createTheCrew()data/tinkerpop-crew*获得的。该图演示了多属性和元属性。

the crew graph

Figure 3. TinkerPop Crew

console(groovy):

gremlin> g.V().as('a').
               properties('location').as('b').
               hasNot('endTime').as('c').
               select('a','b','c').by('name').by(value).by('startTime') // determine the current location of each person
==>[a:marko,b:santa fe,c:2005]
==>[a:stephen,b:purcellville,c:2006]
==>[a:matthias,b:seattle,c:2014]
==>[a:daniel,b:aachen,c:2009]
gremlin> g.V().has('name','gremlin').inE('uses').
               order().by('skill',asc).as('a').
               outV().as('b').
               select('a','b').by('skill').by('name') // rank the users of gremlin by their skill level
==>[a:3,b:matthias]
==>[a:4,b:marko]
==>[a:5,b:stephen]
==>[a:5,b:daniel]

groovy:

g.V().as('a').
      properties('location').as('b').
      hasNot('endTime').as('c').
      select('a','b','c').by('name').by(value).by('startTime') // determine the current location of each person
g.V().has('name','gremlin').inE('uses').
      order().by('skill',asc).as('a').
      outV().as('b').
      select('a','b').by('skill').by('name') // rank the users of gremlin by their skill level

图变量

Graph.Variables是与图本身关联的键/值对——本质上是a Map。这些变量旨在存储有关图形的元数据。用例示例包括:

  • 模式信息:命名空间( namespace )前缀解析了什么?上次修改 schema 的时间是什么?
  • 全局权限:特定组的访问权限是什么?
  • 系统用户信息:谁是系统管理员?

下面提供了一个使用中的图形变量的示例:

console(groovy):

gremlin> graph = TinkerGraph.open()
==>tinkergraph[vertices:0 edges:0]
gremlin> graph.variables()
==>variables[size:0]
gremlin> graph.variables().set('systemAdmins',['stephen','peter','pavel'])
gremlin> graph.variables().set('systemUsers',['matthias','marko','josh'])
gremlin> graph.variables().keys()
==>systemAdmins
==>systemUsers
gremlin> graph.variables().get('systemUsers')
==>Optional[[matthias, marko, josh]]
gremlin> graph.variables().get('systemUsers').get()
==>matthias
==>marko
==>josh
gremlin> graph.variables().remove('systemAdmins')
gremlin> graph.variables().keys()
==>systemUsers

groovy :

graph = TinkerGraph.open()
graph.variables()
graph.variables().set('systemAdmins',['stephen','peter','pavel'])
graph.variables().set('systemUsers',['matthias','marko','josh'])
graph.variables().keys()
graph.variables().get('systemUsers')
graph.variables().get('systemUsers').get()
graph.variables().remove('systemAdmins')
graph.variables().keys()
重要图变量既不打算同时进行大量变更,也不打算在复杂的计算中使用。目的是要有一个位置来存储有关图形的数据以用于管理目的。
警告尝试在参考图中设置图变量不会将它们提升为远程图。通常,参考图具有不变的功能,并且将不支持此功能。

图事务

gremlin coins数据库事务 代表对数据库执行的工作单元。可以在多种情况下考虑TinkerPop中的事务:通过Graph API 进行的嵌入式图形事务,针对Gremlin Server的事务以及远程Gremlin Provider中的事务 。对于遵循以下推荐模式的人员,嵌入部分中介绍的概念通常应该很少关注,主要是作为参考。利用这些事务功能将大大降低应用程序Gremlin代码的可移植性。

嵌入式的

在JVM上使用嵌入式图时,在处理事务方面具有相当大的灵活性。使用Graph API,事务由Transaction接口的实现控制,并且可以Graph使用该tx()方法从接口获取该对象。重要的是要注意该 Transaction对象本身并不表示“事务”。它仅公开了用于事务处理的方法(例如,提交,回滚等)。

大多数Graph执行工具中supportsTransactions将实现“自动” ThreadLocal事务,这意味着在Graph实例化实例后发生读取或写入时,将在该线程内自动启动事务。无需手动调用“创建”或“启动”事务的方法。只需根据需要修改图形,然后调用graph.tx().commit()即可应用更改或graph.tx().rollback()撤消更改。当对图进行下一个读或写操作时,将在该当前执行线程内启动一个新事务。

当以这种方式使用事务时,特别是在web应用程序(例如HTTP服务器)中,确保事务不会从一个请求泄漏到下一个请求是很重要的。换言之,除非客户机以某种方式通过会话绑定以处理同一服务器线程上的每个请求,否则每个请求都必须在请求结束时提交或回滚。通过确保请求封装了一个事务,它可以确保在服务器线程上处理的未来请求以新的事务状态启动,并且不能访问先前请求的剩余部分。一个好的策略是在请求开始时回滚一个事务,这样,如果在请求之间发生了某种事务泄漏,新的事务就由新的请求来保证。

TIPtx()方法在Graph接口上,但也可以在通过TraversalSource产生的方法上使用 Graph。为方便起见TraversalSource.tx()将调用底层Graph
警告TinkerPop提供基本的事务控制,但是,与TinkerPop的许多方面一样,图系统提供商也可以选择具体方面,以决定其实现的工作方式以及如何使其适合TinkerPop堆栈。确保了解正在使用的特定图形实现的事务语义,因为它可能呈现与此处所述不同的功能。注(20)
配置

确定事务何时开始取决于分配给Transaction的行为。取决于 Graph实现来确定默认行为,除非实现不允许,否则可以通过以下Transaction方法更改行为本身:

public Transaction onReadWrite(Consumer<Transaction> consumer);

public Transaction onClose(Consumer<Transaction> consumer);

提供一个Consumer函数使onReadWrite允许定义在发生读取或写入时事务如何开始。Transaction.READ_WRITE_BEHAVIOR包含预定义函数Consumer要提供给onReadWrite 的方法。有两个选择:

  • AUTO -自动事务,其中事务隐式启动到读取或写入操作
  • MANUAL -手动事务,取决于用户明确地打开事务,如果交易未事务,则引发异常

提供一个Consumer功能使onClose允许配置在Transaction.close()调用时如何处理事务 。 Transaction.CLOSE_BEHAVIOR有几个可以提供给此方法的预定义选项:

  • COMMIT -自动提交未结束的事务
  • ROLLBACK -自动回滚未结束的事务
  • MANUAL -如果事务已打开,则会引发异常,从而迫使用户显式关闭事务
重要由于事务是ThreadLocal自然的,因此onCloseonReadWrite的事务配置也是如此 .

一旦了解了事务的配置方式,其余大部分Transaction接口都是不言自明的。请注意,由于TinkerGraph不支持事务,因此以下示例使用Neo4j-Gremlin

gremlin> graph = Neo4jGraph.open('/tmp/neo4j')
==>neo4jgraph[EmbeddedGraphDatabase [/tmp/neo4j]]
gremlin> g = graph.traversal()
==>graphtraversalsource[neo4jgraph[community single [/tmp/neo4j]], standard]
gremlin> graph.features()
==>FEATURES
> GraphFeatures
>-- Transactions: true  //1
>-- Computer: false
>-- Persistence: true
...
gremlin> g.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.AUTO) //2
==>org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph$Neo4jTransaction@1c067c0d
gremlin> g.addV("person").("name","stephen")  //3
==>v[0]
gremlin> g.tx().commit() //4
==>null
gremlin> g.tx().onReadWrite(Transaction.READ_WRITE_BEHAVIOR.MANUAL) //5
==>org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph$Neo4jTransaction@1c067c0d
gremlin> g.tx().isOpen()
==>false
gremlin> g.addV("person").("name","marko") //6
Open a transaction before attempting to read/write the transaction
gremlin> g.tx().open() //7
==>null
gremlin> g.addV("person").("name","marko") //8
==>v[1]
gremlin> g.tx().commit()
==>null
  1. 检查features以确保该图支持事务。
  2. 默认情况下,Neo4jGraph配置有“自动”事务,因此此处仅出于演示目的进行设置。
  3. 添加顶点后,事务将自动开始。从这一点出发,可以在该开放事务的上下文中暂存更多突变或执行其他读取操作。
  4. 调用commit完成事务。
  5. 更改事务行为以要求手动控制。
  6. 现在添加顶点会导致失败,因为未显式打开事务。
  7. 显式打开一个事务。
  8. 现在,由于手动打开了事务,因此添加顶点成功。
注意Graph当涉及到事务行为的细节时, 重要的是要查阅所用实现的文档。TinkerPop允许在此领域中留出一定的余地,并且实现可能不具有完全相同的行为和ACID保证。
线程化事务

大多数Graph支持事务的实现都以某种ThreadLocal方式这样做,其中当前事务绑定到当前执行线程。请考虑以下示例进行演示:

GraphTraversalSource g = graph.traversal();
g.addV("person").("name","stephen").iterate();

Thread t1 = new Thread(() -> {
    g.addV("person").("name","josh").iterate();
});

Thread t2 = new Thread(() -> {
    g.addV("person").("name","marko").iterate();
});

t1.start()
t2.start()

t1.join()
t2.join()

g.tx().commit();

上面的代码显示了graph在三个不同线程中添加的三个顶点:当前线程t1t2。可能有人希望在这段代码完成执行时,将有三个顶点持久存在于Graph。但是,鉴于ThreadLocal事务的性质,实际上在该代码体中创建了三个单独的事务(即,每个执行线程一个),并且唯一提交的是在addV()执行主线程中的第一次调用。内部的对该方法的另外两个调用,t1并且t2 从未提交,因此成为孤立的。

supportsThreadedTransactions是一个允许Graph该约束之外操作,因此允许多个线程在同一事务中操作。因此,如果需要在同一事务中运行三个不同的线程,则可以将代码重写为如下:

Graph threaded = graph.tx().createThreadedTx();
GraphTraversalSource g = graph.traversal();
g.addV("person").("name","stephen").iterate();

Thread t1 = new Thread(() -> {
    threaded.addV("person").("name","josh").iterate();
});

Thread t2 = new Thread(() -> {
    threaded.addV("person").("name","marko").iterate();
});

t1.start()
t2.start()

t1.join()
t2.join()

g.tx().commit();

在上述样例中,对graph.tx().createThreadedTx()的调用会创建一个与ThreadLocal事务未绑定的新Graph实例 ,从而允许每个线程在同一上下文中对其进行操作。在这种情况下,将存在三个单独的顶点保留到Graph

Gremlin服务器

使用Gremlin Server进行事务处理的可用功能取决于所使用的交互方法。与Gremlin Server进行交互的首选方法 是通过websocket和基于字节码的请求。在这种操作模式下,每次执行的Gremlin遍历都将被视为单个事务。失败的遍历将使事务回滚,并且遍历的成功迭代将以事务提交结束。Gremlin Server中托管的图如何响应这些命令取决于所选择的图,因此在开发应用程序时了解该图的事务语义非常重要。

Gremlin Server还可以选择接受基于Gremlin的脚本。脚本方法提供了对Graph API的访问,因此也提供了对嵌入式部分中描述的事务模型的访问。因此,单个脚本可以具有针对每个请求执行多个事务的能力,并提供给开发人员的完全控制权,使其可以根据需要提交或回滚事务。

有两种方法可以将脚本发送到Gremlin Server:无会话和基于会话。对于无会话请求,如果没有错误,总是会尝试在请求结束时通过提交关闭事务,如果失败则回滚。因此,无需在脚本本身内手动关闭事务。默认情况下,基于会话的请求没有这种质量。事务将在服务器上保持打开状态,直到用户手动关闭它为止。有一个选项可以对会话进行自动事务管理。有关此主题的更多信息,请参见对价交易部分和对价会议部分。

尽管这些部分提供了一些其他详细信息,但简短的建议是在可能的情况下避免使用脚本,而倾向于基于字节码的请求。

远程Gremlin Providers

目前,远程Gremlin Provider的事务处理模式与Gremlin Server大致相同。大多数提供基于字节码或脚本的无会话请求,这些请求具有自动事务管理功能,这样成功的遍历将在成功时进行,而失败的遍历将回滚。由于这些RGP中的大多数不公开Graph实例,因此通常甚至不允许以无会话的方式访问较低级别的事务功能。与任何启用TinkerPop的图形系统一样,“事务”含义的性质将取决于RGP,因此重要的是,请查阅系统文档以获取更多详细信息。

命名空间约定

最终用户,图形系统提供者GraphComputer算法设计者, GremlinPlugin创建者等都利用元素上的属性来存储信息。命名属性密钥时应遵循一些约定,以确保这些利益相关者之间的冲突不会发生冲突。

  • 端用户被授予的平面命名空间(例如nameagelocation)加键它们的性质和标记他们的元素。
  • 图形系统提供者被授予隐藏的名称空间(例如~metadata),以为其属性和标签添加密钥。如此键控的数据只能通过图形系统实现来访问,并且没有其他利益相关者被授予对以“〜”为前缀的数据的读写权限(请参阅参考资料Graph.Hidden)。存在测试覆盖率和异常,以确保图形系统遵守此硬性边界。
  • VertexProgram并且MapReduce开发人员应利用 特定于其域的合格名称空间(例如mydomain.myvertexprogram.computedata)。
  • GremlinPlugin创建者应在其插件名称前添加域(例如mydomain.myplugin)。
重要TinkerPop使用tinkerpop.gremlin.作为提供的策略、顶点程序、map reduce实现和插件的前缀。

唯一受真正保护的名称空间是提供给图形系统的隐藏名称空间。从那里开始,工程师必须尊重所提出的命名间隔惯例。

遍历

gremlin running

在最一般的层次上,有Traversal<S,E>实现了Iterator<E>S代表开始和E结束。遍历由四个主要部分组成:

  1. Step:应用于S产生E的单个函数。在遍历中链接步骤。
  2. TraversalStrategy:拦截器方法,用于更改遍历的执行(例如,查询重写)。
  3. TraversalSideEffects:可用于存储有关遍历的全局信息的键/值对。
  4. Traverser:通过Traversal传播的对象,当前表示T类型的对象。

一个图的遍历的经典概念是通过提供GraphTraversal延伸TraversalGraphTraversal提供根据顶点,边等对图数据的解释,从而提供图形遍历DSL的信息

重要TinkerPop提供 Step的基础实现应包含DSL作者所需的大多数功能。DSL作者必须利用提供的步骤(Step),这一点很重要,因为常见的优化和修饰策略可以根据底层遍历序列进行推理。如果采用新的步骤,则常见的遍历策略可能无法正常运行。

Graph Traversal Steps注(21)

step types

(未完待续,翻译进度7.68%)

译者注:

(1):这里原文用的是很诗意的语句描绘,译者文学素养没那么高,大家领会精神

(2):这6个就是图中除了Gremlin之外的5个小伙伴(五个项目),蓝色的就是Blueprints(蓝图),红色的就是Pipes (管道),绿色的是Gremlin,橙色的是Frames (框架),紫色的是Furnace (熔炉),黄色的是Rexster,这些项目的logo都很形象……

(3):这段很哲学,我们是‘什么’,‘什么’是TinkerPop,所以我们是TinkerPop……好像没啥问题

(4):原文cloud-only graph,这里译成‘仅云图’,有更好的翻译欢迎提出

(5):套娃……这句话贯穿全文,仔细品味其实很有意思

(6):这一点很重要,实际应用中很容易体验到,即使你用的是java/python/其他的api,语法永远是gremlin的语法,加上部分这门语言的语法,一定程度降低了学习成本,非常方便使用。

(7):这部分的意思大概是:因为开源的性质,你所用的图,很可能已经经过二次开发,非原生的图于官方文档不符的部分,请找提供给你这张图的人要个文档……

(8):原文toy graphs ,这里译成‘玩具图’,有更好的翻译欢迎提出

(9):原文Anatomy,这里翻译成’剖析‘

(10):原文中分成了带控制台返回的版本和纯groovy版本,本翻译后的文档沿用这种方法,一方面方便查看返回值,另一方面方便大家直接复制粘贴

(11):原文The Traverser,这里翻译成’遍历器‘

(12):原文 Gremlin Traversal Machine ,这里翻译成’Gremlin遍历机‘

(13):原文 Remote Gremlin Provider ,这里翻译成’远程Gremlin提供者‘

(14):原文 Embedded ,这里翻译成’嵌入式的‘

(15):原文 reference implementation ,这里翻译成’参考实现‘

(16):虽然按照习惯一般来说用的是g,但是不推荐直接在包含业务逻辑的代码中使用g,而是根据具体的图来命名,比如person_g等。否则你会发现自己的代码里面充满了g,g,g,g,g,g……根本没法维护

(17) 原文 graph modelers toolkit ,这里翻译成’图形建模工具‘

(18) 原文 meta-properties ,这里翻译成’元属性‘

(19) 原文 literal vertex ,这里翻译成’文字节点‘

(20)用大白话说,就是你使用的图可能被二次开发过了,所以原生的事务方法不一定管用,具体你需要问提供这个图的人。

(21)为了避免歧义和方便大家(ctrl+f)查询,这章开始所有步骤(step)的名称都使用原文。相信会看这篇文档的同学这些基本的单词还是会的(这章很重要,是使用tinkerpop gremlin的关键)。

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值