spark数据处理练习题番外篇【上】

一. 单选题(共23题,100分)

1. (单选题)maven依赖应该加在哪个文件中?

  • A. pom.xml
  • B. log4j.properties
  • C. src/main/scala.resource
  • D. src/test/scala.resource

正确答案: A:pom.xml;

Maven 依赖应该添加在 pom.xml 文件中,这是 Maven 项目的核心配置文件。

解释:

  • pom.xml (Project Object Model) 文件定义了项目的所有配置信息,包括项目依赖、插件、构建设置等
  • 依赖通常在 <dependencies> 标签内定义,每个依赖使用 <dependency> 标签,包含 groupId、artifactId 和 version 等信息
  • 其他选项的用途:
    • log4j.properties:日志配置文件
    • src/main/scala.resource:资源文件目录,不是配置依赖的地方
    • src/test/scala.resource:测试资源文件目录,同样不是配置依赖的地方

Maven 通过 pom.xml 文件管理项目的整个生命周期,包括依赖管理、构建过程和部署等。

2. (单选题)

1 val conf=new SparkConf()

2 .setMaster("local")

3 .setAppName("test")

4 var sc=new SparkContext(conf)

5 var data=sc.textFile("f:/00ppt/spark1/abc.txt")

如果要打包发布到spark集群里运行需要改哪些行,选出行号

  • A. 2 3 4 5
  • B. 2 5
  • C. 3 5
  • D. 2 4

正确答案: B:2 5;

解释:

当将Spark应用程序从本地开发环境打包发布到Spark集群运行时,需要修改以下行:

  1. 第2行:.setMaster("local") 需要修改或删除

    • 在本地开发环境中,使用"local"表示在本地运行Spark
    • 在集群环境中,应该删除这一行,让集群管理器(如YARN、Mesos或Spark Standalone)决定master
    • 或者可以将其修改为集群地址,但通常在提交时通过spark-submit命令指定更灵活
  2. 第5行:var data=sc.textFile("f:/00ppt/spark1/abc.txt") 需要修改

    • 本地文件路径"f:/00ppt/spark1/abc.txt"是Windows格式的本地路径
    • 在集群环境中,应该使用分布式文件系统路径,如HDFS路径:"hdfs://namenode:8020/path/to/file"
    • 或者使用集群可访问的共享存储路径

不需要修改的行:

  • 第3行:.setAppName("test") 应用名称可以保持不变
  • 第4行:var sc=new SparkContext(conf) SparkContext创建方式不需要改变

3. (单选题)

var lst1=List("zs"->170,"ls"->175)

var rdd1=sc.parallelize(lst1)

rdd1.sortByKey().foreach(println(_))

输出结果是

  • A. (ls,175)

    (zs,170)

  • B. (ls)

    (zs)

  • C. (170)

    (175)

  • D. (zs,170)

    (ls,175)

正确答案: A:(ls,175) (zs,170) ;

解释:

让我们分析代码的执行过程:

  1. 首先创建了一个包含元组的List:

    List("zs"->170, "ls"->175)

    这里的 -> 操作符创建了两个二元组:("zs",170) 和 ("ls",175)

  2. 将List转换为RDD:

    var rdd1 = sc.parallelize(lst1)

  3. 使用sortByKey()对RDD进行排序:

    rdd1.sortByKey()

    • sortByKey() 默认按照key进行升序排序
    • 这里的key是字符串("zs"和"ls")
    • 字符串按字典顺序排序,"ls"在字母表中排在"zs"前面
  4. 最后foreach打印每个元素:

    foreach(println(_))

其他选项都是错误的:

  • B只输出了key
  • C只输出了value
  • D没有经过排序

4. (单选题)

var lst1=List("zs"->170,"ls"->175)

sc.parallelize(lst1).sortBy(_____).foreach(println())

输出结果是

(zs,170)

(ls,175)

请填空

  • A. x=>x
  • B. _._2
  • C. _._1
  • D. x=>x.split("->")[1]

正确答案: B:_._2;

解释:

在这种情况下,sortBy 根据的是元组的 第二个元素(value) 来进行排序。具体来说:

  • lst1 是一个包含元组的列表:("zs" -> 170, "ls" -> 175),其中 "zs""ls" 是键(key),170175 是值(value)。
  • 使用 sortBy(_._2) 时,表示按照元组的第二个元素(即身高,170175)进行排序。

