[英]'set intersection' vs. 'has path to' and Sack()
The query starts at the vertex 'me'.查询从顶点“我”开始。 I wish to find all A-vertices that are connected to my B-vertex and one of my C-vertices.
我希望找到连接到我的 B 顶点和我的一个 C 顶点的所有 A 顶点。
A person (like me) is always connected to exacty one B-Vertex, but several C-vertices.一个人(像我一样)总是连接到一个 B 顶点,但连接到几个 C 顶点。 Also, the C-vertices connected to me are connected to possibly hundreds of A-vertices.
此外,连接到我的 C 顶点可能连接到数百个 A 顶点。 Whereas, my B-vertex, is usually connected to less than 50 A-Vertices.
然而,我的 B 顶点通常连接到不到 50 个 A 顶点。
=> way more CA edges, than BA edges. => 比 BA 边更多的 CA 边。
I developed two traversals to find all A-vertices connected to my B-vertex and C-vertices.我开发了两个遍历来找到连接到我的 B 顶点和 C 顶点的所有 A 顶点。
To make them more easy to understand, lets call those A-vertices connected to me via the B-vertex 'Ab' and those A-vertices connected to me via a C-vertex 'Ac'.为了使它们更容易理解,我们将那些通过 B 顶点连接到我的 A 顶点称为“Ab”,将那些通过 C 顶点连接到我的 A 顶点称为“Ac”。 Of course the two sets have an intersection, which is exactly what I'm after.
当然这两个集合有交集,这正是我所追求的。
The first traversal uses the 'intersecting set' (Schnittmenge) between the Ac- amd Ab-vertices.第一次遍历使用 Acam 和 Ab 顶点之间的“相交集”(Schnittmenge)。 First it collects all Ab and stores them with 'as()', then it collects all Ac and keeps only those equal to an Ab-vertex.
首先,它收集所有 Ab 并将它们存储在“as()”中,然后它收集所有 Ac 并仅保留那些等于 Ab 顶点的。
g.V('me').out('mb').out('ba').as('Ab')
.V('me').out('mc').out('ca').as('Ac')
.where(eq('Ab'))
variation with aggregate:与聚合的变化:
g.V('me').out('mb').out('ba').aggregate('Ab')
.V('me').out('mc').out('ca')
.where(within('Ab')).dedup()
The seceond uses a filter.第二个使用过滤器。 First collecting all Ab-vertices (as this is the smaller set of the two) and then using filter, to only keep those Ab-vertices that are also connected to me via a C-vertex.
首先收集所有 Ab 顶点(因为这是两者中较小的一组),然后使用过滤器,只保留那些也通过 C 顶点连接到我的 Ab 顶点。
g.V('me').out('mb').out('ba')
.filter(
__.in('ca').in('mc').hasId('me')
)
In my estimation, the second should be more efficient, because it traverses a smaller section of the Graph.据我估计,第二个应该更有效,因为它遍历了 Graph 的一小部分。
Am I right in this assumption?我的这个假设对吗? Is there a more efficient approach?
有没有更有效的方法?
My second problem relates to the sack operator.我的第二个问题与 sack 操作员有关。 I wish to sort the resulting set of A-vertices by the strength of the C-Path.
我希望根据 C 路径的强度对生成的 A 顶点集进行排序。
The first query is capable of doing that.第一个查询能够做到这一点。
g.withSack(1.0f)
.V('me').out('mb').out('ba').as('Ab')
.V('me')
.outE('mc').has('weight').sack(mult).by('weight')
.inV().hasLabel('C')
.outE('ca').has('weight').sack(mult).by('weight')
.inV().hasLabel('A')
.as('Ac')
.where(eq('Ab'))
.group().by().by(sack().sum())
.unfold()
.order().by(values, desc)
Is there a way to get the me-AC sack-value in the second query as well?有没有办法在第二个查询中也获得 me-AC sack-value? My only guess would be to turn the second query around: first find all Ac-vertices, note the sack-values, then remove those not part of Ab.
我唯一的猜测是扭转第二个查询:首先找到所有 Ac 顶点,记下 sack 值,然后删除那些不属于 Ab 的部分。 But this would traverse a huge part of the graph.
但这将遍历图表的很大一部分。 As I said above: the set of Ac-vertices counts several hundred, whereas Ab-vertices are less than fifty.
正如我上面所说:Ac-顶点的集合有几百个,而 Ab-顶点的集合不到五十个。
Data:数据:
g.addV('person').property(id, 'me')
.addV('A').property(id, 'a1')
.addV('A').property(id, 'a2')
.addV('A').property(id, 'a3')
.addV('A').property(id, 'a4')
.addV('B').property(id, 'b')
.addV('C').property(id, 'c1')
.addV('C').property(id, 'c2')
.addE('mc').property(id, 'mc1').property('weight', 0.5).from(V('me')).to(V('c1'))
.addE('mc').property(id, 'mc2').property('weight', 0.6).from(V('me')).to(V('c2'))
.addE('mb').property(id, 'mb').from(V('me')).to(V('b'))
.addE('ba').property(id, 'ba1').from(V('b')).to(V('a2'))
.addE('ba').property(id, 'ba2').from(V('b')).to(V('a3'))
.addE('ba').property(id, 'ba3').from(V('b')).to(V('a4'))
.addE('ca').property(id, 'ca1').property('weight', 0.5).from(V('c1')).to(V('a1'))
.addE('ca').property(id, 'ca2').property('weight', 0.7).from(V('c2')).to(V('a2'))
.addE('ca').property(id, 'ca3').property('weight', 0.4).from(V('c2')).to(V('a3'))
(my code runs on Neptune with gremlin: {'version': 'tinkerpop-3.4.11'}) (我的代码使用 gremlin 在 Neptune 上运行:{'version': 'tinkerpop-3.4.11'})
There is a third option (which can parallellize retrieving B and C, depending on the TinkerPop implementation, but does not retrieve all A):还有第三个选项(可以并行检索 B 和 C,具体取决于 TinkerPop 实现,但不会检索所有 A):
g.V('me').out('mc').as('C')
.V('me').out('mb').out('ba')
.where(in('ca').within('C'))
For the sack multiplication you can traverse back very fast from A to 'me', because the vertices are already in the cache of the graph system.对于 sack 乘法,您可以非常快速地从 A 返回到“我”,因为顶点已经在图形系统的缓存中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.