我有两个数据集并创建两个案例类(我之所以不将ds连接在一起是因为我想在ds B中使用ds A中的键返回第一个匹配记录)
以下是我到目前为止的尝试。如何将该功能映射到两个案例类?非常感谢!我在这里很新。
case class a_class (idA: Int, numA: Int)
case class b_class(idB: Int, numB:Int )
def findNum(a:a_Class, b:b_class): Int = {
if (a.idA =!=b.idB){
break
}else{
return b.numB
}
}
aTb.createOrReplaceTempView("tableA")
bTb.createOrReplaceTempView("tableB")
var aDS = sqlContext.table("tableA").as[a_class]
var bDS = sqlContext.table("pview").as[b_class]
//a_class.map(, => )).show //how do I use findNum function here?
示例输入:
+------+---+
|idA |numA|
+------+---+
| a |100|
| b |200|
+------+---+
+------+---+
|idB |numB|
+------+---+
|a |500|
|a |600|
+------+---+
因此预期输出为500,因为第一行是表B中的第一个匹配记录
答案 0 :(得分:2)
您的解决方案位于join
,groupBy
和aggregation
首先,您的case class
和示例输入数据不匹配,因为a
和b
不能是int
类型。所以case classes
应该是
case class a_class (idA: String, numA: Int)
case class b_class(idB: String, numB:Int )
使用这些case classes
,您可以创建dataSets
。出于测试目的,我创建如下
import sqlContext.implicits._
import org.apache.spark.sql.functions._
val tableA = Seq(
a_class("a", 100),
a_class("b", 200)
).toDS
val tableB = Seq(
b_class("a", 500),
b_class("a", 600)
).toDS
然后使用以下方法可以实现最终的dataset
。
tableA.join(tableB, $"idA" === $"idB", "inner") // inner join of two datasets
.drop("idA", "numA") //droping columns of tableB
.groupBy("idB") //grouping data to get the first of each group
.agg(first("numB").as("numB")) //taking the first of each group
.show(false)
应该给你
+---+----+
|idB|numB|
+---+----+
|a |600 |
+---+----+
<强>更新强>
以上结果与您想要的输出不符,这是因为join
重新排序tableB
。
只需执行
即可获得所需的输出tableB.groupBy("idB")
.agg(first("numB").as("numB"))
.show(false)
结果将是row
id
的每个tableB
的第一个+---+----+
|idB|numB|
+---+----+
|a |500 |
+---+----+
rows
如果您只希望第一个id
与tableA
匹配join
,那么您tableA
与tableA
同上,如果您不想要drop
的数据,然后您val tempTableB = tableB.groupBy("idB")
.agg(first("numB").as("numB"))
tableA.join(tempTableB, $"idA" === $"idB", "inner")
.drop("idA", "numA")
.show(false)
将其作为
row
tableB
的{{1}}的第一个id
与tableA
的{{1}}匹配
+---+----+
|idB|numB|
+---+----+
|a |500 |
+---+----+