为什么不是其他选项:

  • A. x => x:这会按整个元组的顺序排序,不是按键或值,因此不符合要求。
  • C. _._1 :这表示按元组的第一个元素(即key)排序,结果会是按字母顺序排序,输出会是:
    (ls, 175) (zs, 170) 这和题目要求的输出不符。
  • D. x => x.split("->")[1] :这是不正确的,因为 x 是元组,而不是字符串,所以不能使用 split

5. (单选题)

哪种分区可能造成数据倾斜?1 Hash分区 2 Range分区 3 自定义分区

  • A. 仅1
  • B. 1,2,3
  • C. 仅1 ,2
  • D. 2,3

正确答案: B:1,2,3;

解释:

所有三种分区方式 (Hash分区、Range分区、自定义分区) 都可能导致数据倾斜,下面逐一说明:

  1. Hash分区: Hash分区是根据某个键的哈希值来决定数据分配的分区。数据倾斜可能发生的原因是:
  • 如果某些键的分布不均匀,某些分区可能会得到非常多的数据,而其他分区则相对较少。
  • 例如,如果某些键的出现频率很高,所有具有这些高频键的数据就会被分配到少数几个分区,造成负载不均衡。
  1. Range分区: Range分区按数据的范围将数据分配到不同的分区。数据倾斜发生的原因是:
  • 如果数据在某些范围内非常集中,可能会导致某个分区的负载远大于其他分区。
  • 比如,某个数值区间(如[1000, 2000])可能包含大量的数据,而其他区间则相对空闲,造成负载不均。
  1. 自定义分区: 自定义分区由用户定义分区规则,因此,如果用户设计的分区策略不合理,也可能导致数据倾斜。
  • 例如,如果按照某些不均匀分布的字段进行分区(如按用户ID分区,而ID分布不均),某些分区可能包含大量数据,而其他分区几乎没有数据。

6. (单选题)

var a1=Array(1,2,3,9,8,7,4,6,5)

var range1=sc.parallelize(List(______________)).map((_,1))

var rdd1=sc.parallelize(a1)

rdd1.map((_,1)).partitionBy(new RangePartitioner(3,range1))

选择合适的内容填空使数据尽量不倾斜

  • A. 1,3,6
  • B. 1,9,4
  • C. 2,8,6
  • D. 3,6,9

正确答案: D:3,6,9;

解释:

这个问题涉及到使用 RangePartitioner 进行数据分区,目标是避免数据倾斜。让我们分析一下代码和各个选项:

var a1 = Array(1, 2, 3, 9, 8, 7, 4, 6, 5) var range1 = sc.parallelize(List(______________)).map((_, 1)) var rdd1 = sc.parallelize(a1) rdd1.map((_, 1)).partitionBy(new RangePartitioner(3, range1))

在这段代码中:

  1. 我们有一个数组 a1,包含 9 个元素:1, 2, 3, 9, 8, 7, 4, 6, 5
  2. 需要创建一个 RDD range1,其中包含一些关键的分区边界值
  3. 然后使用 RangePartitionerrdd1 分成 3 个分区

RangePartitioner 的工作原理

  • RangePartitioner 会根据提供的样本数据(这里是 range1)确定分区边界
  • 它会尝试将数据均匀地分布在各个分区中

为了避免数据倾斜,我们需要选择能够将原始数据 a1 均匀分配到 3 个分区的边界值。

分析选项 D: 3,6,9

  • 如果选择 3, 6, 9 作为边界值,RangePartitioner 会创建以下分区:
    • 分区 1: 小于或等于 3 的值 ------ 包含 1, 2, 3(共 3 个元素)
    • 分区 2: 大于 3 且小于或等于 6 的值 ------ 包含 4, 5, 6(共 3 个元素)
    • 分区 3: 大于 6 的值 ------ 包含 7, 8, 9(共 3 个元素)

这样,9 个元素被均匀地分配到 3 个分区中,每个分区包含 3 个元素,实现了最佳的负载均衡,避免了数据倾斜。

其他选项的问题

  • 选项 A (1,3,6): 分区 1 包含 1 个元素,分区 2 包含 2 个元素,分区 3 包含 6 个元素,不均衡
  • 选项 B (1,9,4): 这些值不是有序的,不适合作为 RangePartitioner 的边界值
  • 选项 C (2,8,6): 这些值也不是有序的,不适合作为边界值

