写在前面
1.依赖:
值得注意的一点:请务必保证spark兼容所用java版本
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<java.version>1.8</java.version>
<spark.version>3.2.2</spark.version>
</properties>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.12</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.12</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-10_2.12</artifactId>
<version>${spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.3.2</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-mapreduce-client-core -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>3.3.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.6</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.daerfen.sparktest.common.SqlHiveApp</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
2.初始化
初始化需要先创建一个sparkConf文件用于保存设置,比如这样
SparkConf conf = new SparkConf(). setMaster("local[*]"). setAppName("spark"). set("spark.testing.memory","2147480000");
不设置后面的参数可能会报错
然后根据设置创建sparkContext对象即可JavaSparkContext sc = new JavaSparkContext(conf);
3.RDDs及其创建方法
RDDs 即 Resilient(弹性的) Distributed Datasets,弹性分布式数据集
它容错,且支持并行
RDDs有两种创建方法
- 可以用集合构建,也就是用类似Array这样的类构建,比如
List<Integer> data = Arrays.asList(1, 2, 3, 4, 5); JavaRDD<Integer> distData = sc.parallelize(data);
- 可以用外部数据集构建,也就是说用HDFS,HBase这些Hadoop支持的文件构建,比如:
JavaRDD<String> distFile = sc.textFile("data.txt");
4.关于RDDs
RDDs支持的两种操作:
- 转化,它基于已有集合返回一个新的集合,比如map映射就是这样的
- 转化都是惰性的,它只在需要返回时计算,正如在SQL中选择/笛卡尔积会尽量最后计算一样
- 同时,对于可能需要经常使用的集合可以将其持久化以减少计算,类似SQL中的with
- 行动,它计算数据集给出一个值,比如reduce聚集就是这样的
- 考察下面的例子:
JavaRDD<String> lines = sc.textFile("data.txt"); //从文件创建RDD,文件并未加载,只是一个指针 JavaRDD<Integer> lineLengths = lines.map(s -> s.length()); //映射,转化lines中每个line为其长度,出于惰性,并不会马上计算 { lineLengths.persist(StorageLevel.MEMORY_ONLY()); //lineLengths会在第一次计算后被保存 } int totalLength = lineLengths.reduce((a, b) -> a + b); //行动,计算总和,任务被spark分解到不同机器运行
向Spark传递函数
为使函数正确在集群上运行,需要正确传递函数,在Java中表现为需要实现
org.apache.spark.api.java.function 接口具体来说有两种方式:
- lambda表达式,比如上面的例子中那样
- 在类中实现接口,可以是匿名类或者命名的类,比如可以把上面的例子改> 写成这样:
JavaRDD<String> lines = sc.textFile("data.txt"); JavaRDD<Integer> lineLengths = lines.map(new Function<String, Integer>() { public Integer call(String s) { return s.length(); } }); int totalLength = lineLengths.reduce(new Function2<Integer, Integer, Integer>() { public Integer call(Integer a, Integer b) { return a + b; } });
本地模式与集群模式
为了执行作业,Spark 将 RDD 操作的处理分解为多个任务,每个任务都由一个 executor 执行
- 从参数角度看:
- 在执行前,spark会计算执行所需参数的闭包,并将其副本序列化后的一个副本传给执行器
- 换句话说,这就好比直接给C++函数传参数,每个函数都是独立的
- 因而其实我们设想中会改变的值其实只在执行器上改变了
- 从打印的角度看:
- 类似的,如果需要打印一些结果,写
是不对的,它只会在每台执行器上打印rdd.foreach(println) ; 或者: rdd.map(println);
- 所以如果希望在本地打印,需要将DDR先去到,再打印
键值对
Java使用 scala.Tuple2 类表示键值对,可以用 tuple._1() 和 tuple._2().取得键和值
RDD的键值对表示为 JavaPairRDD 类
看下面这个统计词频的程序就不难理解了:
JavaRDD<String> lines = sc.textFile("data.txt"); JavaPairRDD<String, Integer> pairs = lines.mapToPair(s -> new Tuple2(s, 1)); JavaPairRDD<String, Integer> counts = pairs.reduceByKey((a, b) -> a + b);
5.具体算子
此处不细说 >_~
为什么不去看官方的文档呢qwq