我对Spark很新,并且不太了解基础知识,我只是跳进去解决问题。该问题的解决方案涉及制作图形(使用GraphX),其中边具有字符串属性。用户可能希望查询此图形并通过仅过滤出具有与用户查询相等的字符串属性的边缘来处理查询。
现在,我的图表边缘超过1600万;当我使用计算机的所有8个内核时,创建图表需要10多分钟。但是,当我查询这个图表时(就像我上面提到的那样),我立刻得到了结果(令我惊喜的是)。
所以,我的问题是,过滤器操作究竟是如何搜索我查询的边缘的?它是否迭代地看待它们?是否在多个核心上搜索边缘,它看起来非常快?或者是否涉及某种哈希?
以下是我如何使用过滤器的示例:Mygraph.edges.filter(_。attr(0).equals(" cat"))这意味着我想要检索边缘具有属性" cat"在他们中。如何搜索边缘?
答案 0 :(得分:2)
运行语句的速度非常快,因为它实际上并没有执行过滤。 Spark使用延迟评估:在您执行实际收集结果的操作之前,它实际上并不执行转换。调用转换方法(如filter
)只会创建一个表示此转换及其结果的新RDD。您必须执行操作,例如collect
或count
才能实际执行该操作:
def myGraph: Graph = ???
// No filtering actually happens yet here, the results aren't needed yet so Spark is lazy and doesn't do anything
val filteredEdges = myGraph.edges.filter()
// Counting how many edges are left requires the results to actually be instantiated, so this fires off the actual filtering
println(filteredEdges.count)
// Actually gathering all results also requires the filtering to be done
val collectedFilteredEdges = filteredEdges.collect
请注意,在这些示例中,过滤器结果不存储在以下之间:由于懒惰,两次操作都会重复过滤。为了防止这种重复,在阅读了有关转换和操作的详细信息以及Spark在场景背后实际执行的操作后,您应该查看Spark的缓存功能:https://spark.apache.org/docs/latest/programming-guide.html#rdd-operations。
边缘存储在EdgeRDD[ED]
类型的RDD中,其中ED
是边缘属性的类型,在您的情况String
中。这个特殊的RDD在后台进行了一些特殊的优化,但是出于你的目的,它的行为类似于它的超类RDD[Edge[ED]]
,并且过滤就像过滤任何RDD一样:它将迭代所有项,将给定的谓词应用于每个项。然而,RDD被分成许多分区,Spark将并行过滤多个分区;在您似乎在本地运行Spark的情况下,它将与您拥有的核心数量并行,或者您使用--master local[4]
明确指定了多少。
带边的RDD根据设置的PartitionStrategy
进行分区,例如,如果您使用Graph.fromEdgeTuples
创建图表或在图表上调用partitionBy
。但是,所有策略都基于边缘顶点,因此不了解您的属性,因此不会影响您的过滤操作,除非您可能会遇到一些不平衡的网络负载#39 ; d在集群上运行它,所有的“猫”都是edge最终出现在同一个分区/执行器中,并执行collect
或一些shuffle操作。有关如何表示和分区图表的更多信息,请参阅GraphX docs on Vertex and Edge RDDs。