在Spark中存储倒排索引

时间:2016-06-07 11:55:06

标签: apache-spark parquet

我正在使用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和一个距离,即整数和浮点数的元组,我该怎么办?)或者你会建议不要使用这样的发布列表,并采用扁平结构(例如密钥,在多次出现相同密钥的情况下发布)?

1 个答案:

答案 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,您需要创建UDAFUDAF API有点单调乏味,所以你可以稍微作弊,然后将列聚合成两个列表,然后使用简单的UDFzip两个列表,如下所示:

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")