7. (单选题)

自定义分区类的设计,按key的首字母分区,a-g在0区,h-n在1区,o-t在2区,u-z在3区,请填空

class MyPartitioner1(n:Int) extends Partitioner{

override def numPartitions: Int = __________

override def getPartition(key: Any): Int = {

var ch=key._______________

if(ch<='n')

if(ch<='g') 0

else 1

else

if(ch<='t') 2

else 3

}

}

  • A. n _.1

  • B. n _.2

  • C. n toString().charAt(0)

  • D. 4 element(0)

正确答案: C:n toString().charAt(0);

需求分析:

  1. 这是一个自定义分区器,根据key的首字母将数据分成4个区:

    • a-g: 区0
    • h-n: 区1
    • o-t: 区2
    • u-z: 区3
  2. 需要填写两个空:

    • 第一个空:需要返回分区数
    • 第二个空:需要获取key的首字母

解答分析:

  1. 第一个空 numPartitions

    • 根据分区逻辑,总共有4个分区(0,1,2,3)
    • 虽然构造函数接收参数n,但这里实际分区数是固定的4个
    • 应填 n(保持构造函数参数的一致性)
  2. 第二个空 getPartition 方法中的代码

    • 需要获取key的首字母
    • key是Any类型,需要先转换为字符串
    • 然后获取第一个字符
    • 应填 toString().charAt(0)

选项分析:

A. n, _.1

  • _.1 语法不正确,无法获取字符串首字母

B. n, _.2

  • _.2 语法不正确,无法获取字符串首字母

C. n, toString().charAt(0)

  • n 正确,表示分区数
  • toString().charAt(0) 正确,可以获取任意key的首字母

D. 4, element(0)

  • 4 虽然是实际分区数,但不符合构造函数参数设计
  • element(0) 语法不正确

8. (单选题)

spark-core中计算中采用了惰性求值方案,其中行动操作有()

1 count() 2 collect() 3 take() 4 first() 5 foreach()

  • A. 1,2,3,4,5
  • B. 1,2,4
  • C. 1,3,5
  • D. 2,3,4,5

正确答案: A:1,2,3,4,5;

解释:

在Spark中,操作可以分为两类:

  1. 转换操作(Transformations):惰性操作,不会立即执行
  2. 行动操作(Actions):触发实际计算的操作

让我们分析每个选项中的操作:

  1. count()

    • 是行动操作
    • 返回RDD中元素的数量
    • 会触发实际计算
  2. collect()

    • 是行动操作
    • 将RDD中的所有元素收集到驱动程序中
    • 会触发实际计算
  3. take()

    • 是行动操作
    • 返回RDD中的前n个元素
    • 会触发实际计算
  4. first()

    • 是行动操作
    • 返回RDD中的第一个元素
    • 相当于take(1)
    • 会触发实际计算
  5. foreach()

    • 是行动操作
    • 对RDD中的每个元素执行指定操作
    • 会触发实际计算

其他常见的行动操作:

  • reduce()
  • aggregate()
  • fold()
  • saveAsTextFile()
  • countByKey()
  • foreach()

转换操作(Transformations)示例:

  • map()
  • filter()
  • flatMap()
  • groupBy()
  • union()
  • intersection()

行动操作的特点:

  1. 会触发实际的计算
  2. 会返回结果给驱动程序
  3. 导致之前的所有转换操作被执行

惰性求值的好处:

  1. 优化执行计划
  2. 减少不必要的计算
  3. 提高效率

9. (单选题)

关于spark-core说法正确的有()

1 当需要对RDD进行reduceByKey和filter,应该先filter

2 当需要对RDD按key值聚合运算,可以用reduceByKey也可以用groupByKey

3 选项2中,用reduceByKey效率更高

4 可以通过持久化(缓存)机制避免重复计算的开销

  • A. 1,2,3,4
  • B. 1,2,3
  • C. 2,3,4
  • D. 1,3,4

正确答案: A:1,2,3,4;

