spark_2

学习spark第二天
一.spark基本工作原理
1.分布式
2.主要基于内存(少数情况基于磁盘)
3.迭代计算
二.RDD及其特点
1.RDD是Spark提供的核心抽象,全称为Resillient Distributed Dataset,及弹性分布式数据集
2.RDD在抽象上来说是一种元素集合,包含了数据.他是被分区的,分为多个区,每个分区分布在不同的节点上,从而让RDD中的数据可以被并行操作(分布式数据集)
3.RDD通常通过hadoop上的文件,及hdfs文件或者hive表,来进行创建;有时也可以通过应用程序中的集合来创建
4.RDD最重要的特性就是提供了容错性,可以自动从节点失败中回复我过来.即如果某个节点上的RDDpartition,因为节点故障,导致数据丢失,那么RDD会自动通过自己的数据来源重新计算该partition.这一切对使用者都是透明的.
5.RDD的数据默认情况下存放在内存中的,但是在内存资源不多时,spark会自动将RDD数据写入磁盘(弹性)
三.什么是spark开发
1.核心开发:离线批处理 / 延迟性的交互式数据处理
2.SQL查询: 底层都是RDD和计算操作
3.实时计算:底层都是RDD和计算操作
四.Wordcount程序

package main;

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.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction;
import scala.Tuple2;

import java.util.Arrays;

public class WordCountLocal {
    public static void main(String[] args) {
        //编写spark应用程序本地执行
        //第一步:创建SpaekConf对象,设置spark本地信息
        //使用setMaster设置spark应用程序要的链接的集群master的url
        //local代表本地
        SparkConf conf = new SparkConf().setAppName("WordCountLocal").setMaster("local");

        //第二步,创建JavaSparkContext
        //在Spark中,SparkContext是Spark所有功能的一个入口,你无论使用Spark,scala,甚至是python编写
        //都必须有一个SparkContext,它的主要作用,包括初始化Spark应用程序所需要的一些核心组件包括
        //调度器(DAGSchedule,TaskScheduler),还会去到Spark Master节点上进行注册,等等
        //一句话,SparkContext,是Spark应用中,可以说是最最重要的一个对象
        //但是呢,在Spark中,编写不同类型的Spark应用程序,使用的SparkContext是不同的,如果使用scala,
        //使用的就是原生的SparkContext对象
        //如果是Java,就是JavaSparkContext对象
        //如果开发Spark SQL程序,那么就是SQLContext,HiveContext
        //如果开发Spark Streaming程序,那么就是它独有的SparkContext

        JavaSparkContext sc = new JavaSparkContext(conf);

        //第三步: 要针对输入源(hdfs文件,本地文件,等等),创建一个初始的RDD
        //输入源的数据会打散,分配到RDD的每一个partition中,从而形成一个初始的分布式数据集
        //我们这里测试的是本地数据
        //在Java中,创建普通的DRR,叫做JavaRDD
        //在这里,RDD中,有元素这种概念,如果是hdfs或者本地文件呢,创建RDD,每一个元素就相当于是文件里的一行

        /*注意事项
        1.如果是针对本地文件的话,如果在Windows上本地测试,Windows上有一份文件即可;如果实在spark集群上针对Linux本地文件,
        那么需要将文件拷贝到所有worker节点上.
        2.Spark的textFile()方法支持怎对目录,压缩文件以及通配符进行RDD创建
        3.Spark默认会为hdfs文件的每一个block创建一个partition,但是也可以通过textFile()的
        第二个人参数手动设置分区数量,不能比block数量少
         */
        /*
        Spark的textFile()除了可以针对上述几种普通的文件创建RDD之外,还有一些特列的方法来创建RDD:
        1.SparkContext.wholeTextFile()方法,可以针对一个目录中的大小文件,返回<filename,fileContext>组成的pair,
        作为一个PariRDD,而不是普通的RDD.
        2.SparkContext.sequenceFile[K,V]()方法,可以针对SequenceFile创建RDD,K和V泛型类型就是Sequence
        的Key和value的类型.K和V要求必须是Hadoop的序列化类型,比如IntWritable,Text等
        3.SparkContext.hadoopRDD()方法,对于Hadoop的自定义输入类型,可以创建RDD,该方法接收JobConf,
        IntputFormatClass,Key和Value的Class
        4.SparkContext.objectFile()方法,可以针对之前调用的RDD.saveAsOBjectFile()创建
        的对象序列化的文件,反序列化的文件中的数据,并创建一个RDD
         */

        JavaRDD<String> lines = sc.textFile("D:\\hadoop\\spark\\spark.txt");
        //long count=lines.count();
        //System.out.println(count);

        //第四步:对初始化的RDD进行transformation操作,也就是一些计算操作
        //通常操作会通过创建function,并配合RDD的map,flatMap的算子来执行
        //function,通常,如果比较复杂,则会单独创建一个类 ,作为实现这个function借口的类

        //先将每一行拆分成单个单词
        //FlatMaoFunction,有两个泛型参数,分别代表代表输入类型和输出类型
        //我们这里,输入肯定是String,因为是一行一行的文本,输出也是String,因为把每一行文本拆分成单个单词
        //这里先简单介绍flatMap算子的作用,其实就是将RDD的一个元素给拆分一个或多个元素

        JavaRDD<String> worlds = lines.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public Iterable<String> call(String s) throws Exception {
                return Arrays.asList(s.split(" "));
            }
        });
        //接着,需要将每一个单词,映射为(单词,1)的这种格式
        //只有这样,才能根据单词作为key,来进行每个单词的出现次数进行累加
        //mapTOPair,其实就是将每个元素映射为一个(v1,v2),这样的Tuple2类型的元素
        //scala里的Tuple,这里的Tuple2就是scala类型,包含两个值
        //mapToPair这个算子,要求的是与PairFunction配合使用,第一个泛型参数代表了输入类型
        //第二个和第三个泛型参数,代表的输出的Tuple2的第一个值和第二个值的类型
        //JavaPairRDD的两个泛型参数,分别代表了Tuple元素的第一个值和第二个值得类型

        JavaPairRDD<String, Integer> pairs = worlds.mapToPair(new PairFunction<String, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(String s) throws Exception {
                return new Tuple2<String, Integer>(s, 1);
            }
        });

        //需要以单词作为key,统计每个单出现的次数
        //这里要使用reduceByKey这个算子,对于每个key对应的value,都进行reduce操作
        //比如JavaPairRDD中有几个元素,分别是(hello, 1) (hello, 1) (hello, 1) (world, 1)
        //reduce操作,相当于把第一个值和第二个值进行计算,然后在将结果也第三个值进行计算
        //比如这里的hello,那么就是相当于是 1 + 1 = 2,然后 2 + 1 = 3
        //最后JavaPairRDD中的元数,也是Tuple,但是第一个值就是每一个key,第二个值就是key的value
        //reduce之后的结果,相当于就是每个单词出现的次数

        JavaPairRDD<String, Integer> wordcounts = pairs.reduceByKey(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) throws Exception {
                return integer + integer2;
            }
        });

        //到这里为止,我们通过几个Spark算子操作,已经统计出了单词的次数
        //但是,之前我们使用的flatMap,MapToPair,reduceByKey这种操作,都叫transformation操作
        //一个Spark应用中,光是有transformation操作是不行的,是不会执行的,必须要有一种叫做action
        //接着,最后可以使用一种叫做action操作,比如说,foreach,来触发程序执行
        wordcounts.foreach(new VoidFunction<Tuple2<String, Integer>>() {
            @Override
            public void call(Tuple2<String, Integer> t) throws Exception {
                System.out.println(t._1+":"+t._2);
            }
        });
        //关闭JavaSparkContext
        sc.close();


    }
}

