我有一个带有"id"和"date"列的DataFrame
。 日期的格式为 yyyy-mm-dd 下面是一个示例:
+---------+----------+
| item_id| ds|
+---------+----------+
| 25867869|2018-05-01|
| 17190474|2018-01-02|
| 19870756|2018-01-02|
|172248680|2018-07-29|
| 41148162|2018-03-01|
+---------+----------+
我想创建一个新列,其中每个日期都与一个从 1 开始的整数相关联。 这样最小(最早(日期得到整数 1,下一个(第二个最早的日期(被分配给 2,依此类推。
我希望我的DataFrame
看起来像这样... :
+---------+----------+---------+
| item_id| ds| number|
+---------+----------+---------+
| 25867869|2018-05-01| 3|
| 17190474|2018-01-02| 1|
| 19870756|2018-01-02| 1|
|172248680|2018-07-29| 4|
| 41148162|2018-03-01| 2|
+---------+----------+---------+
解释:
2018 年 1 月 02 日日期最早,因此其数字为 1。 由于有 2 行具有相同的日期,因此 1 位于两次。 在 2018-01-02 之后,下一个日期是 2018-03-01,因此它的编号是 2,依此类推......如何创建这样的列?
这可以通过Window
函数中的dense_rank
来实现。
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
val win = Window.orderBy(to_date(col("ds"),"yyyy-MM-dd").asc)
val df1 = df.withColumn("number", dense_rank() over win)
df1
将根据需要number
列。
注意:to_date(col("ds"),"yyyy-MM-dd")
是强制性的,否则它将被视为字符串并且无法生存。
你应该创建一个函数来获取最旧的查询,没有这样的数字:
SELECT * FROM tablename WHERE number IS NULL ORDER BY ds ASC
然后进行另一个查询,获得最大的数字:
SELECT * FROM tablename ORDER BY number DESC
然后,如果两个查询具有相同的日期,则使用相同的数字更新表:
UPDATE tablename SET number = 'greatest number from first query' WHERE ds = 'the date from first query'
或者,如果日期不同,则相同,但在数字上加 1:
UPDATE tablename SET number= 'greatest number from first query' + 1 WHERE ds = 'the date from first query'
要完成这项工作,您应该首先将数字 1 断言到最旧的条目。 您应该在循环中执行此操作,直到第一个查询(检查是否有任何未设置的数字(为空。 第一个查询假设空列全部为 null,如果是另一种情况,则应更改 WHERE 条件以检查列何时为空。