Spark,DataFrame:从许多列中获取所有不同的字符串

Spark, DataFrame: Get all distinct strings from many columns

数据DataFrame 有 15 个字符串列。

目标:创建一个包含所有 15 列中不同字符串的列表。

示例:如果单词"guitar"在第一列和第四列中出现一次或多次,则它必须在最终名单。

建议的解决方案但并不理想:UDF 是一种将所有列连接到一个新列中的选项,然后我可以使用 CountVectorizer 处理该列将提取词汇。但是 UDF 是有限的,因为它们最多接受 10 个输入参数(即我不能将超过 10 列传递给 UDF),所以这个解决方案必须实现两个 UDF,第一个连接 10 列,第二个连接带有接下来 5 列的第一个 UDF 的输出。

我正在为这个问题寻找一个更有效的紧凑解决方案,更一般地说,是一个解决 UDF 输入参数数量有限问题的解决方案。

spark-sql 函数 array 可以将任意数量的冒号(相同类型)映射到该类型的数组列。

从那时起,您可以在数组类型上创建 UDF,或者针对您的情况,按照建议使用 CountVectorizer。

scala> val data = spark.sparkContext.parallelize(Seq(("a1", "b1", "c1"), ("a2", "b2", "c2"))).toDF("a", "b", "c")
data: org.apache.spark.sql.DataFrame = [a: string, b: string ... 1 more field]

scala> data.show
+---+---+---+
|  a|  b|  c|
+---+---+---+
| a1| b1| c1|
| a2| b2| c2|
+---+---+---+

scala> data.select(array("a", "b", "c")).show
+--------------+
|array(a, b, c)|
+--------------+
|  [a1, b1, c1]|
|  [a2, b2, c2]|
+--------------+

虽然比 CountVectorizer 更简单:

scala> data.select(explode(array("a", "b", "c"))).distinct.show
+---+
|col|
+---+
| b2|
| c1|
| a2|
| b1|
| a1|
| c2|
+---+

如果您可以直接使用 RDD,那么还有更简单(而且可能更快)的方法:

scala> data.rdd.flatMap(r=>r.toSeq).distinct.collect
res4: Array[Any] = Array(b2, a1, a2, c1, c2, b1)