最近一年对JanusGraph接触较多,故经常使用Gremlin图遍历语言,对其常见语法做简要整理,备忘。
Gremlin语句基础用法介绍
基础语法
V():查询顶点,一般作为图查询的第1步,后面可以续接的语句种类繁多。例:g.V(),g.V('v_id'),查询所有点和特定点;
E():查询边,一般作为图查询的第1步,后面可以续接的语句种类繁多;
id():获取顶点、边的id。例:g.V().id(),查询所有顶点的id;
label():获取顶点、边的 label。例:g.V().label(),可查询所有顶点的label。
key()/values():获取属性的key/value的值。
properties():获取顶点、边的属性;可以和 key()、value()搭配使用,以获取属性的名称或值。例:g.V().properties('name'),查询所有顶点的 name 属性;
valueMap():获取顶点、边的属性,以Map的形式体现,和properties()比较像;
values():获取顶点、边的属性值。例:g.V().values() 等于 g.V().properties().value()
遍历
以“顶点”为基准
out(label):根据指定的Edge Label来访问【顶点的OUT方向邻接点】(零个Edge Label,代表所有类型边;也可为一个或多个Edge Label,代表任意给定Edge Label的边,下同);
in(label):根据指定的Edge Label来访问【顶点的IN方向邻接点】;
both(label):根据指定的Edge Label来访问【顶点的双向邻接点】;
outE(label):根据指定的Edge Label来访问【顶点的OUT方向邻接边】;
inE(label):根据指定的Edge Label来访问【顶点的IN方向邻接边】;
bothE(label):根据指定的Edge Label来访问【顶点的双向邻接边】;
以“边”为基准
outV():访问【边的出顶点】,出顶点是指【边的起始顶点】;
inV():访问【边的入顶点】,入顶点是指【边的目标顶点】,箭头指向的顶点;
bothV():访问【边的双向顶点】;
otherV():访问【边的伙伴顶点】,即相对于基准顶点而言的另一端的顶点;
过滤
has语句是filter类型语句的代表,能够以顶点和边的属性作为过滤条件,决定哪些对象可以通过。常用的有下面几种:
has(key,value): 通过属性的名字和值来过滤顶点或边;
has(label, key, value): 通过label和属性的名字和值过滤顶点和边;
has(key,predicate): 通过对指定属性用条件过滤顶点和边,例:g.V().has('age', gt(20)),可得到年龄大于20的顶点; predicate(断言)
hasLabel(labels…): 通过 label 来过滤顶点或边,满足label列表中一个即可通过;
hasId(ids…): 通过 id 来过滤顶点或者边,满足id列表中的一个即可通过;
hasKey(keys…): 通过 properties 中的若干 key 过滤顶点或边;
hasValue(values…): 通过 properties 中的若干 value 过滤顶点或边;
has(key): properties 中存在 key 这个属性则通过,等价hasKey(key);
hasNot(key): 和 has(key) 相反;
路径
path():获取当前遍历过的所有路径;
simplePath():过滤掉路径中含有环路的对象,只保留路径中不含有环路的对象;
cyclicPath():过滤掉路径中不含有环路的对象,只保留路径中含有环路的对象。
迭代
repeat():指定要重复执行的语句;
times(): 指定要重复执行的次数,如执行3次;
until():指定循环终止的条件,如一直找到某个名字的朋友为止;
emit():指定循环语句的执行过程中收集数据的条件,每一步的结果只要符合条件则被收集,不指定条件时收集所有结果;
loops():当前循环的次数,可用于控制最大循环次数等,如最多执行3次。
repeat() 和 until() 的位置不同,决定了不同的循环效果:
repeat() + until():等同 do-while;
until() + repeat():等同 while-do。
repeat() 和 emit() 的位置不同,决定了不同的循环效果:
repeat() + emit():先执行后收集;
emit() + repeat():表示先收集再执行。
排序
order()
order().by()
逻辑
is():可以接受一个对象(能判断相等)或一个判断语句(如:P.gt()、P.lt()、P.inside()等),当接受的是对象时,原遍历器中的元素必须与对象相等才会保留;当接受的是判断语句时,原遍历器中的元素满足判断才会保留,其实接受一个对象相当于P.eq();
and():可以接受任意数量的遍历器(traversal),原遍历器中的元素,只有在每个新遍历器中都能生成至少一个输出的情况下才会保留,相当于过滤器组合的与条件;
or():可以接受任意数量的遍历器(traversal),原遍历器中的元素,只要在全部新遍历器中能生成至少一个输出的情况下就会保留,相当于过滤器组合的或条件;
not():仅能接受一个遍历器(traversal),原遍历器中的元素,在新遍历器中能生成输出时会被移除,不能生成输出时则会保留,相当于过滤器的非条件。
统计
sum():将 traversal 中的所有的数字求和;
max():对 traversal 中的所有的数字求最大值;
min():对 traversal 中的所有的数字求最小值;
mean():将 traversal 中的所有的数字求均值;
count():统计 traversal 中 item 总数。
常用Gremlin语句详解
查询所有点,但限制点的返回数量为100,也可以使用range(x, y)的算子,返回区间内的点数量
g.V().limit(100)
查询点的label值为'software'的点
g.V().hasLabel('software') # label为点类型名称,如:“员工”、“客户”,例:g.V().hasLabel('员工') ;g.V().hasLabel('账户','员工')
查询id为'11'的点
g.V('11')
g.V().id() #查询所有点的janusGraph生成的点id #12312
查询id为'8392'的点属性
g.V('8392').properties()
g.V('8392').valueMap()
查询账户点中卡账号属性为'6217002430020910004'的OUT方向邻接边
g.V().has('账户','卡账号','6217002430020910004').outE().limit(20)
查询账户点中卡账号属性为'6217002430020910004'的IN方向邻接边
g.V().has('账户','卡账号','6217002430020910004').inE().limit(20)
查询账户点中卡账号属性为'6217002430020910004'的双向邻接边
g.V().has('账户','卡账号','6217002430020910004').bothE().limit(20)
g.V().hasLabel('person') // lable 等于 person 的所有顶点;
g.V().has('age',inside(20,30)).values('age') // 所有年龄在20(含)~30(不含)之间的顶点;
g.V().has('age',outside(20,30)).values('age') // 所有年龄不在20(含)~30(不含)之间的顶点;
g.V().has('name',within('josh','marko')).valueMap() // name 是'josh'或'marko'的顶点的属性;
g.V().has('name',without('josh','marko')).valueMap() // name 不是'josh'或'marko'的顶点的属性;
g.V().has('name',not(within('josh','marko'))).valueMap() // 同上,用not修饰within来生成without语义
g.V().properties().hasKey('age').value() // age 这个属性的所有 value
g.V().hasNot('age').values('name') // 找到所有不含age属性的顶点,并且获取他们的name
g.V().has('账户','卡账号','6217002430020910004').bothE().bothV().bothE().limit(20)
g.V().has('账户','卡账号','6217002430020910004').both().both().bothE().limit(20)
g.V().has('账户','卡账号','6217002430020910004').both().both().bothE().hasLabel('转账交易').has('资金交易总金额',within('2342353')).limit(100)
g.V(602128).bothE().where(hasLabel('家庭地址').or().hasLabel('家庭电话')).bothV().dedup().has('座机号码',is('021-7625532')).valueMap()
查询过滤某个下一层点边的语法结构
g.V(16520).bothE().where(has().and().has().or().has()).otherV().hasLabel().where(has().and().has().or().has())
where()中可以使用如下条件
g.V().has('age',inside(20,30)) // 所有年龄在20(含)~30(不含)之间的顶点;
g.V().has('age',outside(20,30)) // 所有年龄不在20(含)~30(不含)之间的顶点;
g.V().has('name',within('josh','marko')) // name 是'josh'或'marko'的顶点的属性;
g.V().has('name',without('josh','marko')) // name 不是'josh'或'marko'的顶点的属性;
g.V().has('name',not(within('josh','marko')))// 同上
g.V().has('name',is('josh'))
抽象示例
g.V(16520).bothE('edgeLabel1','edgeLabel2').where(has('edgeProp1',eq(edgeValue1)).and().has('edgeProp2',eq(edgeValue2)).or().has('edgeProp3',eq(edgeValue3))).otherV().hasLabel('vertexLabel1','vertexLabel2').where(has('vertexProp1',eq(vertexValue1)).and().has('vertexProp2',eq(vertexValue2)).or().has('vertexProp3',eq(vertexValue3)))
实际示例
g.V(16520).bothE('员工管辖客户','员工本人行内账户','关联关系','转账交易').where(has('资金交易总金额',eq(12124))).otherV().hasLabel('账户','账户').where(has('卡账号','6217002430020910014'))