结果
(MLlib),:1
For:2
Product:1
it:3
operators:1
Hadoop��s:1
sits:1
have:3
tweet:1
stack.:1
modification:1
conference.:1
simple:1
we:2
This:1
manager.:1
//第一种
package com.scala_spark

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

object Wordcount {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("Wordcount").setMaster("local")
    val sc = new SparkContext(conf)

    val lines = sc.textFile("D:\\hadoop\\spark\\spark.txt")

    val worlds: RDD[String] = lines.flatMap(_.split(" "))

    //val worldAndOne: RDD[(String, Int)] = worlds.map((world:String)=>(world,1))
    val worldAndOne: RDD[(String, Int)] = worlds.map((_,1))

    //val worldcount = woldcount.reduceByKey((v1:Int,v2:Int)=>v1+v2)
    //val worldcount = woldcount.reduceByKey(v1+v2)
    val woldcount: RDD[(String, Int)] = worldAndOne.reduceByKey(_ + _)

    val unit: Unit = woldcount.foreach(wc=>println(wc._1+":"+wc._2))
    //woldcount.foreach(println)


//第二种
sc.textFile("E:\\sparktext\\spark.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).foreach(println)
  }

}


五.创建RDD
在进入Spark核心编程时,首先要做的第一件事就是创建一个初始的RDD,该RDD中,通常就代表和包含了Spark应用程序的输入源数据,然后创建了初始的RDD之后,才可以通过Spark Core提供的transformation算子,对该RDD进行转换,来获取其他的RDD
Spark Core提供了三种创建RDD的方式,包括: 使用程序中的集合创建RDD;使用本地文件创建RDD;使用HDFS文件创建RDD

  • 使用程序中的集合创建RDD,主要用于进行测试,可以实际部署到集群运行之前,自己使用集合构造测试数据,来测试数据,来测试后面的spark应用的流程
  • 使用本地文件创建RDD主要用于临时性处理一些存储了大量数据文件
  • 使用HDFS文件创建RDD,应该是最常用的生产环境处理方式,主要可以针对HDFS上存储的大量数据,进行离线操作

