python/pyspark-correct方法链接顺序规则

noj0wjuj  于 2021-05-27  发布在  Spark
关注(0)|答案(1)|浏览(289)

来自sql开发背景,目前正在学习pyspark/python,我对使用python查询数据/链接方法有点困惑。
例如下面的查询(摘自“learning spark第二版”):

fire_ts_df.               
 select("CallType")
 .where(col("CallType").isNotNull())
 .groupBy("CallType")
 .count()
 .orderBy("count", ascending=False)
 .show(n=10, truncate=False)

执行得很好。
但我不明白的是,如果我编写了如下代码:(将调用移到'count()'更高)

fire_ts_df.               
 select("CallType")
 .count()
 .where(col("CallType").isNotNull())
 .groupBy("CallType")
 .orderBy("count", ascending=False)
 .show(n=10, truncate=False)

这行不通。问题是我不想记住顺序,但我想理解它。我觉得这与python/pyspark中正确的方法链接有关,但我不知道如何证明这一点。换句话说,在这样的情况下,应该使用(.)调用和链接多个方法,正确的顺序是什么,有什么特定的规则要遵循吗?
提前多谢了

3hvapo4f

3hvapo4f1#

这里需要注意的重要一点是链式方法不一定以随机顺序出现。这些方法调用所表示的操作不是从左到右直接应用于数据的一些关联转换。
每个方法调用都可以编写为一个单独的语句,其中每个语句生成一个结果,该结果将输入到下一个操作,依此类推,直到生成结果为止。

fire_ts_df.                           
  select("CallType")                  # selects column CallType into a 1-col DF
 .where(col("CallType").isNotNull())  # Filters rows on the 1-column DF from select()
 .groupBy("CallType")                 # Group filtered DF by the one column into a pyspark.sql.group.GroupedData object
 .count()                             # Creates a new DF off the GroupedData with counts
 .orderBy("count", ascending=False)   # Sorts the aggregated DF, as a new DF
 .show(n=10, truncate=False)          # Prints the  last DF

只是用你的例子来解释为什么这不起作用,打电话给 count()pyspark.sql.group.GroupedData 创建包含聚合结果的新Dataframe。但是 count() 拜访了一位 DataFrame 对象只返回记录数,这意味着下面的调用, .where(col("CallType").isNotNull()) ,是长的,这根本没有意义。long没有那种过滤方法。
如上所述,您可以通过在单独的语句中重写代码来实现不同的可视化:

call_type_df = fire_ts_df.select("CallType")
non_null_call_type = call_type_df.where(col("CallType").isNotNull())
groupings = non_null_call_type.groupBy("CallType")
counts_by_call_type_df = groupings.count()
ordered_counts = counts_by_call_type_df.orderBy("count", ascending=False)

ordered_counts.show(n=10, truncate=False)

如您所见,排序是有意义的,因为操作的连续性与它们各自的输出是一致的。
链式调用产生了所谓的fluent api,可以最大限度地减少冗长性。但这并不能消除这样一个事实:链式方法必须适用于前一个调用的输出类型(事实上,下一个操作将应用于前一个调用生成的值)。

相关问题