我有两个spark数据帧,具有以下结构。在使用sqlContext之前阅读。
itens.columns (scala command)
Array[String] = Array(id_location,id_item, name, price)
rdd1
[1,1,item A,10]
[1,2,item b,12]
[1,3,item c,12]
rdd2
[1,2,item b,50]
[1,4,item c,12]
[1,5,item c,12]
我想要基于复合键(id_location,id_item)
的以下结果 [1,1,item A,10]
[1,2,item b,50]
[1,3,item c,12]
[1,4,item c,12]
[1,5,item c,12]
所以,我想要一个带有明显itens的结果(关于复合键),但是当我在两个rdd中找到一个具有相同键的记录时,我想要保留rdd2中的记录。
有人有这样的要求吗?
我正在使用spark和scala。
最诚挚的问候 拉斐尔。
答案 0 :(得分:0)
我对Spark很新,所以可能有更好的方法来实现这一点,但是你可能会映射到一对RDD(基于你的复合键),然后执行一个fullOuterJoin,只使用& #34;右"结果数据中的元素,其中" left"和"对"两侧?
粗伪代码:
val pairRdd1 = rdd1 map {
line =>
(line(0)+line(1), line)
}
val pairRdd2 = rdd2 map {
line =>
(line(0)+line(1), line)
}
val joined = pairRdd1.fullOuterJoin(pairRdd2)
joined map {
(id, left, right) =>
right.getOrElse(left.get)
}
如果我早上有时间,我会试着拼凑一个有效的例子。希望有所帮助!
答案 1 :(得分:0)
@Steven有正确的想法。您需要将数据集映射到键值对,然后执行outerjoin
val rdd1 = sc.parallelize(List((1,1,"item A",10),(1,2,"item b",12),(1,3,"item c",12)))
val rdd2 = sc.parallelize(List((1,2,"item b",50),(1,4,"item c",12),(1,5,"item c",12)))
val rdd1KV = rdd1.map{case(id_location,id_item, name, price) => ((id_location, id_item), (name, price))}
val rdd2KV = rdd2.map{case(id_location,id_item, name, price) => ((id_location, id_item), (name, price))}
val joined = rdd1KV.fullOuterJoin(rdd2KV)
val res = joined.map{case((id_location, id_item),(leftOption, rightOption)) =>
val values = rightOption.getOrElse(leftOption.get)
(id_location, id_item, values._1, values._2)
}
这将为您提供您正在寻找的结果。
答案 2 :(得分:0)
看起来@Steven的回答在逻辑上很好,但如果你的数据没有很多交叉元素,那么可能会遇到问题(即一个完整的外连接会产生一个巨大的数据集)。您还使用了DataFrame,因此转换为RDD然后返回DataFrames对于可以使用DataFrames API完成的任务来说似乎过多。我将在下面描述如何执行此操作。
让我们从一些示例数据开始(取自您的示例):
val rdd1 = sc.parallelize(Array((1,1,"item A",10), (1,2,"item b",12), (1,3,"item c",12)))
val rdd2 = sc.parallelize(Array((1,2,"item b",50), (1,4,"item c",12), (1,5,"item c",12)))
接下来,我们可以在单独的列别名下将它们转换为DataFrame。我们在df1
和df2
使用不同的别名,因为当我们最终加入这两个DataFrame时,后续的选择可以更容易编写(如果有一种方法可以在连接后识别列的来源,这是不必要的)。请注意,两个DataFrame的并集包含要过滤的行。
val df1 = rdd1.toDF("id_location", "id_item", "name", "price")
val df2 = rdd2.toDF("id_location_2", "id_item_2", "name_2", "price_2")
// df1.unionAll(df2).show()
// +-----------+-------+------+-----+
// |id_location|id_item| name|price|
// +-----------+-------+------+-----+
// | 1| 1|item A| 10|
// | 1| 2|item b| 12|
// | 1| 3|item c| 12|
// | 1| 2|item b| 50|
// | 1| 4|item c| 12|
// | 1| 5|item c| 12|
// +-----------+-------+------+-----+
在这里,我们首先加入关键字上的两个DataFrame,即df1
和df2
的前两个元素。然后,我们通过选择行(主要来自df1
)来创建另一个DataFrame,其中存在来自df2
的具有相同连接键的行。之后,我们在df1
上运行除以从之前创建的DataFrame中删除所有行。这可以看作是补充,因为我们基本上已经完成了删除df1
中("id_location", "id_item")
中df2
中存在相同df2
的所有行。最后,我们将补码与val df_joined = df1.join(df2, (df1("id_location") === df2("id_location_2")) && (df1("id_item") === df2("id_item_2")))
val df1_common_keyed = df_joined.select($"id_location", $"id_item", $"name", $"price")
val df1_complement = df1.except(df1_common_keyed)
val df_union = df1_complement.unionAll(df2)
// df_union.show()
// +-----------+-------+------+-----+
// |id_location|id_item| name|price|
// +-----------+-------+------+-----+
// | 1| 3|item c| 12|
// | 1| 1|item A| 10|
// | 1| 2|item b| 50|
// | 1| 4|item c| 12|
// | 1| 5|item c| 12|
// +-----------+-------+------+-----+
结合在一起以生成输出DataFrame。
subtractByKey()
再次,就像@Steven建议的那样,您可以通过将DataFrame转换为RDD并使用它来运行RDD API。如果这是你想要做的,以下是使用val keyed1 = rdd1.keyBy { case (id_location, id_item, _, _) => (id_location, id_item) }
val keyed2 = rdd2.keyBy { case (id_location, id_item, _, _) => (id_location, id_item) }
val unionRDD = keyed1.subtractByKey(keyed2).values.union(rdd2)
// unionRDD.collect().foreach(println)
// (1,1,item A,10)
// (1,3,item c,12)
// (1,2,item b,50)
// (1,4,item c,12)
// (1,5,item c,12)
和上面的输入RDD完成你想要的东西的另一种方式:
String username=edittext1.getText().toString();
if(username.matches("")) {
edittext1.setError("Invalid ");
}