graphframes是一个基于PySpark DataFrames的网络分析工具。以下代码是教程子图示例的修改版本:
from graphframes.examples import Graphs
import graphframes
g = Graphs(sqlContext).friends() # Get example graph
# Select subgraph of users older than 30
v2 = g.vertices.filter("age > 30")
g2 = graphframes.GraphFrame(v2, g.edges)
人们会期望新图形,g2
将包含更少的节点和更少的边,与原始图形相比,g
。但是,情况并非如此:
print(g.vertices.count(), g.edges.count())
print(g2.vertices.count(), g2.edges.count())
给出输出:
(6, 7)
(7, 4)
很明显,生成的图形包含不存在节点的边。更令人不安的是,g.degrees
和g2.degrees
是相同的。这意味着至少有一些图形功能忽略了节点信息。 有没有一种好方法可以确保GraphFrame
创建仅使用提供的nodes
和edges
参数的交集的图形?
我用来对图形框架进行子图的方法是使用主题:
motifs = g.find("(a)-[e]->(b)").filter(<conditions for a,b or e>)
new_vertices = sqlContext.createDataFrame(motifs.map(lambda row: row.a).union(motifs.map(lambda row: row.b)).distinct())
new_edges = sqlContext.createDataFrame(motifs.map(lambda row:row.e).distinct())
new_graph = GraphFrame(new_vertices,new_edges)
虽然这看起来更复杂,并且在运行时方面可能需要更长的时间,但对于更复杂的图形查询,这可以很好地与您作为单个实体与图形框架进行交互,而不是作为独立的顶点和边进行交互。因此,对顶点进行过滤也会影响图表框中的左侧边。
有趣..我无法看到该结果:
>>> from graphframes.examples import Graphs
>>> import graphframes
>>> g = Graphs(sqlContext).friends() # Get example graph
>>> # Select subgraph of users older than 30
... v2 = g.vertices.filter("age > 30")
>>> g2 = graphframes.GraphFrame(v2, g.edges)
>>> print(g.vertices.count(), g.edges.count())
(6, 7)
>>> print(g2.vertices.count(), g2.edges.count())
(4, 7)
到目前为止,GraphFrames不检查图形是否有效 - 即在图形构建时,所有边都连接到顶点等。但似乎过滤器后的顶点数是正确的?
我的解决方法可能不是完美的,但它们对我有用。
我得到的问题陈述:filtered_nodes过滤了节点集合,我们只想拥有原始图形中的边缘,其中包括来自filtered_nodes节点的边缘。
方法 1:使用联接(成本高昂)
edgesframe = graphframe.edges
src_join = edgesframe.join(filtered_nodes, (edgesframe.src == subgraph_nodes.id), "inner").withColumnRenamed("src", "srcto")
dst_join = edgesframe.join(filtered_nodes, (edgesframe.dst == subgraph_nodes.id), "inner").withColumnRenamed("dst", "dstto")
final_join = src_join.join(dst_join, (src_join.src == dst_join.src) & (src_join.dst == dst_join.dst), "inner").select("src", "dst")
g2 = GraphFrame(filtered_nodes, final_join)
方法 2:使用收集的集合作为 isin 方法的列表引用(我只会在过滤器节点的小集合上使用它)
edgesframe = graphframe.edges
collected_nodes = subgraph_nodes.select("columnWeUseForReference").rdd.map(lambda r: r[0]).collect()
edgs = edgesframe.filter(edgesframe.src.isin(collected_nodes) & edgesframe.dst.isin(collected_nodes))
有人有更好的方法吗?我真的很高兴看到它。
我建议使用dropIsolatedVertices()。