SparkSQL的API调用(影评案例)

本文详细介绍了如何使用Python和PySpark在Hadoop和Spark集群环境中准备数据、读取CSV文件、创建DataFrame,以及进行数据统计,包括用户评分平均分、电影平均分、筛选高分电影等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

语言:python

工具:PyCharm、Hadoop集群、spark集群

1.准备数据

        下载数据

                下载地址,下载u.data,下载后可以用记事本打开查看里面内容(10w条记录)。

 

 记事本内没有标出每一列的含义,可以参考下图。


        上传数据

                将下载好的u.data上传到Linux主机/data目录下

        


2.编写python文件

        导入模块

  • SparkSession是PySpark中的一个主要入口点,用于创建和管理Spark应用程序的上下文。
  • functions模块是PySpark中的一个子模块,提供了许多用于数据处理和转换的函数,例如聚合、过滤、排序等。
  • StructType是PySpark中用于定义结构化数据模式的类,用于指定DataFrame中的列名和数据类型。
  • StringType是PySpark中的一种数据类型,表示字符串类型的数据。
  • IntegerType是PySpark中的一种数据类型,表示整数类型的数据。
from pyspark.sql import SparkSession,functions
from pyspark.sql.types import StructType, StringType,IntegerType

         创建SparkSession对象

  • SparkSession.builder: 是用于构建SparkSession对象的构建器。
  • appName('test'): 是设置Spark应用程序的名称,可以根据需要进行更改。
  • master("local[*]"): 是设置Spark应用程序的主节点地址。在这里,"local[*]"表示在本地运行Spark应用程序,使用所有可用的CPU核心。
  • getOrCreate(): 是获取或创建SparkSession对象的方法。如果已经存在一个SparkSession对象,则返回该对象;否则,将创建一个新的SparkSession对象。
spark = SparkSession.builder.appName('test'). master("local[*]"). getOrCreate()

        创建SparkContext对象

  • SparkContext是Spark的主要入口点,用于与集群通信并创建RDD(弹性分布式数据集)。通过SparkContext,可以执行各种Spark操作,如读取数据、转换数据和执行操作。
sc = spark.sparkContext

         定义Spark DataFrame中的schema

  • StructType():创建一个空的结构类型,用于存储字段信息。
  • add("user_id", StringType(), nullable=True):向结构类型中添加一个名为"user_id"的字段,字段类型为StringType(),可为空。
  • add("movie_id", IntegerType(), nullable=True):向结构类型中添加一个名为"movie_id"的字段,字段类型为IntegerType(),可为空。
  • add("rank", IntegerType(), nullable=True):向结构类型中添加一个名为"rank"的字段,字段类型为IntegerType(),可为空。
  • add("marktime", StringType(), nullable=True):向结构类型中添加一个名为"marktime"的字段,字段类型为StringType(),可为空。
schema = StructType().add("user_id", StringType(), nullable=True).add("movie_id", IntegerType(), nullable=True).add("rank", IntegerType(), nullable=True).add("marktime", StringType(), nullable=True)

        读取数据文件

  • spark.read.format('csv'):使用Spark的CSV数据源读取数据。
  • .option("sep", "\t"):设置分隔符为制表符("\t")。
  • .option("header", False):设置文件中没有标题行。
  • .option("encoding", "utf-8"):设置文件编码为UTF-8。
  • .schema(schema=schema):指定数据的模式(schema),其中schema是预先定义好的模式。
  • .load("file:///data/u.data"):加载指定路径下的文件。
df = spark.read.format('csv').option("sep", "\t"). option("header", False).option("encoding", "utf-8").schema(schema=schema).load("file:///data/u.data")

         测试

目前完整代码如下,只是为了测试能否读取u.data文件

import findspark
findspark.init()

from pyspark.sql import SparkSession,functions
from pyspark.sql.types import StructType, StringType,IntegerType

if __name__=='__main__':
    spark = SparkSession.builder.appName('test'). master("local[*]"). getOrCreate()
    sc = spark.sparkContext
    schema = StructType().add("user_id", StringType(), nullable=True).add("movie_id", IntegerType(), nullable=True).add("rank", IntegerType(), nullable=True).add("marktime", StringType(), nullable=True)

df = spark.read.format('csv').option("sep", "\t"). option("header", False).option("encoding", "utf-8").schema(schema=schema).load("file:///data/u.data")
df.show()


3.数据统计

        一、求同一用户打过所有分的平均分

  • groupby("user_id"):根据"userid"列对DataFrame进行分组
  • avg("rank"):计算每个组中"rank"列的平均值
  • withColumnRenamed("avg(rank)","avg_rank"):将计算结果的列名从"avg(rank)"改为"avg_rank"
  • withColumn("avg_rank",functions.round("avg_rank",2)) :将"avg_rank"列的值保留两位小数
  • orderBy("avg_rank",ascending=False):按照"avg_rank"列的值降序排序
  • show():打印结果
df.groupby("user_id").avg("rank").withColumnRenamed("avg(rank)","avg_rank").withColumn("avg_rank",functions.round("avg_rank",2)).orderBy("avg_rank",ascending=False).show()

