【问题标题】:Spark SQL scenario not giving the correct resultsSpark SQL 场景没有给出正确的结果
【发布时间】:2021-12-21 08:46:18
【问题描述】:

我有一个如下的df:

  1. 手机号码是different

    |applicantkey|     first_reg_date|utmcontent| latest_signin_date|mobilenumber|
     +------------+-------------------+----------+-------------------+------------+
     |        1234|2021-01-03 06:05:43|   Android|2021-01-03 06:05:43|         987|
     |        1234|2021-04-03 07:05:43|   Android|2021-10-03 06:05:43|         986|
     +------------+-------------------+----------+-------------------+------------+
    
  2. 手机号码是same

    |applicantkey|     first_reg_date|utmcontent| latest_signin_date|mobilenumber|
     +------------+-------------------+----------+-------------------+------------+
     |        1234|2021-01-03 06:05:43|   Android|2021-01-03 06:05:43|         987|
     |        1234|2021-04-03 07:05:43|   Android|2021-10-03 06:05:43|         987|
     +------------+-------------------+----------+-------------------+------------+
    

现在,我想获取first_reg_dateminlatest_signin_datemax,并替换数据集中这两列的值。所以我的预期输出应该如下所示:

+------------+-------------------+----------+-------------------+------------+
|applicantkey|first_reg_date     |utmcontent|latest_signin_date |mobilenumber|
+------------+-------------------+----------+-------------------+------------+
|1234        |2021-01-03 06:05:43|Android   |2021-10-03 06:05:43|987         |
|1234        |2021-01-03 06:05:43|Android   |2021-10-03 06:05:43|986         |

+------------+-------------------+----------+-------------------+------------+  

我尝试了以下查询,但它给出的输出如下所示:

spark.sql(
    "select applicantkey,min(first_reg_date) first_reg_date,utmcontent,max(latest_signin_date) latest_signin_date,mobilenumber from df group by applicantkey,utmcontent,mobilenumber").show(truncate=False)

+------------+-------------------+----------+-------------------+------------+
|applicantkey|first_reg_date     |utmcontent|latest_signin_date |mobilenumber|
+------------+-------------------+----------+-------------------+------------+
|1234        |2021-01-03 06:05:43|Android   |2021-01-03 06:05:43|987         |
|1234        |2021-04-03 07:05:43|Android   |2021-10-03 06:05:43|986         |
+------------+-------------------+----------+-------------------+------------+  

AND

+------------+-------------------+----------+-------------------+------------+
|applicantkey|first_reg_date     |utmcontent|latest_signin_date |mobilenumber|
+------------+-------------------+----------+-------------------+------------+
|1234        |2021-01-03 06:05:43|Android   |2021-10-03 06:05:43|987         |
+------------+-------------------+----------+-------------------+------------+

第二个输出正确但第一个输出错误。

所以,我尝试了以下方法,它可以帮助我获得正确的结果,但是当手机号码相同时,我会得到重复:

df1 = spark.sql(
    "select applicantkey,min(first_reg_date) first_reg_date, max(latest_signin_date) latest_signin_date from df group by applicantkey")
df2 = spark.sql("select applicantkey,utmcontent,mobilenumber from df")
df3 = df1.join(df2, "applicantkey", "left_outer")
df3.show(truncate=False)  

+------------+-------------------+-------------------+----------+------------+
|applicantkey|first_reg_date     |latest_signin_date |utmcontent|mobilenumber|
+------------+-------------------+-------------------+----------+------------+
|1234        |2021-01-03 06:05:43|2021-10-03 06:05:43|Android   |987         |
|1234        |2021-01-03 06:05:43|2021-10-03 06:05:43|Android   |987         |
+------------+-------------------+-------------------+----------+------------+  

我不想在最后使用DISTINCT()。那么,我到底做错了什么?

【问题讨论】:

  • 您能否更好地重新表述问题,您想为每个申请人或每个申请人的手机号码组合找到min(first_reg_date)max(latest_signin_date) 吗?您可以应用firstlast 作为虚拟聚合来选择utmcontentmobilenumber,但这又取决于您到底想要什么。
  • 对于相同的applicantkey 记录,我想要min(first_reg_date)max(latest_signin_date),其余值应该按原样拾取。

