Spark之wordcount全家桶

本篇案例wordcount 操作的文件的内容

a a
b b
c c
d d

运行spark-shell --master local[N] 读取本地文件

单机模式:通过本地N个线程跑任务,只运行一个SparkSubmit进程。

  1. 需求
    读取本地文件,实现文件内的单词计数。本地文件 words.txt 内容如下:
    hello me
    hello you
    hello her
  2. 运行spark-shell --master local[2]
    在这里插入图片描述
    观察启动的进程:

在这里插入图片描述

  1. 编写 scala 代码

    sc.textFile("file://虚拟机本地文件的绝对路径").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
    

    代码说明:
    sc: Spark-Shell 中已经默认将 SparkContext 类初始化对象 sc。如果需要用到 SparkContext 类,则直接使用sc即可。
    textFile:读取数据文件。
    flatMap:对文件中的每一行数据进行压平切分,这里按照空格分隔。
    map:对出现的每一个单词记为 1(word,1)
    reduceByKey:对相同的单词出现的次数出现累加
    collect:触发任务执行,收集结果数据。

  2. 结果
    在这里插入图片描述

运行spark-shell --master local[N] 读取HDFS上数据

  1. 整合 spark 和 HDFS ,修改配置文件
    spark-env.sh ,添加 HADOOP_CONF_DIR 配置,指明了 hadoop 的配置文件后,默认它就是使用的 hdfs 上的文件。
    export HADOOP_CONF_DIR=/opt/bigdata/hadoop-2.6.4/etc/hadoop
    
    在这里插入图片描述
  2. 在启动hdfs,然后重启spark集群
  3. 向hdfs上传一个文件(hdfs dfs -put 虚拟机本地路径 hdfs路径)
  4. 在spark shell中用scala语言编写spark程序
    sc.textFile("hdfs中文件的绝对路径").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
    

运行spark-shell 读取HDFS并存到HDFS

  1. 需求:spark-shell 运行时指定具体的 master 地址,读取 HDFS 上的数据,做单词计数,然后将结果保存在 HDFS 上。

  2. 执行启动命令:

    spark-shell \
    --master spark://主节点名(hdp-node-01):7077 \
    --executor-memory 1g \
    --total-executor-cores 2
    
    

    在这里插入图片描述
    参数说明:
    – master spark://hdp-node-01:7077 指定Master的地址
    – executor-memory 1g 指定每个worker可用内存为1g
    – total-executor-cores 2 指定整个集群使用的cup核数为2个

    注意:
    如果启动 spark shell 时没有指定 master 地址,但是也可以正常启动 spark shell 和执行 spark shell 中的程序,其实是启动了 spark 的local 模式,改模式仅在本机启动一个进程,没有与集群建立联系。

  3. 编写 scala 代码

    sc.textFile("hdfs路径(/words.txt)").flatMap(_.split("")).map((_,1)).reduceByKey(_+_).saveAsTextFile("/wc")
    //saveAsTextFile("/wc")保存结果数据到hdfs文件中,wc一定是不存在的目录
    
  4. 查看 hdfs 上的结果
    在这里插入图片描述

在 IDEA 中编写 WordCount 程序

