Как выполнить подвыборку окон набора данных в Spark?

#java #apache-spark #subsampling

#java #apache-spark #подвыборка

Вопрос:

Допустим, у меня есть DataSet что-то похожее на это:

 Name    | Grade
---------------
Josh    | 94
Josh    | 87
Amanda  | 96
Karen   | 78
Amanda  | 90
Josh    | 88
  

Я хотел бы создать новый DataSet , в котором каждое имя имеет 3 строки, где дополнительные строки (если таковые имеются) выбираются из строк с тем же именем (например, у Карен будет три одинаковые строки).

Как мне это сделать, не перебирая каждое имя?

Ответ №1:

Подготовка данных :

  val df = Seq(("Josh",94),("Josh",87),("Amanda",96),("Karen",78),("Amanda",90),("Josh",88)).toDF("Name","Grade")
  

Выполните следующее, только если ваши данные skewed для Name :
Добавьте случайное число и отфильтруйте 3 лучших случайных числа для каждого Name .

 val df2 = df.withColumn("random", round(rand()*10))

import org.apache.spark.sql.expressions.Window
val windowSpec  = Window.partitionBy("Name").orderBy("random")

val df3 = df2.withColumn("row_number",row_number.over(windowSpec))
             .filter($"row_number" <= 3)
  

Теперь объедините значения для каждого Name и продублируйте 3 раза, чтобы убедиться, что у нас есть по крайней мере 3 записи для каждого Name . Затем, наконец, возьмите 1-е 3 значения и explode

 df4.groupBy("Name").agg(collect_list("Grade") as "grade_list")
.withColumn("temp_list", slice( flatten(array_repeat($"grade_list", 3)), 1,3))
.select($"Name",explode($"temp_list") as "Grade").show
  

Примечания :

  • Поскольку приведенный выше код будет иметь максимум 3 значения grade_list , следовательно, дублирование его 3 раза не повредит.
  • Если вы не используете этот Window шаг, у вас может быть комбинация из when( size($"grade_list") === n, ).otherwise() вышеуказанного ненужного дублирования.