【Spark征服之路-2.5-Spark-Core编程(一)】

环境准备

  1. Jdk1.8版本
  2. Scala2.12版本
  3. Idea集成开发环境中需要安装scala插件

环境配置

· 添加 Scala 插件

Spark 由 Scala 语言开发的,所以接下来的开发所使用的语言也为 Scala,当前使用的 Spark 版本为 3.0.0,默认采用的 Scala 编译版本为 2.12,所以后续开发时,我们依然采用2.12的scala版本。开发前请保证 IDEA 开发工具中含有 Scala 开发插件

File---Settings---plugins

创建spark实现的WordCount程序

1 . 创建Maven项目

2 . 在pom.xml中添加依赖

<dependencies >
<dependency >
<groupId >org.apache.spark</groupId >
<artifactId >spark-core_2.12</artifactId >
<version >3.0.0</version >
</dependency >
<dependency >
<groupId >org.apache.maven.plugins</groupId >
<artifactId >maven-assembly-plugin</artifactId >
<version >3.1.0</version >
</dependency >
</dependencies >

<build >
<plugins >
<!-- 该插件用于将 Scala 代码编译成 class 文件 -->
<plugin >
<groupId >net.alchim31.maven</groupId >
<artifactId >scala-maven-plugin</artifactId >
<version >3.2.2</version >
<executions >
<execution >
<!-- 声明绑定到 maven compile 阶段 -->
<goals >
<goal >testCompile</goal >
</goals >
</execution >
</executions >
</plugin >
<plugin >
<groupId >org.apache.maven.plugins</groupId >
<artifactId >maven-assembly-plugin</artifactId >
<version >3.1.0</version >
<configuration >
<descriptorRefs >
<descriptorRef >jar-with-dependencies</descriptorRef >
</descriptorRefs >
</configuration >
<executions >
<execution >
<id >make-assembly</id >
<phase >package</phase >
<goals >
<goal >single</goal >
</goals >
</execution >
</executions >
</plugin >
</plugins >
</build >

保存之后重新加载。

3.创建Spark-core子模块

4 . 将spark-core当中的java文件夹重命名为scala。

5 . 在scala文件夹中创建Scala的object程序。

6 . 编写wordCount的spark程序

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object WordCount {
def main(args: Array[String]): Unit = {
// 创建 Spark 运行配置对象
val sparkConf = new SparkConf().setMaster("local[*]" ).setAppName("WordCount" )
// 创建 Spark 上下文环境对象(连接对象)
val sc : SparkContext = new SparkContext(sparkConf)
// 读取文件数据
val fileRDD: RDD[String] = sc.

textFile(" Spark-core /input/word.txt" )
// 将文件中的数据进行分词
val wordRDD: RDD[String] = fileRDD.flatMap( .split(" " ) )
// 转换数据结构 word => (word, 1)
val word2OneRDD: RDD[(String, Int)] = wordRDD.map((
,1))
// 将转换结构后的数据按照相同的单词进行分组聚合
val word2CountRDD: RDD[(String, Int)] = word2OneRDD.reduceByKey(+)
// 将数据聚合结果采集到内存中
val word2Count: Array[(String, Int)] = word2CountRDD.collect()
// 打印结果
word2Count.foreach(println )
// 关闭 Spark 连接
sc.stop()

}
}

7 . 在Spark-core中创建名为input的文件夹,在此文件夹中创建word.txt文件,并在文件中添加需要进行统计的语句。

测试文本:

Spark is a unified analytics engine for large-scale data processing

It provides high-level APIs in Scala Java Python and R and an optimized engine that

supports general computation graphs for data analysis

It also supports a rich set of higher-level tools including Spark SQL for SQL and DataFrames

MLlib for machine learning GraphX for graph processing and Structured Streaming for stream processing

8. 运行编写好的Word C ount程序

9 . 配置日志文件

执行过程中,会产生大量的执行日志,如果为了能够更好的查看程序的执行结果,可以在项

目的 resources 目录中创建 log4j.properties 文件,并添加日志配置信息:

log4j.rootCategory =ERROR, console
log4j.appender.console =org.apache.log4j.ConsoleAppender
log4j.appender.console.target =System.err
log4j.appender.console.layout =org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern =%d{yy/MM/ddHH:mm:ss} %p %c{1}: %m%n
# Set the default spark-shell log level to ERROR. When running the spark-shell,the
# log level for this class is used to overwrite the root logger's log level, so that
# the user can have different defaults for the shell and regular Spark apps.
log4j.logger.org.apache.spark.repl.Main =ERROR
# Settings to quiet third party logs that are too verbose
log4j.logger.org.spark_project.jetty =ERROR
log4j.logger.org.spark_project.jetty.util.component.AbstractLifeCycle =ERROR
log4j.logger.org.apache.spark.repl.SparkIMainexprTyper**** =****ERROR**** ****log4j.logger.org.apache.spark.repl.SparkILoopSparkILoopInterpreter =ERROR
log4j.logger.org.apache.parquet =ERROR
log4j.logger.parquet =ERROR
# SPARK-9183: Settings to avoid annoying messages when looking up nonexistent UDFs in SparkSQL with Hive support
log4j.logger.org.apache.hadoop.hive.metastore.RetryingHMSHandler =FATAL
log4j.logger.org.apache.hadoop.hive.ql.exec.FunctionRegistry =ERROR