让我们逐条分析这些说法:

  1. "当需要对RDD进行reduceByKey和filter,应该先filter" - ✓正确

    • 原因:
      • filter操作会减少数据量
      • 先执行filter可以减少后续reduceByKey处理的数据量
      • 这符合Spark的优化原则:尽早减少数据量
  2. "当需要对RDD按key值聚合运算,可以用reduceByKey也可以用groupByKey" - ✓正确

    • 两者都可以实现按key聚合
    • reduceByKey: 在map端先进行combine,再进行reduce
    • groupByKey: 直接在reduce端进行分组
  3. "用reduceByKey效率更高" - ✓正确

    • 原因:
      • reduceByKey在map端有预聚合(combine)操作
      • 减少了网络传输的数据量
      • 而groupByKey需要传输所有数据到reduce端
  4. "可以通过持久化(缓存)机制避免重复计算的开销" - ✓正确

    • 通过cache()或persist()方法实现
    • 可以将RDD存储在内存或磁盘中
    • 避免多次计算同一个RDD
    • 特别适用于迭代计算场景

10. (单选题)

JSON 语法规则正确的是()

1 数据在key-value对中 2 数据由逗号分隔 3 大括号 {} 保存对象4 中括号 [] 保存数组,数组可以包含多个对象

  • A. 1,2,3
  • B. 1,2,3,4
  • C. 2,3,4
  • D. 1,3

正确答案: B:1,2,3,4;

让我们详细分析 JSON 的语法规则:

  1. 数据在 key-value 对中 ✓
  • 格式:"key": value
  • 示例:

{ "name": "John", "age": 25 }

  1. 数据由逗号分隔 ✓
  • 多个 key-value 对之间使用逗号分隔
  • 数组元素之间使用逗号分隔
  • 示例:

{ "name": "John", "age": 25, "city": "New York" }

  1. 大括号 {} 保存对象 ✓
  • 对象以 { 开始,以 } 结束
  • 示例:

{ "person": { "name": "John", "age": 25 } }

  1. 中括号 [] 保存数组,数组可以包含多个对象 ✓
  • 数组以 [ 开始,以 ] 结束
  • 示例:

{ "people": [ { "name": "John", "age": 25 }, { "name": "Mary", "age": 30 } ] }

11. (单选题)

val rdd1=spark.sparkContext.parallelize(

List(Person0("tom",21),Person0("zs",19),Person0("ls",20)) )

val df1=rdd1.toDF()

df1._______________________("person0")

val res1=spark.sql( "select * from person0 where age>20")

res1.show()

}

case class ________(name:String,age:Int)

  • A. createSQLTable Person0
  • B. querySQLString Person1
  • C. createSQLTable Person
  • D. createOrReplaceTempView Person0

正确答案: D:createOrReplaceTempView Person0;

为什么 createOrReplaceTempView 是正确的?

  • createOrReplaceTempView 用来将一个 DataFrame 注册为一个临时视图或表,允许我们在 SQL 查询中使用它。
  • 这个临时视图只会在当前 Spark 会话中有效。

选项分析:

  • A: createSQLTable Person0 :这个方法不存在,Spark没有提供名为 createSQLTable 的方法。
  • B: querySQLString Person1 :同样,querySQLString 不是 Spark 的有效方法。
  • C: createSQLTable Person :同样,createSQLTable 并不是一个有效的方法。
  • D: createOrReplaceTempView Person0 :正确,createOrReplaceTempView 是 Spark 中注册临时视图的方法。
相关推荐
bxlj_jcj6 分钟前
解锁Flink CDC:实时数据同步秘籍
大数据·flink
悢七10 分钟前
flink1.19.2+cdc-3.2.1遇到的问题及解决方案
大数据·flink
保持学习ing43 分钟前
SpringBoot前后台交互 -- 登录功能实现(拦截器+异常捕获器)
java·spring boot·后端·ssm·交互·拦截器·异常捕获器
gadiaola1 小时前
【JVM面试篇】高频八股汇总——类加载和类加载器
java·jvm·面试
七七&5561 小时前
【Java开发日记】基于 Spring Cloud 的微服务架构分析
java·spring cloud·架构
小猫咪怎么会有坏心思呢1 小时前
华为OD机考-数字游戏-逻辑分析(JAVA 2025B卷)
java·游戏·华为od
Aesopcmc1 小时前
idea 启动jar程序并调试
java·intellij-idea·jar
南极Ou2 小时前
Mybatis逆向工程详解(附源码文件)动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
xml·java·mybatis
Moshow郑锴2 小时前
IDEA为何一直无法使用超过4g内存
java·ide·intellij-idea
木头左2 小时前
Docker容器化镜像分层原理及优化策略
java·eureka