遍历对象 g 是 Pre-bound。不支持 graph 对象。
Neptune 不支持枚举值的完全限定类名称。例如,您在 Groovy 请求中必须使用 single,不能使用 org.apache.tinkerpop.gremlin.structure.VertexProperty.Cardinality.single。
**Neptune 不支持调用由支持的 Gremlin API 以外的任意 Java 或 Java 库调用定义的方法。**例如,不允许 java.lang.*、Date() 和 g.V().tryNext().orElseGet()。
Neptune 提供了 datetime 方法,用于为 Gremlin Groovy 变体中发送的查询指定日期和时间。这包括 Gremlin 控制台、使用 HTTP REST API 的文本字符串以及使用 Groovy 的任何其他序列化。日期和时间值必须使用 datetime() 函数进行指定。
YYYY-MM-DD
YYYY-MM-DDTHH:mm
YYYY-MM-DDTHH:mm:SS
YYYY-MM-DDTHH:mm:SS.ssss
YYYY-MM-DDTHH:mm:SSZ
所有查询必须以遍历对象 g 开头。
多个遍历可由分号 ( 或换行符 (\n) 分隔发布。最后一个以外的每个语句都必须以要执行的 next() 步骤结尾。仅返回最后遍历数据。
Neptune 属于无会话型。它不支持控制台 session 参数。
Neptune 在每个 Gremlin 遍历开始时打开新的事务,并在遍历成功完成后结束事务。事务会在出现错误时回滚。
用分号 ( 或换行符 (\n) 分隔的多个语句包含在单个事务中。最后一个以外的每个语句都必须以要执行的 next() 步骤结尾。仅返回最后遍历数据。
不支持使用 tx.commit() 和 tx.rollback() 的手动事务逻辑。
Neptune Gremlin 顶点和边缘 ID 必须属于 String 类型。如果您在添加顶点或边缘时未提供 ID,则 UUID 会生成并转换为一个字符串;例如,“48af8178-50ce-971a-fc41-8c9a954cea62”。
用户提供的 ID 在 Neptune Gremlin 中允许,且具有以下规定。
* 提供的 ID 是可选的。
* 仅支持顶点和边缘。
* 仅支持 String 类型。
要使用自定义 ID 创建新顶点,请将 property 步骤与 id 关键字一起使用:g.addV().property(id, ‘customid’)。
gremlin> g.addV('label1').property(id, 'customid')
gremlin> g.addV('label2').property(id, 'customid')
gremlin> g.V('customid').label()
==>label1::label2
顶点属性 ID 会自动生成且可以在查询时显示为正数或负数。
Neptune 支持集基数和单一基数。如果未指定,则集基数处于选中状态。这意味着,如果您设置一个属性值,它会向该属性添加新值,但是仅当它未显示在一组值中时。这是 Set 的 Gremlin 枚举值。
不支持 List。有关属性基数的更多信息,请参阅 Gremlin JavaDoc 中的顶点主题。
要更新属性值而无需向一组值添加其他值,请在 property 步骤中指定 single 基数。
g.V('exampleid01').property(single, 'age', 25)
Neptune 支持一个顶点的多个标签。创建标签时,您可以指定多个标签,同时使用 :: 分隔它们。例如,g.addV(“Label1::Label2::Label3”) 添加具有三个不同标签的顶点。hasLabel 步骤与具有以下任一三个标签的此顶点相匹配:hasLabel(“Label1”)、hasLabel(“Label2”) 和 hasLabel(“Label3”)。
Neptune 不支持 Gremlin 变量且不支持 bindings 属性。
Gremlin 控制台命令 :remote config timeout 仅设置本地超时。要为 Neptune 设置远程查询超过,请使用 neptune_query_timeout 参数。
Neptune 解析所有转义字符,如 Apache Groovy 语言文档的转义特殊字符部分中所述。
Neptune 不支持不以 g 开头的 Groovy 命令。这包括数学(例如:1+1)、系统调用(例如:System.nanoTime())和变量定义(例如:1+1)。
Neptune 不支持 Lambda 步骤。
Neptune 不支持以下 Gremlin 方法:
Neptune 不支持以下 Gremlin 步骤:
Gremlin 的 Neptune 实施不公开 graph 对象。以下部分介绍支持和不支持的 graph 功能。
参考:https://docs.aws.amazon.com/zh_cn/neptune/latest/userguide/access-graph-gremlin-differences.html?shortFooter=true
wget https://archive.apache.org/dist/tinkerpop/3.3.2/apache-tinkerpop-gremlin-console-3.3.2-bin.zip
unzip apache-tinkerpop-gremlin-console-3.3.2-bin.zip
cd apache-tinkerpop-gremlin-console-3.3.2
hosts: [your-neptune-endpoint]
port: 8182
serializer: { className: org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV3d0, config: { serializeResultToString: true }}
bin/gremlin.sh
\,,,/
(o o)
-----oOOo-(3)-oOOo-----
plugin activated: tinkerpop.server
plugin activated: tinkerpop.utilities
plugin activated: tinkerpop.tinkergraph
gremlin>
:remote connect tinkerpop.server conf/neptune-remote.yaml
:remote console
g.V().limit(1)
:exit
* 使用分号 (;) 或换行符 (\n) 分隔每个语句。
* 在最后遍历之前的每个遍历必须以要执行的 next() 结尾。仅返回最后遍历中的数据。
gremlin> g.addV('person').property('name', 'justin')
==>v[30b583c5-acf9-31aa-eee7-99c1644e3367]
// 顶点分配有包含 GUID 的 string ID。Neptune 中的所有顶点 ID 均为字符串。
gremlin> g.addV('person').property(id, '1').property('name', 'martin')
==>v[1]
// id 属性未使用引号引起来。这是顶点 ID 的关键字。顶点 ID 具有一个字符串,其中包含数字 1。
// 普通属性名称必须包含在引号中。
gremlin> g.V('1').property(single, 'name', 'marko')
==>v[1]
// 此处介绍如何更改上一步中顶点的 name 属性。这会从 name 属性删除现有值。
// 如果您未指定 single,则会改为将值附加到 name 属性(如果尚未附加)。
gremlin> g.V('1').property('age', 29)
==>v[1]如果 age 属性已有值,此命令将 29 附加到属性。例如,如果 age 属性是 27,则新值将为 [ 27, 29 ]。
// Neptune 使用集基数作为默认操作。
// 此命令添加值为 29 的 age 属性,但不替换任何现有值。
// 如果 age 属性已有值,此命令将 29 附加到属性。例如,如果 age 属性是 27,则新值将为 [ 27, 29 ]。
gremlin> g.addV('person').property(id, '2').property('name', 'vadas').property('age', 27).next()
==>v[2]
gremlin> g.addV('software').property(id, '3').property('name', 'lop').property('lang', 'java').next()
==>v[3]
gremlin> g.addV('person').property(id, '4').property('name', 'josh').property('age', 32).next()
==>v[4]
gremlin> g.addV('software').property(id, '5').property('name', 'ripple').property('ripple', 'java').next()
==>v[5]
gremlin> g.addV('person').property(id, '6').property('name', 'peter').property('age', 35)
==>v[6]
// 可以同时将多个语句发送到 Neptune。
// 语句可以使用换行符 ('\n')、空格 (' ')、分号 ('; ') 或什么都不使用(例如,g.addV(‘person’).next()g.V() 是有效的)来分隔。
// 注意
// Gremlin 控制台对每个换行符 ('\n') 发送单独的命令,因此在该例中,它们将成为单独的事务处理。此示例的每个命令位于单独一行中,以便阅读。删除换行符 ('\n') 可以将其通过 Gremlin 控制台作为单个命令发送。
// 除了最后一条语句之外的所有语句必须以终止步骤结尾,例如 .next() 或 .iterate(),否则语句不会运行。Gremlin 控制台不需要这些终止步骤。
// 一起发送的所有语句包括在单个事务处理中,并且一起成功或失败。
gremlin> g.V('1').addE('knows').to(g.V('2')).property('weight', 0.5).next()
==>e[fab583cd-5686-b3df-60f8-ab792ca96ba9][1-knows->2]
gremlin> g.addE('knows').from(g.V('1')).to(g.V('4')).property('weight', 1.0)
==>e[60b583cd-74fe-581d-f3b2-637328927188][1-knows->4]
// 这里介绍了两种不同的方法来添加边缘。
gremlin> g.V('1').addE('created').to(g.V('3')).property('weight', 0.4).next()
==>e[c4b583cd-06e0-9740-98a0-15f0ed923186][1-created->3]
gremlin> g.V('4').addE('created').to(g.V('5')).property('weight', 1.0).next()
==>e[7eb583cd-0793-821a-2466-78eba1efa94e][4-created->5]
gremlin> g.V('4').addE('knows').to(g.V('3')).property('weight', 0.4).next()
==>e[7ab583cd-083a-1491-a623-f7102b950e85][4-knows->3]
gremlin> g.V('6').addE('created').to(g.V('3')).property('weight', 0.2)
==>e[cab583cd-08e4-f637-944f-810fb09bda56][6-created->3]
gremlin> g.V().has('name', 'justin').drop()
gremlin>
// 删除 name 属性等于 justin 的顶点。
// 注意:到这里,您拥有了完整的 Apache TinkerPop 现代图形。TinkerPop 文档的“遍历”部分中的示例使用现代图形。
gremlin> g.V().hasLabel('person')
==>v[2]
==>v[6]
==>v[1]
==>v[4]
// 返回所有 person 顶点。
gremlin> g.V().has('name', 'marko').out('knows').valueMap()
==>{name=[vadas], age=[27]}
==>{name=[josh], age=[32]}
// 返回 marko“知道”的所有顶点的键值对。
gremlin> g.addV("Label1::Label2::Label3")
==>v[54b583d3-f0a3-f0ce-2ddb-3e92a968744b]
// Neptune 支持一个顶点的多个标签。创建标签时,您可以指定多个标签,同时使用 :: 分隔它们。
// 此示例添加具有三个不同标签的顶点。
// hasLabel 步骤与具有以下任一三个标签的此顶点相匹配:hasLabel("Label1")、hasLabel("Label2") 和 hasLabel("Label3")。
// :: 分隔符仅用于此用途。
// 您不能在 hasLabel 步骤中指定多个标签。例如,hasLabel("Label1::Label2") 与任何内容都不匹配。
gremlin> g.V().property(single, 'lastUpdate', datetime('2018-01-01T00:00:00'))
==>v[2]
==>v[6]
==>v[54b583d3-f0a3-f0ce-2ddb-3e92a968744b]
==>v[1]
==>v[3]
==>v[4]
==>v[5]
// Neptune 不支持 Java 日期。改用 datetime() 函数。datetime() 接受符合 ISO8061 的 datetime 字符串。
// 它支持以下格式:YYYY-MM-DD、YYYY-MM-DDTHH:mm、YYYY-MM-DDTHH:mm:SS、YYYY-MM-DDTHH:mm:SSZ
gremlin> g.V().hasLabel('person').properties('age').drop().iterate()
gremlin> g.V('1').drop().iterate()
gremlin> g.V().outE().hasLabel('created').drop()
gremlin>
// 注意 .next() 步骤不可与 .drop() 一起使用。请改用 .iterate()
完成后,键入以下命令以退出 Gremlin 控制台。
gremlin> :exit
Gremlin是 Apache TinkerPop 框架下的图遍历语言。Gremlin是一种函数式数据流语言,可以使得用户使用简洁的方式表述复杂的属性图(property graph)的遍历或查询。每个Gremlin遍历由一系列步骤(可能存在嵌套)组成,每一步都在数据流(data stream)上执行一个原子操作。
Gremlin 语言包括三个基本的操作:
gremlin> g.addV('person').property(id,'1').property('name','tom')
==>v[1]
gremlin> g.addV('person').property(id,'2').property('name','jack')
==>v[2]
gremlin> g.addV('software').property(id,'3').property('lang','java')
==>v[3]
gremlin> g.addE('uses').from(g.V('1')).to(g.V('3'))
==>e[8ab5866d-4a04-20cf-e4f4-610ec1b45a84][1-uses->3]
gremlin> g.addE('develops').from(g.V('2')).to(g.V('3'))
==>e[96b5866d-74b3-4980-b2b2-93abe93ab990][2-develops->3]
gremlin> g.addE('knows').from(g.V('1')).to(g.V('2'))
==>e[76b5866d-917c-c238-e37d-2ee823b897c2][1-knows->2]
* 顶点:
person
software
* 边:
uses(person -> software)
develops(person -> software)
knows(person -> person)
// 查询所有点,但限制点的返回数量为100,也可以使用range(x, y)的算子,返回区间内的点数量。
gremlin> g.V().limit(100)
==>v[2]
==>v[1]
==>v[3]
// 查询点的label值为'software'的点。
gremlin> g.V().hasLabel('software')
==>v[3]
// 查询id为‘1’的点。
gremlin> g.V('1')
==>v[1]
// 查询所有边,不推荐使用,边数过大时,这种查询方式不合理,一般需要添加过滤条件或限制返回数量。
gremlin> g.E()
==>e[96b5866d-74b3-4980-b2b2-93abe93ab990][2-develops->3]
==>e[76b5866d-917c-c238-e37d-2ee823b897c2][1-knows->2]
==>e[8ab5866d-4a04-20cf-e4f4-610ec1b45a84][1-uses->3]
// 查询边id为‘96b5866d-74b3-4980-b2b2-93abe93ab990’的边。
gremlin> g.E('96b5866d-74b3-4980-b2b2-93abe93ab990')
==>e[96b5866d-74b3-4980-b2b2-93abe93ab990][2-develops->3]
// 查询label为‘develops’的边。
gremlin> g.E().hasLabel('develops')
==>e[96b5866d-74b3-4980-b2b2-93abe93ab990][2-develops->3]
// 查询点id为‘2’所有label为‘develops’的边。
gremlin> g.V('2').outE('develops')
==>e[96b5866d-74b3-4980-b2b2-93abe93ab990][2-develops->3]
// 查询点的所有属性(可填参数,表示只查询该点, 一个点所有属性一行结果)。
gremlin> g.V().limit(3).valueMap()
==>{name=[jack]}
==>{name=[tom]}
==>{lang=[java]}
// 查询点的label。
gremlin> g.V().limit(1).label()
==>person
// 查询点的name属性(可不填参数,表示查询所有属性, 一个点每个属性一行结果,只有value,没有key)。
gremlin> g.V().limit(10).values('name')
==>jack
==>tom
//新增点,Label为user,ID为500,age为18-24。
Graph graph = TinkerGraph.open();
graph.addVertex(label,'person',id,'500','age','18-24')
//新增点,Label为user,ID为500,age为18。
gremlin> g.addV('person').property(id,'500').property('age','18')
==>v[500]
a = graph.addVertex(label,'person',id,'501','age','18-24')
b = graph.addVertex(label,'software',id,'502','title','love')
// 新增边,边的两个点ID分别为501、502。
a.addEdge('develops', b, 'Year','1994')
g.addV('person').property(id,'501').property('age', 24)
g.addV('software').property(id,'502').property('title', 'love')
g.V('501').addE('develops').to(g.V('502')).property('Year', '1994')
// 删除ID为600的点。
g.V('600').drop()
// 删除ID为“501-502-0”的边。
g.E('501-502-0').drop()
// 添加顶点
gremlin> g.addV('person').property(id, '1').property('name', 'marko').property('age', 29)
==>v[1]
gremlin> g.addV('person').property(id, '2').property('name', 'vadas').property('age', 27)
==>v[2]
gremlin> g.addV('software').property(id, '3').property('name', 'lop').property('lang', 'java')
==>v[3]
gremlin> g.addV('person').property(id, '4').property('name', 'josh').property('age', 32)
==>v[4]
gremlin> g.addV('software').property(id, '5').property('name', 'ripple').property('lang', 'java')
==>v[5]
gremlin> g.addV('person').property(id, '6').property('name', 'peter').property('age', 35)
==>v[6]
// 添加边
gremlin> g.addE('knows').from(g.V('1')).to(g.V('2')).property(id, '7').property('weight', 0.5)
==>e[7][1-knows->2]
gremlin> g.addE('knows').from(g.V('1')).to(g.V('4')).property(id, '8').property('weight', 1.0)
==>e[8][1-knows->4]
gremlin> g.addE('created').from(g.V('1')).to(g.V('3')).property(id, '9').property('weight', 0.4)
==>e[9][1-created->3]
gremlin> g.addE('created').from(g.V('4')).to(g.V('5')).property(id, '10').property('weight', 1.0)
==>e[10][4-created->5]
gremlin> g.addE('created').from(g.V('4')).to(g.V('3')).property(id, '11').property('weight', 0.4)
==>e[11][4-created->3]
gremlin> g.addE('created').from(g.V('6')).to(g.V('3')).property(id, '12').property('weight', 0.2)
==>e[12][6-created->3]
顶点为基准:
在众多Gremlin的语句中,有一大类是filter类型,顾名思义,就是对输入的对象进行条件判断,只有满足过滤条件的对象才可以通过filter进入下一步。
has语句是filter类型语句的代表,能够以顶点和边的属性作为过滤条件,决定哪些对象可以通过。常用的有下面几种:
例子:
// lable 等于 person 的所有顶点
g.V().hasLabel('person')
// 所有年龄在20(含)~30(不含)之间的顶点
g.V().has('age',inside(20,30)).values('age')
// 所有年龄不在20(含)~30(不含)之间的顶点
g.V().has('age',outside(20,30)).values('age')
// name 是'josh'或'marko'的顶点的属性
g.V().has('name',within('josh','marko')).valueMap()
// name 不是'josh'或'marko'的顶点的属性
g.V().has('name',without('josh','marko')).valueMap()
// 同上
g.V().has('name',not(within('josh','marko'))).valueMap() g.V().hasNot('age').values('name')
// age 这个属性的所有 value
g.V().properties().hasKey('age').value()
// 不含 age 这个属性的所有 顶点的 name 属性
g.V().hasNot('age').values('name')
path():获取当前遍历过的所有路径;
simplePath():过滤掉路径中含有环路的对象,只保留路径中不含有环路的对象;
cyclicPath():过滤掉路径中不含有环路的对象,只保留路径中含有环路的对象。
// 寻找4跳以内从 andy 到 jack 的最短路径
g.V("andy").repeat(both().simplePath()).until(hasId("target_v_id").and().loops().is(lte(4))).hasId("jack").path().limit(1)
// “Titan” 顶点到与其有两层关系的顶点的不含环路的路径(只包含顶点)
g.V().hasLabel('software').has('name','Titan').both().both().simplePath().path()
* repeat() 和 until() 的位置不同,决定了不同的循环效果:
repeat() + until():等同 do-while;
until() + repeat():等同 while-do。
* repeat() 和 emit() 的位置不同,决定了不同的循环效果:
repeat() + emit():先执行后收集;
emit() + repeat():表示先收集再执行。
注意:
emit()与times()搭配使用时,是“或”的关系而不是“与”的关系,满足两者间任意一个即可。
emit()与until()搭配使用时,是“或”的关系而不是“与”的关系,满足两者间任意一个即可。
g.V('1').repeat(out()).until(outE().count().is('0')).path().by('name')
g.V('1').repeat(out()).until(loops().is('3')).path()
// 创建了 titan 的作者节点的姓名
g.V('titan').in('created').map(values('name'))
// 创建了 titan 的作者节点的所有出边
g.V('titan').in('created').flatMap(outE())
// 默认升序排列
g.V().values('name').order()
// 按照元素属性age的值升序排列,并只输出姓名
g.V().hasLabel('person').order().by('age', asc).values('name')
// 筛选出顶点属性“age”等于28的属性值,与`is(P.eq(28))`等效
g.V().values('age').is(28)
// 所有包含出边“supports”和“created”的顶点的名字“name”
g.V().and(outE('supports'), outE('created')).values('name')
// 使用 where语句 实现上面的功能
g.V().where(outE('supports').and().outE('created').values('name')
// 筛选出所有不是“person”的顶点的“label”
g.V().not(hasLabel('person')).label()
gremlin> g.V().hasLabel('person').and(outE('created').count().is(lte(1)), values("age").is(P.not(P.eq(28)))).values('name')
==>vadas
==>peter
==>marko
// 计算所有“person”的“created”出边数的均值
g.V().hasLabel('person').map(outE('created').count()).mean()
if-else
gremlin> g.V().hasLabel('person').choose(values('age').is(lte(30)),__.in(),__.out()).values('name')
==>marko
==>lop
==>lop
==>ripple
// 结果分析:g.V().hasLabel('person').values('age').is(lte(30)) 的结果是27,29
// 所以 true-traversal——【27,29】:__in()求入度,age=27的入度顶点name是marko,age=29的入度顶点没有
// false-traversal——【32,35】:__out()求出度,age=35的出度顶点name为lop,age=32的出度顶点name为lop和ripple
if-elseif-else
// 查找所有的“person”类型的顶点
// 如果“age”属性等于0,输出名字
// 如果“age”属性等于28,输出年龄
// 如果“age”属性等于29,输出他开发的软件的名字
// choose(predicate).option().option()...
gremlin> g.V().hasLabel('person').choose(values('age')).option(0, values('name')).option(28, values('age')).option(29, __.out('created').values('lang'))
==>java
//
gremlin> g.V().hasLabel('person').choose(values('age')).option(0, values('name')).option(28, values('age')).option(29, __.out('created').values('name')).option(none, values('name'))
==>vadas
==>peter
==>lop
==>josh