我正在使用 OrientDB 图形数据库。我必须遍历一棵树并在每个节点收集数据并汇总。例如:
如果A是根节点,并且A1和A2节点通过'has'关系连接。 A1与A11和A12连接,具有'a'关系。类似地,A2与A21和A22连接,具有'具有'关系。叶节点A11,A12,A21和A22具有称为“点”的属性。我必须根据子节点计算每个父节点的平均点数。如果A11.points = 20且A12.points = 10。然后A1的平均点变为15.对于A节点,我必须根据A1和A2计算的平均点计算平均点。
A
/ \
A1 A2
/ \ / \
A11 A12 A21 A22
简而言之,我必须从树的根节点开始,继续遍历所有节点并遍历收集数据。是否有人知道如何使用 OrientDB API 或 Gremlin ?
实际上我试图简化问题陈述。平均值不是简单平均值,而是加权平均值。叶子节点还有一个字段,比方说几个小时。平均值将根据小时数而变化。如果A11在100小时内有90分,A12在10小时内有10分。在计算平均点时我们还需要考虑小时数。
答案 0 :(得分:4)
这个解决方案可能会让你更接近你需要的东西,虽然我不确定它是否合适,因为它只是让你计算层次结构选定级别的平均值(即“A”或“A1”) )。这是我的Gremlin会议:
gremlin> g = new TinkerGraph()
==>tinkergraph[vertices:0 edges:0]
gremlin> a = g.addVertex("a")
==>v[a]
gremlin> a1 = g.addVertex("a1")
==>v[a1]
gremlin> a2 = g.addVertex("a2")
==>v[a2]
gremlin> a.addEdge('has',a1)
==>e[0][a-has->a1]
gremlin> a.addEdge('has',a2)
==>e[1][a-has->a2]
gremlin> a1.addEdge('relationship',g.addVertex("a11",[points:20]))
==>e[2][a1-relationship->a11]
gremlin> a1.addEdge('relationship',g.addVertex("a12",[points:20]))
==>e[3][a1-relationship->a12]
gremlin> a2.addEdge('relationship',g.addVertex("a21",[points:100]))
==>e[4][a2-relationship->a21]
gremlin> a2.addEdge('relationship',g.addVertex("a22",[points:0]))
==>e[5][a2-relationship->a22]
gremlin> p=g.v("a").out.loop(1){it.loops<10}{true}.path.filter{it.last().getProperty("points")!=null}.toList()
==>[v[a], v[a2], v[a22]]
==>[v[a], v[a2], v[a21]]
==>[v[a], v[a1], v[a12]]
==>[v[a], v[a1], v[a11]]
gremlin> p.collect{[it, it.last().getProperty("points")]}._().groupBy{it[0][0]}{it[1]}{it.sum()/it.size()}.cap.next()
==>v[a]=35
gremlin> p.collect{[it, it.last().getProperty("points")]}._().groupBy{it[0][1]}{it[1]}{it.sum()/it.size()}.cap.next()
==>v[a1]=20
==>v[a2]=50
因此,这一行为我们提供了重要的路径(即那些以points
的叶节点结束的路径:
p=g.v("a").out.loop(1){it.loops<10}{true}.path.filter{it.last().getProperty("points")!=null}.toList()
我将这些存储在p
中供以后使用。请注意,这将探测由it.loops<10
控制的深度为10的树。从那里使用p
计算平均值非常简单。以下是计算A:
p.collect{[it, it.last().getProperty("points")]}._().groupBy{it[0][0]}{it[1]}{it.sum()/it.size()}.cap.next()
上面基本上说,对于每个路径,将其转换为新的List,其中第一个项目是路径,第二个项目是叶子节点上的点。将该列表转换为具有标识函数的管道,并在路径中的第一个项目上对其进行分组(由it[0][0]
标识),并获取该路径的点值(第二个闭包到groupBy
)。 groupBy
的第三个闭包是一个reducer函数,它对点进行求和并计算平均值。
另一种选择,如果您只需要计算单个顶点的平均值,则采用以下方法:
gremlin> g.v("a").out.loop(1){it.loops<10}{true}.path{it.points}.filter{it.last()!=null}
.transform{it.last()}.gather.transform{it.sum()/it.size()}
==>35
请注意,遍历在开始时大致相同,但在抓取路径时使用闭包。该闭包将顶点转换为points
属性的值(请注意,使用it.getProperty("points")
比it.points
更有效。从那里我再次过滤掉路径中最后一项具有空值的路径(即叶子节点是唯一具有点属性的路径,这应该给我们留下以叶子结尾的路径)。然后我转换这些路径以获取点,将它们收集到列表中并将列表转换为“A”的平均点。
答案 1 :(得分:1)
您可以先查看Traverse statement并存储平均积分: - 进入父顶点或 - 进入运行时上下文
使用Java Traverse编写几行Java(或Javascript)会更容易。
从节点A开始遍历“out”中的所有节点的示例,假设A是name属性(我建议索引“name”属性以便更快地检索):
traverse out('has_a') from (
select from Node where name = 'A'
)
使用此查询,您可以使用key = record和value =基础节点的平均值创建内存映射:
select avg( out('has_a').points ) ) as total_points from (
traverse out('has_a') from (
select from Node where name = 'A'
)
)
仅当“A”下的所有节点都有点时才有效。