标签: sql apache-spark pyspark apache-spark-sql


【解决方案1】:

根据您的评论,您希望根据 applicantkey 为数据框中的所有行选择 min(first_reg_date)max(latest_signin_date)。您可以通过window functions 执行此操作。 我们将通过applicantkey 对数据框进行分区,对于此分区中的每一行,我们将填充min(first_reg_date)max(latest_signin_date) 的值;我们将保持其他列不变。

最小工作示例

from datetime import datetime

from pyspark.sql.types import *
import pyspark.sql.functions as F
from pyspark.sql import Window

data = [(1234,datetime.strptime("2021-01-03 06:05:43", "%Y-%m-%d %H:%M:%S"),"Android",datetime.strptime("2021-01-03 06:05:43", "%Y-%m-%d %H:%M:%S"),987),
         (1234,datetime.strptime("2021-04-03 07:05:43", "%Y-%m-%d %H:%M:%S"),"Android",datetime.strptime("2021-10-03 06:05:43", "%Y-%m-%d %H:%M:%S"),986),
         (1234,datetime.strptime("2021-01-03 06:05:43", "%Y-%m-%d %H:%M:%S"),"Android",datetime.strptime("2021-01-03 06:05:43", "%Y-%m-%d %H:%M:%S"),987),
         (1234,datetime.strptime("2021-04-03 07:05:43", "%Y-%m-%d %H:%M:%S"),"Android",datetime.strptime("2021-01-03 06:05:43", "%Y-%m-%d %H:%M:%S"),987),
  ]

schema = StructType([
    StructField("applicantkey",IntegerType(),True),
    StructField("first_reg_date",TimestampType(),True),
    StructField("utmcontent",StringType(),True),
    StructField("latest_signin_date", TimestampType(), True),
    StructField("mobilenumber", IntegerType(), True),
  ])
 
df = spark.createDataFrame(data=data,schema=schema)

窗口逻辑

window_spec = Window.partitionBy("applicantkey")
df.withColumn("first_reg_date", F.min(F.col("first_reg_date")).over(window_spec)).withColumn("latest_signin_date", F.max(F.col("latest_signin_date")).over(window_spec)).show()

输出

+------------+-------------------+----------+-------------------+------------+
|applicantkey|     first_reg_date|utmcontent| latest_signin_date|mobilenumber|
+------------+-------------------+----------+-------------------+------------+
|        1234|2021-01-03 06:05:43|   Android|2021-10-03 06:05:43|         987|
|        1234|2021-01-03 06:05:43|   Android|2021-10-03 06:05:43|         986|
|        1234|2021-01-03 06:05:43|   Android|2021-10-03 06:05:43|         987|
|        1234|2021-01-03 06:05:43|   Android|2021-10-03 06:05:43|         987|
+------------+-------------------+----------+-------------------+------------+

PS。将来在提问时,请务必包含一个最低限度的工作示例。

【讨论】:

  • 嘿,谢谢@snithish 的帮助。但是,你能再读一遍我的问题吗?在我的问题中,我已经提到了我的期望,并通过使用我的 sn-p 我得到了什么。我仍然不确定“最低限度的工作示例”到底是什么意思。我已经提到了 2 种不同的方法,它们对我有用,但不是我正在寻找的方式。另外,使用您的解决方案我将无法解决我的问题的最后一部分,即avoiding distinct()
  • 另外,您的代码不达标。这将导致重复的列。
  • @whatsinthename 我了解您正在尝试应用聚合并且还希望包含非聚合列的值。但是,您没有说如何解决歧义。例如,当您在查看mobilenumber 列时找到min(first_reg_date)max(latest_signin_date) 后,您有两个可能的选项(986、987),您想要哪一个,为什么?
  • @whatsinthename 你还期望utmcontent 列中有两个唯一值,例如androidios
猜你喜欢
  • 1970-01-01
  • 2019-07-07
  • 1970-01-01
  • 1970-01-01
  • 2014-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多