从Spark Dataset收集结果的最佳方法是什么?

时间:2018-05-17 20:44:57

标签: apache-spark apache-spark-sql apache-spark-dataset

我有一个包含2个字段/列的数据集javahcol1,两者都是col2类型。我正在为Array[String]的每个元素按排序顺序从col1收集不同的元素,并仅保留名为_dArr的List中的第一个元素。问题是_list,这需要花费很多时间。有没有更好的方法可以用来提高代码的效率。我还使用了一个空数据集,并使用union来添加新行,我从每个for循环获得val arr = _ds.take(1)(0),以便稍后我可以对该结果数据集执行_ds以获得collect结果1}}。但它也花了很多时间。

List[Array[String]]

示例输入:

case class ColFields(fields: Array[String])
var _dArr = null: Array[String]
var _list = List[ClassFields]()

    _dArr.foreach(x => {
      val _ds = df.select("col1")
        .where(array_contains(df("col2"), x))
        .withColumn("col1", explode(col("col1")))
        .agg(sort_array(collect_set("col1")).alias("col1")).as[Array[String]]
        .cache()

      val arr = _ds.take(1)(0)
      // val arr = _ds.collect()(0) // Does not make any performance difference.
      distPredDS.unpersist()

      _list ::= ColFields(arr)
    })

输出:

_dArr = Array[x, y, w]

col1         col2
------------------
[a, b]      [w, x]
[a, d]      [x, y]
[c, d, f]   [y]
[h]         [w]

,或者

List[Array[a, b, d], Array[a, c, d, f], Array[a, b, h]]

1 个答案:

答案 0 :(得分:0)

根据我的理解,你试图找出col2是否包含dArray中的任何元素,如果是,则获取从col1排序到列表中的第一个元素。

    val dArr = Array("x","y","z")
    val df = Seq((Array("s","x","w"),Array("a","x")),(Array("v","d","e"),Array("b","z")),(Array("a","b","c"),Array("f","d"))).toDF("col1","col2")
   def checkValues(arr: Array[String]) = udf((col1: Seq[String], col2: Seq[String]) => { if (col2.exists(arr.contains)) col1.toList.sortWith(_ < _).head else ""})
   df.withColumn("col1_first", checkValues(dArr)($"col1",$"col2")).select($"col1_first").collectAsList

我在这里通过col1&amp; col2到UDF,它将col2与arr进行比较,并在对col1进行排序后得到col1的第一个元素。然后,您可以过滤非空值和collectAsList。

请告诉我它是否有效,否则请提供更多信息,包括您期望的数据样本。

我已修改,但爆炸似乎是一项代价高昂的操作。看看它是否有助于您的数据集,

val dArr = Array("x","y","w")
val df = Seq((Array("a","b"),Array("w","x")),(Array("a","d"),Array("x","y")),(Array("c","d","f"),Array("x","y")),(Array("h"),Array("w"))).toDF("col1","col2")
def checkValues(arr: Array[String]) = udf((col1: Seq[String], col2: Seq[String]) => { arr.foldLeft(Array[String]()){case(acc, elem) => {if (col2.contains(elem)) acc :+ elem else acc}}})
val df_1 = df.withColumn("arrValues", explode(checkValues(dArr)($"col1",$"col2")))
df_1.select($"arrValues",explode($"col1").as("col1")).groupBy($"arrValues").agg(collect_set($"col1").as("col1_list")).show