1 0. 配置完成后重新执行代码

1 1. 常见问题解决

如果本机操作系统是 Windows,在程序中使用了 Hadoop 相关的东西,比如写入文件到 HDFS,则会遇到如下异常:

出现这个问题的原因,并不是程序的错误,而是 windows 系统用到了 hadoop 相关的服 务,解决办法是通过配置关联到 windows 的系统依赖就可以了

首先确保在本地磁盘中有hadoop的相关内容且配置了环境变量

然后在Idea中配置 Run Configuration,添加 HADOOP_HOME 变量

创建RDD

在 Spark 中创建 RDD 的创建方式可以分为四种:

1. 从集合(内存)中创建 RDD

从集合中创建 RDD,Spark 主要提供了两个方法:parallelize 和 makeRDD

val sparkConf =
new SparkConf().setMaster("local[*]" ).setAppName("spark" )
val sparkContext = new SparkContext(sparkConf)

val rdd1 = sparkContext.parallelize(
List (1,2,3,4)
)
val rdd2 = sparkContext.makeRDD(
List (1,2,3,4)
)
rdd1.collect().foreach(println )
rdd2.collect().foreach(println )

sparkContext.stop()

从底层代码实现来讲,makeRDD 方法其实就是 parallelize 方法

def makeRDD[T: ClassTag](

seq: Seq[T],

numSlices: Int = defaultParallelism): RDD[T] = withScope {

parallelize(seq, numSlices)

}

2. 从外部存储(文件)创建 RDD

由外部存储系统的数据集创建 RDD 包括:本地的文件系统,所有 Hadoop 支持的数据集, 比如 HDFS、HBase 等。

val fileRDD: RDD[String] = sparkContext.textFile("spark-core/input" )
fileRDD.collect().foreach(println )

3. 从其他 RDD 创建

主要是通过一个 RDD 运算完后,再产生新的 RDD。

4. 直接创建 RDD(new)

使用 new 的方式直接构造 RDD,一般由 Spark 框架自身使用。

RDD并行度与分区

默认情况下,Spark 可以将一个作业切分多个任务(Task)后,发送给 Executor 节点并行计算,而能够并行计算的任务数量我们称之为并行度。这个数量可以在构建 RDD 时指定。记住,这里的并行执行的任务数量,并不是指的切分任务的数量

val dataRDD: RDD[Int] =
sparkContext.makeRDD(
List (1,2,3,4),
4)
val fileRDD: RDD[String] =
sparkContext.textFile(
"spark-core/input" ,
2)
fileRDD.collect().foreach(println )

读取内存数据时,数据可以按照并行度的设定进行数据的分区操作,数据分区规则的

Spark 核心源码如下:

def positions(length: Long, numSlices: Int): Iterator[(Int, Int)] = {

(0 until numSlices).iterator.map { i =>

val start = ((i * length) / numSlices).toInt

val end = (((i + 1) * length) / numSlices).toInt

(start, end)

}

}

读取文件数据时,数据是按照 Hadoop 文件读取的规则进行切片分区,而切片规则和数据读取的规则有些差异,具体 Spark 核心源码如下

public InputSplit[] getSplits(JobConf job, int numSplits)

throws IOException {

long totalSize = 0; // compute total size

for (FileStatus file: files) { // check we have valid files

if (file.isDirectory()) {

throw new IOException("Not a file: "+ file.getPath());

}

totalSize += file.getLen();

}

long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits);

long minSize = Math.max(job.getLong(org.apache.hadoop.mapreduce.lib.input.

FileInputFormat.SPLIT_MINSIZE, 1), minSplitSize);

...

for (FileStatus file: files) {

...

if (isSplitable(fs, path)) {

long blockSize = file.getBlockSize();

long splitSize = computeSplitSize(goalSize, minSize, blockSize);

...

}

protected long computeSplitSize(long goalSize, long minSize,

long blockSize) {

return Math.max(minSize, Math.min(goalSize, blockSize));

}

相关推荐
xx155802862xx1 小时前
matlab分布式电源微电网潮流
分布式
bxlj_jcj1 小时前
解锁Flink CDC:实时数据同步秘籍
大数据·flink
明达技术1 小时前
分布式I/O在食品包装行业中的应用
分布式
悢七1 小时前
flink1.19.2+cdc-3.2.1遇到的问题及解决方案
大数据·flink
上海锟联科技2 小时前
DAS-U250高性能分布式光纤声波传感器
分布式
wanhengidc2 小时前
大数据服务器和普通服务器之间的区别
大数据·运维·服务器
网硕互联的小客服2 小时前
如何诊断服务器硬盘故障?出现硬盘故障如何处理比较好?
大数据·运维·服务器
从零开始学习人工智能4 小时前
Doris 与 Elasticsearch:谁更适合你的数据分析需求?
大数据·elasticsearch·数据分析
爱编程的张同学4 小时前
Spring Cloud Alibaba Seata安装+微服务实战
分布式·spring cloud·微服务
Gauss松鼠会5 小时前
GaussDB分布式数据库调优方法总结:从架构到实践的全链路优化指南
数据库·分布式·sql·database·gaussdb