我有一个记录每个人姓名和地址的数据框,表示为
case class Person(name:String, addr:String)
数据框看起来像这样,
+----+-----+
|name| addr|
+----+-----+
| u1|addr1|
| u1|addr2|
| u2|addr1|
+----+-----+
但现在我需要为此数据框中的每个元素分配一个Long
类型唯一ID,可以表示为
case class PersonX(name:String, name_id:Long, addr:String, addr_id:Long)
和dataframe看起来像这样,
+----+-------+-----+------+
|name|name_id| addr|addr_id|
+----+-------+-----+------+
| u1| 1|addr1| 2|
| u1| 1|addr2| 3|
| u2| 4|addr1| 2|
+----+-------+-----+------+
请注意,两列中的元素(name
和addr
)共享相同的ID空间,这意味着name_id
不应该有重复项,并addr_id
也不应该,name_id
s& addr_id
不应相互重叠。
如何实现这一目标?
答案 0 :(得分:1)
分配id的最简单方法是使用spark sql中的dense_rank
函数。
为确保ID不会在名称和地址之间重叠,您可以制作一个技巧:
通过这种方式,地址ID将位于名称ID之后
val input = spark.sparkContext.parallelize(List(
Person("u1", "addr1"),
Person("u1", "addr2"),
Person("u2", "addr1")
)).toDF("name", "addr")
input.createOrReplaceTempView("people")
val people = spark.sql(
"""select name,
| dense_rank() over(partition by 1 order by name) as name_id,
| addr,
| dense_rank() over(partition by 1 order by addr) as addr_id
| from people
""".stripMargin)
people.show()
//+----+-------+-----+-------+
//|name|name_id| addr|addr_id|
//+----+-------+-----+-------+
//| u1| 1|addr1| 1|
//| u2| 2|addr1| 1|
//| u1| 1|addr2| 2|
//+----+-------+-----+-------+
val name = people.col("name")
val nameId = people.col("name_id")
val addr = people.col("addr")
val addrId = people.col("addr_id")
val maxNameId = people.select(max(nameId)).first().getInt(0)
val shiftedAddrId = (addrId + maxNameId).as("addr_id")
people.select(name, addr, nameId, shiftedAddrId).as[PersonX].show()
//+----+-----+-------+-------+
//|name| addr|name_id|addr_id|
//+----+-----+-------+-------+
//| u1|addr1| 1| 3|
//| u2|addr1| 2| 3|
//| u1|addr2| 1| 4|
//+----+-----+-------+-------+