图的变换操作#

我们将介绍一系列可以在图上进行新增/投影的方法,以及如何将一个复杂的图转换为可以适配普通算法应用的方法。 最后,我们展示如何将算法得到的结果加回到图中去。

具体而言,图 Graph 提供了两个增加标签的函数, 和一个投影的函数。

def add_vertices(self, vertices, label="_", properties=[], vid_field=0):
    pass

def add_edges(self, edges, label="_", properties=[], src_label=None, dst_label=None, src_field=0, dst_field=1):
    pass

def project(self, vertices, edges):
    pass

其中,我们已经在 载图 一节见到过 add_verticesadd_edges 这两个函数,当时我们用它来构建一张图。 进一步的,当图构建好并载入了 Vineyard 中之后,我们仍然可以用其增加更多的标签。当然这一步并不会在原图上修改,而是会返回基于原图之上, 增加了新的标签的新图。

添加新的标签#

以 LDBC-SNB 属性图为例,我们现在载入其中一部分标签,作为接下来一系列转换操作的起始图。

import graphscope
from pathlib import Path
from graphscope.framework.loader import Loader

sess = graphscope.session()

graph = sess.g(directed=directed)
graph = graph.add_vertices(Loader("person_0_0.csv", delimiter="|"), "person")
graph = graph.add_edges(Loader("person_knows_person_0_0.csv", delimiter="|"),
            "knows", src_label="person", dst_label="person"
    )

# graph has 1 vertex label "person"
print(graph.schema)

到这里, 我们已经载入了一张图。接下来我们在这张图上再添加几个标签。

graph1 = graph.add_vertices(Loader("comment_0_0.csv", delimiter="|"), "comment")

# Now graph1 has 2 vertex labels "person" and "comment"
print(graph1.schema)

graph2 = graph1.add_edges(Loader("comment_replyOf_comment_0_0.csv", delimiter="|"),
            "replyOf", src_label="comment", dst_label="comment"
    )

# graph2 has 2 edge labels "knows" and "replyOf"
print(graph2.schema)

可以看到每次 add 都会产生一张新的图,在底层,他们共有的部分会指向同一块内存,所以并不会将原图的数据复制一份。

投影#

在某些场景下,我们需要将从一张复杂的图提取出一个子图。这个操作可以借助 project 来完成。

def project(
        self,
        vertices: Mapping[str, Union[List[str], None]],
        edges: Union[Mapping[str, Union[List[str], None]], None]
    ):
    pass

project 包含两个参数 verticesedges,其值为一个字典,字典的键是标签名,值是要取的属性的列表。值可以为 None, 代表选择所有的属性。

project 的返回值也是一个属性图,并且可以被进一步 project。 以下是几个例子。

sub_graph = graph2.project(vertices={"person": ["firstName", "lastName"]}, edges={"knows": None})

# 包含一个点标签 "person" 和一个边标签 "knows", 以及所选择的属性。
print(sub_graph.schema)

sub_graph2 = sub_graph.project(vertices={"person": []}, edges={"knows": ["creationDate"]})

# 现在点上没有属性,边上有一个属性
print(sub_graph2.schema)

自动转换为简单图#

当执行一个仅可以跑在简单图上的算法时,其会默认将其参数中的属性图转换为简单图,如果不能进行这种转换(即多于一个点标签和一个边标签,或多于一个属性), 那么就会报错。

from graphscope import wcc

ret = wcc(sub_graph2)

# wcc(graph2)  # 错误! 转换不合法,多于一个点/边标签
# wcc(sub_graph)  # 错误!转换不合法,多于一个属性

将计算结果作为新的属性加入图中#

上一步算法的运行结果可以被加入一张图中, 作为点的一个属性。

不仅可以加入运算结果到直接被查询的图上,还可以将这个查询结果加到被 project 而得到被查询的图上,只要被加入属性的点标签相同。

new_graph = sub_graph2.add_column(ret, selector={'cc': 'r'})

new_graph = sub_graph.add_column(ret, selector={'cc': 'r'})

new_graph = graph.add_column(ret, selector={'cc': 'r'})