六.并行化集合创建RDD
通过并行化集合创建RDD,需要针对程序中的集合,调用SparkContext的parallelize()方法.Spark会将集合中的数据拷贝到集群上去,形成一个分布式的数据集合,也就是一个RDD,相当于是,集合中的部分数据回到一个节点上,而另一部分节点上的数据回到其他节点上,然后就可以并行的方式来操作这个分布式数据集
案例:1到10 累加求和

val arr=Array(1,2,3,4,5,6,7,8,9,10)
val rdd=sc.parallelize(arr)
val sum=rdd.reduce(_+_)

调用parallelize()时,有一个最要的参数可以指定,就是要将集合切成多少个partition.Spark会为每个partition运行一个task来进行处理.Spark管方的建议是,为集群中的每个CPU创建2~4个partition.spark会默认根据集群的情况来设置partition的数量.但是也可以在调用parallilze()方法时,传入第二个参数,来设置RDD的partition数量.
例:
parallalize(arr,10)

七.使用本地文件和HDFS创建RDD
spark是支持使用任何Hadoop支持的存储系统上的文件创建RDD的,比如:HDFS,Cassandra,HBase以及本地文件.通过调用SparkContextFile()方法,可以针对本地文件或HDFS文件创建RDD
注意事项

  • 如果是针对本地文件的话,如果是在Windows上本地测试,Windows上有一份文件即可;如果是在Spark集群上针对Linux本地文件,name需要将文件拷贝到所有worker节点上
  • Spark的textFile()方法支持针对目录.压缩文件以及统配符进行RDD创建
  • Spark默认会为hdfs文件每一个block创建一个partition,但是也可以通过textFile()的第二个参数手动设置分区数量,只能比block多,不能比block数量少

案例:文件字数统记

//本地
package main;

import org.apache.spark.SparkConf;
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.Function2;

public class LocalFile {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setMaster("local").setAppName("LocalFile");

        JavaSparkContext sc = new JavaSparkContext(conf);

// 使用SparkContext以及其子类的textFile()方法,针对本地文件创建RDD
        JavaRDD<String> lines = sc.textFile(args[0]);
        JavaRDD<Integer> lineLength = lines.map(new Function<String, Integer>() {
            @Override
            public Integer call(String s) throws Exception {
                return s.length();
            }
        });
        // 统计文本文件内的字数Array(123,12,45,24
        Integer count = lineLength.reduce(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) throws Exception {
                return integer + integer2;
            }
        });
        System.out.println("文件中出现单词的总数:" + count);

        sc.close();
    }

}


//HDFS
package main;

import org.apache.spark.SparkConf;
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.Function2;

public class HdfsFile {
    public static void main(String[] args) {
        /**
         * 使用HDFS文件创建RDD
         *  * 案例:统计文本文件字数
         */
        SparkConf conf = new SparkConf().setAppName("HdfsFile").setMaster("local");

        JavaSparkContext sc = new JavaSparkContext(conf);

        // 使用SparkContext以及其子类的textFile()方法,针对HDFS文件创建RDD
        // 只要把textFile()内的路径修改为hdfs文件路径即可
        JavaRDD<String> lines = sc.textFile("hdfs://hadoop1:9000/spark.txt");

        JavaRDD<Integer> lineLength = lines.map(new Function<String, Integer>() {
            @Override
            public Integer call(String s) throws Exception {
                return s.length();
            }
        });
        Integer count = lineLength.reduce(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) throws Exception {
                return integer + integer2;
            }
        });
        System.out.println("文件中出现单词的总数:" + count);


        sc.close();
    }
}

Spark的 textFile()除了可以针对上述几种普通的文件创建RDD之外,还有一些特殊的方法来创建RDD

  • SparkContext.whole TextFiles()方法,可以针对一个目录中的大量小文件,返回<filename,fileContent>组成的pair,作为一个PairRDD,而不是普通的RDD.普通的textFile()返回的RDD中,每个元素就是文件中的一行文件
  • SparkContext.sequenceFileK,V方法,可以针对SequenceFile创建RDD,K和V泛型类型就是SequenceFile的key和value的类型.K和V要求必须是Hadoop的序列化类型,比如IntWritable,Text等
  • SparkContext.hadoopRDD()方法,对于hadoop的自定义输入类型,可以创建RDD.该方法接收JobConf,InputFormatClass,Key和Value的Class
  • SparkContext.objectFile()方法,可以针对之前调用的RDD.saveAsObjectFile()创建对象序列化的文件,反序列化的数据,并创建一个RDD
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值