spark-shell仅在测试和验证我们的程序时使用的较多,在生产环境中,通常会在IDEA中编写程序,然后打成jar包,最后提交到集群。最常用的是创建一个 Maven 项目,利用 Maven 来管理 jar 包的依赖。

  1. 创建 maven 项目,编写 pom 依赖
    pom 内容如下:(一定要注意依赖冲突,可以去官网查看依赖 jar 包版本)

    	<properties>
            <scala.version>2.11.2</scala.version>
            <hadoop.version>2.6.5</hadoop.version>
            <spark.version>2.0.2</spark.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.scala-lang</groupId>
                <artifactId>scala-library</artifactId>
                <version>${scala.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.spark</groupId>
                <artifactId>spark-core_2.11</artifactId>
                <version>${spark.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-client</artifactId>
                <version>${hadoop.version}</version>
            </dependency>
        </dependencies>
        <build>
            <sourceDirectory>src/main/scala</sourceDirectory>
            <testSourceDirectory>src/test/scala</testSourceDirectory>
            <plugins>
                <plugin>
                    <groupId>net.alchim31.maven</groupId>
                    <artifactId>scala-maven-plugin</artifactId>
                    <version>3.2.0</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>testCompile</goal>
                            </goals>
                            <configuration>
                                <args>
                                    <arg>-dependencyfile</arg>
                                    <arg>${project.build.directory}/.scala_dependencies</arg>
                                </args>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>2.3</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                            <configuration>
                                <filters>
                                    <filter>
                                        <artifact>*:*</artifact>
                                        <excludes>
                                            <exclude>META-INF/*.SF</exclude>
                                            <exclude>META-INF/*.DSA</exclude>
                                            <exclude>META-INF/*.RSA</exclude>
                                        </excludes>
                                    </filter>
                                </filters>
                                <transformers>
                                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                        <mainClass></mainClass>
                                    </transformer>
                                </transformers>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
    </build>
    
    
  2. 新建一个 scala class,类型为object,编写 spark程序,内容如下:

    object Test {
      import org.apache.spark.{SparkConf, SparkContext}
      import org.apache.spark.rdd.RDD
    
    
      def main(args: Array[String]): Unit = {
        //设置spark的配置文件信息,local为本地测试
        val sparkConf: SparkConf = new SparkConf().setAppName("WordCount").setMaster("local")
        //构建sparkcontext上下文对象,它是程序的入口,所有计算的源头
        val sc: SparkContext = new SparkContext(sparkConf)
        
        //读取本地的文件,返回弹性数据集,按照文件中的行分隔,返回一个RDD弹性数据集,
       	//利用foreach打印后的结果为:
       		a a
    		b b
    		c c
    		d d
        val file: RDD[String] = sc.textFile("d://abcca.txt")
    
        //对文件中每一行单词进行压平切分,按照空格切分,返回一个RDD弹性数据集,
        //利用foreach打印的结果为:
        a
    	a
    	b
    	b
    	c
    	c
    	d
    	d
        val words: RDD[String] = file.flatMap(_.split(" "))
    	
        //对每一个单词计数为1 转化为(单词,1) KV形式
        //利用foreach打印的结果为:
        (a,1)
    	(a,1)
    	(b,1)
    	(b,1)
    	(c,1)
    	(c,1)
    	(d,1)
    	(d,1)
        val wordAndOne: RDD[(String, Int)] = words.map(x=>(x,1))
        
        //相同的单词进行汇总 前一个下划线表示累加数据,后一个下划线表示新数据,按照K去分区,相同K的V去进行相加
        val result: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
        //打印计数结果
        (d,2)
    	(a,2)
    	(b,2)
    	(c,2)
       result.foreach(println(_))
    	//关闭上下文对象
        sc.stop()
      }
    }
    
    

使用Maven打包,在linux集群上运行

	打包之前,要改一下代码:
	package cn.test.spark

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

	object WordCount {
	  def main(args: Array[String]): Unit = {
	    //设置spark的配置文件信息
	    val sparkConf: SparkConf = new SparkConf().setAppName("WordCount")
	    //构建sparkcontext上下文对象,它是程序的入口,所有计算的源头
	    val sc: SparkContext = new SparkContext(sparkConf)
	    //读取文件
	    val file: RDD[String] = sc.textFile(args(0))
	
	    //对文件中每一行单词进行压平切分
	    val words: RDD[String] = file.flatMap(_.split(" "))
	    //对每一个单词计数为1 转化为(单词,1)
	    val wordAndOne: RDD[(String, Int)] = words.map(x=>(x,1))
	    //相同的单词进行汇总 前一个下划线表示累加数据,后一个下划线表示新数据
	    val result: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
	    //保存数据到HDFS
	    result.saveAsTextFile(args(1))
	    sc.stop()
	  }
	}
  1. 启动hdfs
    /opt/bigdata/hadoop-2.6.4/sbin/start-dfs.sh

    启动spark
    /opt/bigdata/spark/sbin/start-all.sh

  2. 使用spark-submit命令提交Spark应用

    	spark-submit \
    	--class cn.test.spark.WordCount \
    	--master spark://hdp-node-01:7077 \
    	--executor-memory 1g \
    	--total-executor-cores 2 \
    	/root/spark-1.0-SNAPSHOT.jar \
    	/words.txt \
    	/spark_out
    

    这里通过spark-submit提交任务到集群上。用的是spark的Standalone模式
    Standalone模式是Spark内部默认实现的一种集群管理模式,这种模式是通过集群中的Master来统一管理资源。

    1. 查看Spark的web管理界面
      在这里插入图片描述
    2. 查看HDFS上的结果文件
      hdfs dfs -cat /spark_out/part*
      (hello,3)
      (me,1)
      (you,1)
      (her,1)

使用 Java 语言去编写 spark wordcount

	package cn.bw;
	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 scala.Tuple2;
	import java.util.Arrays;
	
	/**
	 * java代码实现spark的WordCount
	 */
	public class WordCountJava {
	    public static void main(String[] args) {
	        //todo:1、构建sparkconf,设置配置信息
	        SparkConf sparkConf = new SparkConf().setAppName("WordCount_Java").setMaster("local[2]");
	        //todo:2、构建java版的sparkContext
	        JavaSparkContext sc = new JavaSparkContext(sparkConf);
	        //todo:3、读取数据文件
	        JavaRDD<String> dataRDD = sc.textFile("d:/data/words1.txt");
	        //todo:4、对每一行单词进行切分
	        JavaRDD<String> wordsRDD = dataRDD.flatMap(new FlatMapFunction<String, String>() {
	            @Override
	            public Iterator<String> call(String s) throws Exception {
	                String[] words = s.split(" ");
	                return Arrays.asList(words).iterator();
	            }
	        });
	        //todo:5、给每个单词计为 1
	        // Spark为包含键值对类型的RDD提供了一些专有的操作。这些RDD被称为PairRDD。
	        // mapToPair函数会对一个RDD中的每个元素调用f函数,其中原来RDD中的每一个元素都是T类型的,
	        // 调用f函数后会进行一定的操作把每个元素都转换成一个<K2,V2>类型的对象,其中Tuple2为多元组
	        JavaPairRDD<String, Integer> wordAndOnePairRDD = wordsRDD.mapToPair(new PairFunction<String, String, Integer>() {
	            @Override
	            public Tuple2<String, Integer> call(String word) throws Exception {
	                return new Tuple2<String,Integer>(word, 1);
	            }
	        });
	
	        //todo:6、相同单词出现的次数累加
	        JavaPairRDD<String, Integer> resultJavaPairRDD = wordAndOnePairRDD.reduceByKey(new Function2<Integer, Integer, Integer>() {
	            @Override
	            public Integer call(Integer v1, Integer v2) throws Exception {
	                return v1 + v2;
	            }
	        });
	
	        //todo:7、反转顺序
	        JavaPairRDD<Integer, String> reverseJavaPairRDD = resultJavaPairRDD.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
	            @Override
	            public Tuple2<Integer, String> call(Tuple2<String, Integer> tuple) throws Exception {
	                return new Tuple2<Integer, String>(tuple._2, tuple._1);
	            }
	        });
	
	        //todo:8、把每个单词出现的次数作为key,进行排序,并且在通过mapToPair进行反转顺序后输出
	        JavaPairRDD<String, Integer> sortJavaPairRDD = reverseJavaPairRDD.sortByKey(false).mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
	            @Override
	            public Tuple2<String, Integer> call(Tuple2<Integer, String> tuple) throws Exception {
	
	                return  new Tuple2<String, Integer>(tuple._2,tuple._1);
	                //或者使用tuple.swap() 实现位置互换,生成新的tuple;
	            }
	        });
	
	        //todo:执行输出
	        System.out.println(sortJavaPairRDD.collect());
	
	        //todo:关闭sparkcontext
	        sc.stop();
	
	    }
	}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值