基于Gremlin Tinkerpop从图数据库多顶点提取多属性问题
TinkerPop 3.5.1 用 aggregate() 结合 valueMap() 提取多属性键值对集合
问题原因
你写的查询 g.V().has("name", "Jefferson").out("offers").aggregate("x").by("level").by("name").cap("x") 没达到预期,是因为**aggregate() 后面跟多个 .by() 不是用来收集多个属性的,而是用来指定聚合的分组维度或者多层处理逻辑**,所以最终只会保留最后一个 .by() 的结果,还出现了异常值。
解决方法
要拿到顶点的多属性键值对,核心是用 valueMap() 提取顶点的属性映射,再配合 aggregate() 完成聚合。下面分场景给你实现方案:
1. 获取学校开设的课程属性
先实现你最初尝试的,获取Jefferson学校的Class属性:
g.V().has("name", "Jefferson") .out("offers") .aggregate("classes") .by(valueMap().by(unfold())) // unfold() 把多值属性转成单值,符合你要的键值对格式 .cap("classes")
执行后会返回:
[ {name: "English", level: 2}, {name: "Math", level: 2} ]
要是需要保留顶点的id、label这些元数据,就改成
valueMap().with(WithOptions.tokens).by(unfold())
2. 一次性获取所有关联顶点的属性
如果要拿到你预期里的所有顶点(Class、Admin、Student)的属性,得先遍历所有关联顶点再聚合:
g.V().has("name", "Jefferson") // 遍历所有关联的顶点:Admin(反向administers边)、Student(反向attends边)、Class(正向offers边) .union( __.in("administers"), __.in("attends"), __.out("offers") ) .aggregate("allVertices") .by(valueMap().by(unfold())) .cap("allVertices")
这个查询返回的结果就是你想要的结构:
[ {status: "AFW", level: "4.2A"}, {name: "Peter", age: 22}, {name: "Sam", age: 24}, {name: "Math", level: 2}, {name: "English", level: 2} ]
3. Java代码中的实现
在Java中调用TinkerPop API的示例:
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import java.util.List; // 假设已经初始化好了GraphTraversalSource实例g List<Object> vertexProperties = g.V() .has("name", "Jefferson") .union( __.in("administers"), __.in("attends"), __.out("offers") ) .aggregate("allVertices") .by(__.valueMap().by(__.unfold())) .cap("allVertices") .next(); // 打印结果 System.out.println(vertexProperties);
关键点总结
aggregate()的.by():单个.by()用来指定要聚合的内容,多个.by()是做分组或多层聚合,不是用来收集多个属性的。valueMap():专门用来提取顶点的属性映射,.by(unfold())可以把默认的多值属性列表转成单值,更贴合你要的键值对格式。union():用来合并多个遍历分支,一次性拉取所有关联的不同类型顶点。
内容的提问来源于stack exchange,提问作者Ebad
相关产品推荐
相关产品推荐

