我正在使用Spark创建一个倒排索引(或更多的"发布列表",所以发布的顺序很重要),看起来有点像这样
| key | postings |
----------------------------------------------------------
| "a" | 1, 3, 4, 7, 8, 9, 21, 25 |
| "b" | 7, 12, 21, 24, 28, 31, 37, 48, 51, 91 |
| "c" | 1, 2, 3, 10, 12, 17, 21, 38, 39, 40, 47 |
注意密钥是例如在字符串中,发布是例如整数的排序列表。我稍后会使用贴子列表并多次迭代(希望非常有效)。
我想知道在Spark中创建这样一个数据帧最好的选择是什么,最后将它存储到Parquet。你建议例如使用嵌套结构?或者更确切地说使用一个数组进行发布(尽管如果我想存储的不仅仅是一个id,而是一个id和一个距离,即整数和浮点数的元组,我该怎么办?)或者你会建议不要使用这样的发布列表,并采用扁平结构(例如密钥,在多次出现相同密钥的情况下发布)?
答案 0 :(得分:1)
我会使用一个列表。收集像IntegerType
这样的简单值列表会相当容易。像这样:
val df = Seq(
("a",1,1.1),("a",3,2.3),("a",4,1.0),("b",7,4.3),("b",12,11.11),("b",21,0.01)
).toDF("key","posting","distance")
val aggregatedDf1 = df.groupBy("key").agg(collect_list(col("posting")) as "postings")
在复杂的collect_list
上执行StructType
会更加困难,因为Hive聚合函数仅适用于简单类型。
要汇总StructType
,您需要创建UDAF
。 UDAF
API有点单调乏味,所以你可以稍微作弊,然后将列聚合成两个列表,然后使用简单的UDF
到zip
两个列表,如下所示:
val zipper = udf[Seq[Tuple2[Int,Double]],Seq[Int],Seq[Double]]((a,b) => a.zip(b))
val aggregatedDf2 = df.groupBy("key").agg(
collect_list(col("posting")) as "postings",
collect_list(col("distance")) as "distances"
).withColumn("postings", zipper($"postings", $"distances")).drop("distances")