小汽车摇号分析

Note

在所有的 Spark 计算子框架中,Spark SQL 是代码量最多、Spark 社区投入最大、应用范围最广、影响力最深远的那个。
就像之前以 Word Count 为例来学习 RDD 一样,我们使用小汽车摇号分析这个例子来学习 Spark SQL 。

SparkSession

from pyspark.sql import SparkSession

# Spark SQL 使用 SparkSession 作为入口
spark = (SparkSession
         .builder
         .appName("lottery")
         .config('spark.executor.memory', '6g')
         .config('spark.driver.memory', '12g')
         .config("spark.executor.cores", 4)
         .config('spark.cores.max', 8)
         .getOrCreate())

读取数据

# 申请者数据
applyNumbersDF = spark.read.parquet("../data/lottery/apply")
applyNumbersDF.show(10)
+-------------+--------+
|       carNum|batchNum|
+-------------+--------+
|1307103851262|  201906|
|3759104948944|  201906|
|1371101893066|  201906|
|3795100749475|  201906|
|1537105696290|  201906|
|3750108035493|  201906|
|1469104063180|  201906|
|3776101354768|  201906|
|1608103890895|  201906|
|3586100269069|  201906|
+-------------+--------+
only showing top 10 rows
# 中签者数据
luckyDogsDF = spark.read.parquet("../data/lottery/lucky")
luckyDogsDF.show(10)
+-------------+--------+
|       carNum|batchNum|
+-------------+--------+
|7923100191899|  201401|
|0570100126544|  201401|
|6780102763770|  201401|
|4512101029666|  201401|
|8302101265951|  201401|
|1235101372069|  201401|
|6296102696988|  201401|
|0905100893507|  201401|
|2697101120908|  201401|
|5417100109768|  201401|
+-------------+--------+
only showing top 10 rows

关联

import pyspark.sql.functions as F

# 过滤2016年之前的数据
filteredLuckyDogs = luckyDogsDF.filter(F.col("batchNum") >= "201601").select("carNum")

# 摇号数据与中签数据做内关联,仅统计中签者
jointDF = applyNumbersDF.join(filteredLuckyDogs, "carNum", "inner")

统计

# 以batchNum、carNum做分组,统计出现次数即倍率系数
multipliers = jointDF.groupBy(["batchNum", "carNum"]).agg(F.count("batchNum").alias("multiplier"))

# 以carNum做分组,保留最大的倍率系数
uniqueMultipliers = multipliers.groupBy("carNum").agg(F.max("multiplier").alias("multiplier"))
# 以multiplier倍率做分组,统计人数
result = uniqueMultipliers.groupBy("multiplier").agg(F.count("carNum").alias("cnt")).orderBy("multiplier")
result.show(10)
+----------+-----+
|multiplier|  cnt|
+----------+-----+
|         1| 8967|
|         2|19174|
|         3|26952|
|         4|29755|
|         5|32988|
|         6|34119|
|         7|29707|
|         8|26123|
|         9|19476|
|        10| 9616|
+----------+-----+
only showing top 10 rows