在 gremlin 中“连接”图的两个节点的正确方法是什么?

问题描述 投票:0回答:2

假设我有一个如下图所示的图表

graph = TinkerGraph.open()
g = graph.traversal()
v1 = g.addV('CC').property('name','t1')
v2 = g.addV('KK').property('name','t1')

我想找到所有与

CC
具有相同
'name'
KK
。我可以写:

g.V().hasLabel('CC').as('c').values('name').as('cn').V().hasLabel('KK').values('name').as('k').where('cn',eq('k')).select('c')

这模仿了SQL中的连接,但是这样写性能看起来很糟糕。从SQL2Gremlin,他们有“连接”两个节点(如果两个节点之间有边连接)的示例。我想知道gremlin中是否有任何连接方法可以预先未知是否存在连接两个节点的路径?换句话说,在 gremlin 中编写“join”的最佳方法是什么,而我们不知道这两个节点是否直接连接或通过路径连接?

非常感谢!

gremlin
2个回答
1
投票

你的直觉基本上是正确的。 “连接”是两个顶点之间已实现的关系(即边)。这通常是图数据库所能获得的收益。对于图来说,以 SQL 样式对属性执行顶点到顶点连接通常效率不高。

对于您的查询,您可以将其重新写入此表单以更加清晰:

gremlin> g.V().hasLabel('CC').as('c').
......1>   V().hasLabel('KK').
......2>   where(eq('c')).
......3>     by('name').
......4>   select('c')
==>v[0]

但是性能可能会保持不变,因为我认为目前没有任何图形系统会优化这种遍历。不会使用任何索引,您将留下“CC”和“KK”的完整图形扫描来获取结果。显然,这在大图上是非常昂贵的。

Gremlin 用户邮件列表这里对此主题进行了一些讨论,其中提出了一些很好的观点。值得注意的是,乔什·佩里曼(Josh Perryman)写道(除其他优点外):

SQL 风格的连接是对图形数据库引擎的一种非常糟糕的使用。喜欢 丹尼尔建议应预先计算连接并在以下位置添加边缘 写入时间/数据我开玩笑。

这是必然和设计的。边缘基本物化 加入。图形数据库针对它们进行了优化,磁盘或缓存读取 手术。关系数据库针对连接、查询时间进行了优化 电脑操作。

预先计算边缘通常要便宜得多 在加载数据之前分离引擎而不是在数据加载之后这样做 进入图表。例外情况是当边缘已确定时 基于通过图的多跳路径。对于该用例,图表 dB 最好。


0
投票

斯蒂芬·马莱特写道:

因为我认为目前没有任何图形系统会优化这种遍历。

pymogwai 正在尝试朝这个方向发展,它是本机 python gremlin 实现。我们打算为其使用 SPOG 索引。看 https://github.com/juupje/pyMogwai/issues/13

https://github.com/juupje/pyMogwai/blob/main/mogwai/core/hd_index.py

基于A。 Harth 和 S. Decker,“从 Web 查询 RDF 的优化索引结构”,第三届拉丁美洲 Web 大会 (LA-WEB'2005),阿根廷布宜诺斯艾利斯,2005 年,第 10 页,doi: 10.1109/LAWEB .2005.25.


'''
Created on 2024-11-10

@author: wf
'''
import json
from mogwai.core.mogwaigraph import MogwaiGraph, MogwaiGraphConfig
from mogwai.core.traversal import MogwaiGraphTraversalSource
from tests.basetest import Basetest

class TestSpogJoin(Basetest):
    """Test SPOG index based joins"""

    def setUp(self, debug=True):
        Basetest.setUp(self, debug=debug)

    def test_spog_join(self):
        """Test joining vertices by property values using SPOG index"""
        # Create test graph with CC and KK vertices having same names
        graph = MogwaiGraph(config=MogwaiGraphConfig(name_field='_node_name',index_config='minimal'))

        # Add test vertices
        v1 = graph.add_labeled_node('CC', 't1', {'name': 't1'})
        v2 = graph.add_labeled_node('CC', 't2', {'name': 't2'})
        v3 = graph.add_labeled_node('KK', 'k1', {'name': 't1'})
        v4 = graph.add_labeled_node('KK', 'k2', {'name': 't3'})

        # Use SPOG join
        graph.join('CC', 'KK', 'name', 'name', 'same_name')

        # Verify joins
        g=MogwaiGraphTraversalSource(graph)
        joins = g.E().has_label('same_name').count().next().run()
        self.assertEqual(joins, 1)

        if self.debug:
            self.show_indices(graph.spog_index)

    def show_indices(self, spog_index, limit=3):
        """Show SPOG index contents"""
        for index_name in spog_index.config.active_indices:
            if index := spog_index.indices.get(index_name):
                print(f"Index: {index_name}")
                keys = list(index.lookup.keys())[:limit]
                lookup = {k: list(index.lookup[k])[:limit]
                         for k in keys}
                print(json.dumps(lookup, indent=2, default=str))

Index: PO
{
  "label": [
    "KK",
    "CC",
    "same_name"
  ],
  "name": [
    "t2",
    "same_name",
    "t3"
  ],
  "same_name": [
    2
  ]
}
Index: PG
{
  "label": [
    "node-label",
    "edge-label"
  ],
  "name": [
    "edge-name",
    "node-name",
    "node-property"
  ],
  "same_name": [
    "edge-link"
  ]
}
Index: SG
{
  "0": [
    "node-property",
    "edge-label",
    "edge-link"
  ],
  "1": [
    "node-label",
    "node-name",
    "node-property"
  ],
  "2": [
    "node-label",
    "node-name",
    "node-property"
  ]
}
Index: SO
{
  "0": [
    "t1",
    2,
    "CC"
  ],
  "1": [
    "t2",
    "CC"
  ],
  "2": [
    "t1",
    "KK",
    "k1"
  ]
}
Index: OS
{
  "CC": [
    0,
    1
  ],
  "t1": [
    0,
    2
  ],
  "t2": [
    1
  ]
}
Index: GO
{
  "node-label": [
    "KK",
    "CC"
  ],
  "node-name": [
    "t1",
    "t2",
    "k2"
  ],
  "node-property": [
    "t1",
    "t2",
    "t3"
  ]
}
Index: PS
{
  "label": [
    0,
    1,
    2
  ],
  "name": [
    0,
    1,
    2
  ],
  "same_name": [
    0
  ]
}
Index: GP
{
  "node-label": [
    "label"
  ],
  "node-name": [
    "name"
  ],
  "node-property": [
    "name"
  ]
}
test test_spog_join, debug=True took   0.0 s
----------------------------------------------------------------------
Ran 1 test in 0.006s
© www.soinside.com 2019 - 2024. All rights reserved.