运行结果(部分):

 


         二、求电影的平均分

  • df.createTempView("movie"):它创建了一个名为"movie"的临时视图,该视图可以用于查询。
  • spark.sql("""XXX......""):表示执行SQL查询语句
  • round(avg(rank),2) as avg_rank:将平均数rank保留2位小数,同时更名为avg_rank
  • SQL语句:从movie中查询movie_id和avg_rank,并按movie_id分组,按avg_rank的值降序排序
df.createTempView("movie")
spark.sql("""select movie_id,round(avg(rank),2) as avg_rank from movie group by movie_id order by avg_rank desc""").show()

运行结果(部分):


        三、查询大于平均分的电影的数量

  •  df是一个 DataFrame 对象
  • where(): 用于筛选出 满足条件的行
  • df["rank"] > df.select(functions.avg("rank")).first()["avg(rank)"]:即 rank列的值大于 rank列的平均值。
  • df.select(functions.avg("rank")).first()["avg(rank)"]:select方法类似SQL的查询,使用functions.avg()函数计算 rank列的平均值。first()["avg(rank)"]方法:select查询后返回一行数据,需要访问第一行数据,并访问该行数据中 avg(rank)列的值。
  • count():计算满足条件的行数,并将结果打印出来。
print(df.where(df["rank"]>df.select(functions.avg("rank")).first()["avg(rank)"]).count())

运行结果:


        四、查询在电影评分>3的电影中,打分次数最多的用户,其打分的平均分

        第一行代码:   

  • df.where("rank > 3"):选择rank大于3的记录
  • groupBy("user_id").count():按照用户ID进行分组计数
  • withColumnRenamed('count','cnt'):将计数结果的列名改为cnt
  • orderBy("cnt",ascending=False):按照计数结果降序排序
  • limit(1).first()["user_id"]:取出计数最多的用户ID

        第二行代码:

  • df.filter(df["user_id"]==user_id):筛选出user_id等于user_id值的行
  • select(functions.round(functions.avg("rank"),2)):计算这些行中rank列的平均值,并将结果保留两位小数

user_id=df.where("rank > 3").groupBy("user_id").count().withColumnRenamed('count','cnt').orderBy("cnt",ascending=False).limit(1).first()["user_id"]
df.filter(df["user_id"]==user_id).select(functions.round(functions.avg("rank"),2)).show()

 运行结果:


         五、查询每个用户的平均打分,最低打分,最高打分

  • df.groupby("user_id"): 据user_id列对进行分组
  • agg():对分组后的数据进行聚合操作,可以对每个分组进行多个聚合操作,例如计算平均值、最小值、最大值等。
  • functions.round(functions.avg("rank"),2).alias("avg_rank"):求平均分,保留2位小数,并指定名字为avg_rank
  •  functions.min("rank").alias("min_rank"):求最低分,并指定名字为min_rank
  • functions.max("rank").alias("max_rank"):求最高分,并指定名字为max_rank
df.groupby("user_id").agg(functions.round(functions.avg("rank"),2).alias("avg_rank"),functions.min("rank").alias("min_rank"),functions.max("rank").alias("max_rank")).show()

运行结果(部分):


 六、查询评分超过100次的电影的平均分、排名、Top10

  •  df.groupby("movie_id"):根据movie_id经行分组
  • agg():对分组后的数据进行聚合操作,可以对每个分组进行多个聚合操作,例如计算平均值、最小值、最大值等。
  • functions.count("movie_id").alias("cnt"):统计相同movie_id的数量,命名为cnt
  • functions.round(functions.avg("rank"),2).alias("avg_rank"):求平均分,保留2位小数,并指定名字为avg_rank
  • where("cnt>100"):筛选出评分超过100次的电影
  • orderBy("avg_rank",ascending=False):根据avg_rank降序排序
  • imit(10).show():只显示前10个数据
df.groupby("movie_id").agg(functions.count("movie_id").alias("cnt"),functions.round(functions.avg("rank"),2).alias("avg_rank")).where("cnt>100").orderBy("avg_rank",ascending=False).limit(10).show()

运行结果:


4.完整代码

import findspark
findspark.init()

from pyspark.sql import SparkSession,functions
from pyspark.sql.types import StructType, StringType,IntegerType


if __name__=='__main__':
    spark = SparkSession.builder.appName('test'). master("local[*]"). getOrCreate()
    sc = spark.sparkContext
    schema = StructType().add("user_id", StringType(), nullable=True).add("movie_id", IntegerType(), nullable=True).add("rank", IntegerType(), nullable=True).add("marktime", StringType(), nullable=True)

df = spark.read.format('csv').option("sep", "\t"). option("header", False).option("encoding", "utf-8").schema(schema=schema).load("file:///data/u.data")
#文件读取测试
#df.show()

#求同一用户打过所有分的平均分
#df.groupby("user_id").avg("rank").withColumnRenamed("avg(rank)","avg_rank").withColumn("avg_rank",functions.round("avg_rank",2)).orderBy("avg_rank",ascending=False).show()

#求电影的平均分
#df.createTempView("movie")
#spark.sql("""select movie_id,round(avg(rank),2) as avg_rank from movie group by movie_id order by avg_rank desc""").show()

#查询大于平均分的电影的数量
#print(df.where(df["rank"]>df.select(functions.avg("rank")).first()["avg(rank)"]).count())

#查询在电影评分>3的电影中,打分次数最多的用户,其打分的平均分
#user_id=df.where("rank > 3").groupBy("user_id").count().withColumnRenamed('count','cnt').orderBy("cnt",ascending=False).limit(1).first()["user_id"]
#df.filter(df["user_id"]==user_id).select(functions.round(functions.avg("rank"),2)).show()

#查询每个用户的平均打分,最低打分,最高打分
#df.groupby("user_id").agg(functions.round(functions.avg("rank"),2).alias("avg_rank"),functions.min("rank").alias("min_rank"),functions.max("rank").alias("max_rank")).show()

#查询评分超过100次的电影的平均分、排名、Top10
#df.groupby("movie_id").agg(functions.count("movie_id").alias("cnt"),functions.round(functions.avg("rank"),2).alias("avg_rank")).where("cnt>100").orderBy("avg_rank",ascending=False).limit(10).show()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值