Graphx: у меня есть исключение NullPointerException внутри mapVertices

Я хочу использовать graphx. Пока я просто запускаю его локально. У меня есть NullPointerException в этих нескольких строках. Первый println работает хорошо, а второй не работает.

..........
val graph: Graph[Int, Int] = Graph(users, relationships)
println("graph.inDegrees = " + graph.inDegrees.count) // this line works well
graph.mapVertices((id, v) => {
  println("graph.inDegrees = " + graph.inDegrees.count) // but this one fails
  42 // doesn't mean anything
}).vertices.collect

И не имеет значения, какой метод объекта 'graph' я вызываю. Но 'graph' не равен нулю внутри 'mapVertices'.

Exception failure in TID 2 on host localhost: 
java.lang.NullPointerException
org.apache.spark.graphx.impl.GraphImpl.mapReduceTriplets(GraphImpl.scala:168)
org.apache.spark.graphx.GraphOps.degreesRDD(GraphOps.scala:72)
org.apache.spark.graphx.GraphOps.inDegrees$lzycompute(GraphOps.scala:49)
org.apache.spark.graphx.GraphOps.inDegrees(GraphOps.scala:48)
ololo.MyOwnObject$$anonfun$main$1.apply$mcIJI$sp(Twitter.scala:42)

2 ответа

Решение

Воспроизведено с использованием GraphX ​​2.10 на Spark 1.0.2. Я дам вам обходной путь, а затем объясню, что, по моему мнению, происходит. Это работает для меня:

val c = graph.inDegrees.count
graph.mapVertices((id, v) => {
  println("graph.inDegrees = " + c)
}).vertices.collect

В общем, Spark становится колючим, когда вы пытаетесь получить доступ ко всему RDD или другой распределенный объект (например, Graph) в коде, который предназначен для параллельного выполнения на одном разделе, например, функции, в которую вы передаете mapVertices, Но это также обычно плохая идея, даже если вы можете заставить ее работать. (Как вы уже видели, когда это не работает, это приводит к действительно бесполезному поведению.)

Вершины Graph представлены в виде RDDи функция, в которую вы переходите mapVertices выполняется локально в соответствующих разделах, где ему предоставляется доступ к локальным данным вершин: id а также v, Вы действительно не хотите, чтобы весь граф копировался в каждый раздел. В этом случае вам просто нужно транслировать скаляр на каждый раздел, поэтому его удаление решит проблему, и трансляция будет действительно дешевой.

В API Spark есть хитрости, позволяющие получить доступ к более сложным объектам в такой ситуации, но если вы будете использовать их небрежно, они снизят вашу производительность, потому что они, как правило, привносят много общения. Часто люди испытывают желание использовать их, потому что они не понимают модель вычислений, а не потому, что они действительно нуждаются в этом, хотя это тоже случается.

Spark не поддерживает вложенные RDD или пользовательские функции, которые ссылаются на другие RDD, следовательно, NullPointerException; увидеть эту тему на spark-users список рассылки. В этом случае вы пытаетесь позвонить count() на Graph (который выполняет действие на Spark RDD) изнутри mapVertices() преобразование, приводящее к NullPointerException, когда mapVertices() пытается получить доступ к структурам данных, которые могут быть вызваны только драйвером Spark.

Одним словом, только драйвер Spark может запускать новые задания Spark; Вы не можете вызывать действия на RDD изнутри других действий RDD.

См. /questions/10896131/nullpointerexception-v-scala-spark-po-vidimomu-vyizvano-tipom-kollektsii/10896142#10896142 для другого примера этой проблемы.

Другие вопросы по тегам