《数据算法Hadoop/Spark》读书笔记1--二次排序

  • 1 说明
    • 本章知识
    • 1.1 Chapter 01: Secondary Sorting With Spark
      • 1.1.1 新建maven工程
      • 1.1.2 编辑输入文件
      • 1.1.3 二次排序
      • 1.1.4 运行结果
      • 1.1.5 小结

1 说明

本文档介绍Spark的二次排序解决方案

本章知识


方法 返回类型/描述
textFile –> JavaRDD

- JavaRDD
        org.apache.spark.api.java.JavaSparkContext.textFile(String path)
- JavaRDD textFile(String path, int minPartitions)
mapToPair –> JavaPairRDD

- static JavaPairRDD
        mapToPair(PairFunction f)
groupByKey –>JavaPairRDD-

-JavaPairRDD>
        org.apache.spark.api.java.JavaPairRDD.groupByKey()
mapValues 要复制一份values再操作

- JavaPairRDD
        mapValues(Function f)
说明:Pass each value in the key-value pair RDD through a map function
without changing the keys; this also retains the original RDD’s partitioning.
IterableList 可以使用第三方包
Lists.newArrayList(e)
com.google.common.collect.Lists.newArrayList
(Iterable elements)
take(n)
collect()
-static java.util.List take(int num)
-static java.util.List collect()

1.1 Chapter 01: Secondary Sorting With Spark

输入格式

每一条记录(行)格式如下

<,>

假设key已经有序,对key分组,对time排序

输入数据

$ cat chap01-timeseries.txt 
p,4,40
p,6,20
x,2,9
y,2,5
x,1,3
y,1,7
y,3,1
x,3,6
z,1,4
z,2,8
z,3,7
z,4,0
p,1,10
p,3,60

期望输出

(z,{1=>4, 2=>8, 3=>7, 4=>0})
(p,{1=>10, 3=>60, 4=>40, 6=>20})
(x,{1=>3, 2=>9, 3=>6})
(y,{1=>7, 2=>5, 3=>1})

环境

spark version 2.1.2-SNAPSHOT        
Java 1.8.0_131

项目详细实现见如下过程,项目结构如下
《数据算法Hadoop/Spark》读书笔记1--二次排序_第1张图片

1.1.1 新建maven工程

新建maven工程,坐标 cn.whbing.spark
dataalgorithms

并添加两个依赖,其中spark-core_2.11,是必须的;guava仅仅是为了将Iterable转化为List。

<dependency>
    <groupId>org.apache.sparkgroupId>
    <artifactId>spark-core_2.11artifactId>
    <version>2.1.2version>
dependency>

<dependency>
  <groupId>com.google.guavagroupId>
  <artifactId>guavaartifactId>
  <version>24.1-jreversion>
dependency>

整个pom文件如下

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>cn.whbing.sparkgroupId>
  <artifactId>dataalgorithmsartifactId>
  <version>0.0.1-SNAPSHOTversion>
  <packaging>jarpackaging>

  <name>dataalgorithmsname>
  <url>http://maven.apache.orgurl>

  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
  properties>

  <dependencies>
    <dependency>
        <groupId>org.apache.sparkgroupId>
        <artifactId>spark-core_2.11artifactId>
        <version>2.1.2version>
    dependency>

    <dependency>
      <groupId>com.google.guavagroupId>
      <artifactId>guavaartifactId>
      <version>24.1-jreversion>
    dependency>

    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>3.8.1version>
      <scope>testscope>
    dependency>
  dependencies>
project>

1.1.2 编辑输入文件

输入文件每一行格式如下<,>,其保存在chap01-timeseries.txt中,内容如下。输入文件的位置可以保存在本地或HDFS等。本测试在local模式运行(集群类似),chap01-timeseries.txt文件位置与src同级。输入文件可以写死,运行时直接运行即可;也可以将输入文件作为参数输入,运行参数为chap01-timeseries.txt

chap01-timeseries.txt

p,4,40
p,6,20
x,2,9
y,2,5
x,1,3
y,1,7
y,3,1
x,3,6
z,1,4
z,2,8
z,3,7
z,4,0
p,1,10
p,3,60

1.1.3 二次排序

Created with Raphaël 2.1.2 输入文件timeseries.txt SparkConf及SparkContext ① textFile将每一行读取成->JavaRDD,即lines ② mapToPair(new PairFunction) -> JavaPairRDD ③ groupByKey -> JavaPairRDD,即groups ④ mapValues->对groups中的Iterable类型的Vaule排序

/ 1 / 说明

textFile将每一行读取成RDD可一参数或两参数;
mapToPair(new PairFunction)对每一行RDD的处理。T:原RDD类型,即StringK:转化后Key类型;V:转化后Value类型;
注:new PairFunction中返回Tuple2即可对应到PairRDD
groupByKey将相同keyvalue值组成Iterable
mapValues排序上述Iterable,属于java中处理集合范畴

/ 2 / 几个重要过程介绍

(1)处理输入文件并读取

将输入作为运行参数

//读取参数并验证
if(args.length<1){
    System.err.println("Usage: SecondarySort ");
    System.exit(1);  //1表示非正常退出,0表示正常退出
}

