简体   繁体   English

“设置交集”与“有路径”和 Sack()

[英]'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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM