it-roy-ru.com

Перебирать строки и столбцы в кадре данных Spark

У меня есть следующий массив данных Spark, который создается динамически:

val sf1 = StructField("name", StringType, nullable = true)
val sf2 = StructField("sector", StringType, nullable = true)
val sf3 = StructField("age", IntegerType, nullable = true)

val fields = List(sf1,sf2,sf3)
val schema = StructType(fields)

val row1 = Row("Andy","aaa",20)
val row2 = Row("Berta","bbb",30)
val row3 = Row("Joe","ccc",40)

val data = Seq(row1,row2,row3)

val df = spark.createDataFrame(spark.sparkContext.parallelize(data), schema)

df.createOrReplaceTempView("people")
val sqlDF = spark.sql("SELECT * FROM people")

Теперь мне нужно перебрать каждую строку и столбец в sqlDF, чтобы напечатать каждый столбец, это моя попытка:

sqlDF.foreach { row =>
  row.foreach { col => println(col) }
}

row имеет тип Row, но не повторяется, поэтому этот код вызывает ошибку компиляции в row.foreach. Как перебрать каждый столбец в Row?

12
ps0604

Вы можете преобразовать Row в Seq с помощью toSeq. Обратившись к Seq, вы можете перебирать его как обычно с помощью foreach, map или чего угодно

    sqlDF.foreach { row => 
           row.toSeq.foreach{col => println(col) }
    }

Результат:

Berta
bbb
30
Joe
Andy
aaa
20
ccc
40
6
SCouto

Считайте, что у вас есть Dataframe, как показано ниже

val df = Seq(
          ("Andy","aaa", 20),     
          ("Berta","bbb", 30),
          ("Joe","ccc", 40)).toDF("name","sector","age")

Зацикливание вашего Dataframe и извлечение элементов из Dataframe , df.foreach не поможет напрямую. Для его реализации вы можете выбрать один из следующих подходов.

Подход 1 - Цикл с использованием rdd

Используйте rdd.collect поверх вашего Dataframe . Переменная row будет содержать каждую строку типа Dataframe типа rdd. Чтобы получить каждый элемент из строки, используйте row.mkString(","), которая будет содержать значение каждой строки в значениях, разделенных запятыми. Используя функцию split (встроенную функцию), вы можете получить доступ к каждому значению столбца строки rdd с помощью индекса.

for (row <- df.rdd.collect)
{   
    var name = row.mkString(",").split(",")(0)
    var sector = row.mkString(",").split(",")(1)
    var age = row.mkString(",").split(",")(2)   
}

Подход 2 - Используя где и выберите

Вы можете напрямую использовать where и select, которые будут внутренне зацикливаться и находить данные. Так как он не должен выбрасывать Index из связанной исключительной ситуации, используется условие if

if(df.where($"name" === "Andy").select(col("name")).collect().length >= 1)
    name = df.where($"name" === "Andy").select(col("name")).collect()(0).get(0).toString

Подход 3 - Использование временных таблиц

Вы можете зарегистрировать фрейм данных как временный, который будет храниться в памяти искры. Затем вы можете использовать запрос на выборку, как и в другой базе данных, для запроса данных, а затем собирать и сохранять в переменной

df.registerTempTable("student")
name = sqlContext.sql("select name from student where name='Andy'").collect()(0).toString().replace("[","").replace("]","")
6
Sarath Avanavu

Вы должны использовать mkString на вашем Row:

sqlDF.foreach { row =>
  println(row.mkString(",")) 
}

Но обратите внимание, что это будет напечатано внутри JVM исполнителей, поэтому в обычном режиме вы не увидите вывод (если вы не работаете с master = local)

2
Raphael Roth

sqlDF.foreach не работает для меня, но Подход 1 из ответа @Sarath Avanavu работает, но он также иногда играл с порядком записей. 

Я нашел еще один способ, который работает

df.collect().foreach { row =>
   println(row.mkString(","))
}
0
Naresh Joshi