//读取输入的参数,即输入文件
String inputPath = args[0];
System.out.println("args[0]:="+args[0]);

创建sparkConfsparkContext,并读取文件

SparkConf conf = new SparkConf().setAppName("SecondarySort by spark").setMaster("local");
JavaSparkContext sc = new JavaSparkContext(conf);
JavaRDD<String> lines = sc.textFile(inputPath);

运行时需要传入参数。eclipseRun Configurations–>Arguments填入timeseries.txt

(2)中间结果调试collect或take

想要打印中间过程的RDDPairRDD,均使用collect。(saveAsText保存为文本,后续介绍)
take(int num)只打印前num个

spark2.1.2 API 如下

static java.util.List    take(int num) 
static java.util.List    collect() 

PairRDD collect后变成List>

如对分组后的PairRDD调试

List<Tuple2<String,Iterable<Tuple2<Integer,Integer>>>> out2 = groups.collect();
for(Tuple2<String,Iterable<Tuple2<Integer,Integer>>> t:out2){
    System.out.println(t._1);
    Iterable<Tuple2<Integer,Integer>> list = t._2;
    for(Tuple2<Integer,Integer> t2:list){
        System.out.println(t2._1+","+t2._2);
    }
    System.out.println("----");
}

(3)对Iterable排序

RDD不可变,进行操作需要先复制一份。

不能直接将Iterable转ArrayList,需要转换。这里可以使用import com.google.common.collect.Lists;

JavaPairRDD<String,Iterable<Tuple2<Integer,Integer>>> sorted = 
    groups.mapValues(new Function<Iterable<Tuple2<Integer,Integer>>, 
            Iterable<Tuple2<Integer,Integer>>>() {

        @Override
        public Iterable<Tuple2<Integer, Integer>> call(Iterable<Tuple2<Integer, Integer>> v)
                throws Exception {

            //直接对v排序是错误的,因为RDD不可变,要复制一份
            //Collections.sort(v, new TupleComparator());

            //书中有错误,需要转化v成ArrayList,不能直接是iterable
            //以下转化也有问题,引入google的包
            //ArrayList> listOut = new ArrayList<>((ArrayList)v);

            ArrayList<Tuple2<Integer, Integer>> listOut =Lists.newArrayList(v);

            Collections.sort(listOut, new TupleComparator());
            return listOut; //listOut属于Iterable,可以返回

        }               
});

(4)定制比较器

可以使用单例模式

TupleComparator.java

package cn.whbing.spark.dataalgorithms.chap01.util;

import java.io.Serializable;
import java.util.Comparator;

import scala.Tuple2;

public class TupleComparator implements 
                Comparator<Tuple2<Integer,Integer>>,Serializable {

    public static final TupleComparator INSTANCE = new TupleComparator(); 

    @Override
    public int compare(Tuple2 t1, 
            Tuple2 t2) {
        if(t1._1 return -1;
        }else if(t1._1 >t2._1){
            return 1;
        }
        return 0;
    }

}

/ 3 / 完整代码

SecondarySort.java

package cn.whbing.spark.dataalgorithms.chap01;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.PairFunction;


import com.google.common.collect.Lists;
import cn.whbing.spark.dataalgorithms.chap01.util.TupleComparator;
import scala.Tuple2;

public class SecondarySort {

    public static void main(String[] args) {
        //读取参数并验证
        if(args.length<1){
            System.err.println("Usage: SecondarySort ");
            System.exit(1);  //1表示非正常退出,0表示正常退出
        }

        //读取输入的参数,即输入文件
        String inputPath = args[0];
        System.out.println("args[0]:="+args[0]);

        //创建sparkConf及sparkContext(集群模式下运行时配模式时sparkConf可以不要)
        SparkConf conf = new SparkConf().setAppName("SecondarySort by spark").setMaster("local");
        JavaSparkContext sc = new JavaSparkContext(conf);
        //final JavaSparkContext sc = new JavaSparkContext();

        //读取每一行即<,>

1.1.4 运行结果

p,4,40
p,6,20
x,2,9
y,2,5
x,1,3

==DEBUG1==
JavaPairRDD collect as:
p,4,40
p,6,20
x,2,9
y,2,5
x,1,3

==DEBUG2==
groupByKey as:
p,4,40
p,6,20
x,2,9
y,2,5
x,1,3
y,1,7
y,3,1
x,3,6
z,1,4
z,2,8
z,3,7
z,4,0
p,1,10
p,3,60

z
1,4
2,8
3,7
4,0
----
p
4,40
6,20
1,10
3,60
----
x
2,9
1,3
3,6
----
y
2,5
1,7
3,1
----

==DEBUG OUTPUT==
z
1,4
2,8
3,7
4,0
----
p
1,10
3,60
4,40
6,20
----
x
1,3
2,9
3,6
----
y
1,7
2,5
3,1
----

1.1.5 小结

  1. textFile –> JavaRDD
  2. mapToPair –> JavaPairRDD
  3. groupByKey –>JavaPairRDD
  4. mapValues–>要复制一份values再操作
  5. Iterable转List
  6. take(n)collect()

你可能感兴趣的:(spark)