我有一个spark数据集的列(在Java中),并且我希望该列的所有值都成为新列的列名(新列可以用常量值填充)。
For example I have:
+------------+
| Column |
+------------+
| a |
| b |
| c |
+------------+
And I want:
+------+----+----+---+
|Column| a | b | c |
+------+----+----+---+
| a | 0 | 0 |0 |
| b | 0 | 0 |0 |
| c | 0 | 0 |0 |
+------+----+----+---+
我尝试过的是:
public class test{
static SparkSession spark = SparkSession.builder().appName("Java")
.config("spark.master", "local").getOrCreate();
static Dataset<Row> dataset = spark.emptyDataFrame();
public Dataset<Row> test(Dataset<Row> ds, SparkSession spark) {
SQLContext sqlContext = new SQLContext(spark);
sqlContext.udf().register("add", add, DataTypes.createArrayType(DataTypes.StringType));
ds = ds.withColumn("substrings", functions.callUDF("add", ds.col("Column")));
return ds;
}
private static UDF1 addSubstrings = new UDF1<String, String[]>() {
public String[] call(String str) throws Exception {
dataset = dataset.withColumn(str, functions.lit(0));
String[] a = {"placeholder"};
return a;
}
};
}
我的问题是,有时我得到正确的结果,有时却没有(没有添加列)。我真的不明白为什么。我正在寻找将数据集传递给UDF的方法,但我不知道如何。
目前,我正在通过使用列的collectAsList()解决此问题,然后迭代Arraylist并由此添加新列。但这确实效率很低,因为我有太多数据。
答案 0 :(得分:2)
对于此用例,您可以使用pivot
:
ds
.withColumn("pivot_column", $"first_column")
.groupBy($"first_column")
.pivot("pivot_column")
.count
如果您想获得更好的性能,则可能需要像pivot("pivot_column", Seq("a", "b", "c"))
一样在数据透视图中提供可能的值
我使用count
进行汇总,但是您可以执行任何所需的汇总。
From
+------------+
|first_column|
+------------+
| a |
| b |
| c |
+------------+
To
+------------+---+---+---+
|first_column| a | b | c |
+------------+---+---+---+
| a | 1 | 0 | 0 |
| b | 0 | 1 | 0 |
| c | 0 | 0 | 1 |
+------------+---+---+---+
答案 1 :(得分:0)
如果Column
的值最小/较小,请尝试以下代码。
df.show
+------+
|Column|
+------+
| A|
| B|
| C|
+------+
// If you have multiple columns are exist, select only required column
val names = df.select($"Column").as[String].collect
val df1 = names.foldLeft(df)((df,n) => df.withColumn(n, lit(0)))
df1.show()
+------+---+---+---+
|Column| A| B| C|
+------+---+---+---+
| A| 0| 0| 0|
| B| 0| 0| 0|
| C| 0| 0| 0|
+------+---+---+---+
答案 2 :(得分:0)
我认为Spark的本质(更确切地说是其并行性)不允许您使用UDF实现目标。
在执行查询时,Spark会将您的数据分发给执行器,每个执行器都有自己的一行行。每个行块都有自己的列Column
的可能值列表。因此,每个执行者都将尝试添加自己的列列表,这与其他执行者的操作不同。
因此,当驱动程序尝试合并来自不同执行者的结果集时,它将失败(或者执行者自身也会失败)。
collectAsList
确实解决了您的问题,尽管效率很低。
也,您可以猜测列数并发明一些功能(适合您的实际数据)以将Column
列获得的值映射到这些数,这样您就可以能够使每个执行器上的列集保持相等。这种解决方案不是很通用,但是可以解决某些情况。
即,您将获得类似以下的列:<c01, c02, c03, ..., cNN>
。