Spark_06

函数中引用一个Driver端的一个类

案例1
package day6
import java.net.InetAddress
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object SerTest {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("SerTest")
    val sc = new SparkContext(conf)

    val lines: RDD[String] = sc.textFile(args(0))
    val r = lines.map(word => {
      //在map的函数中,创建一个rules实例,下面程序在executor的Task中执行。
      val rules = new Rules	//每获取一个word数据就会创建一个Rules对象
      val hostname = InetAddress.getLocalHost.getHostName
      val threadName = Thread.currentThread().getName
      (hostname, threadName, rules.rulesMap.getOrElse(word, 0), rules.toString)
    })
    r.saveAsTextFile(args(1))
    sc.stop()
  }
}

package day6
class Rules {

  val rulesMap = Map("spark" -> 1, "hadoop" -> 2)
}

在这里插入图片描述
由结果可知,每获取一个word数据就会创建一个Rules对象。浪费内存资源。

案例2

闭包:函数的内部使用了一个外部的变量(函数式编程经常会遇到的问题)。

package day6

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

object SerTest {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("SerTest")
    val sc = new SparkContext(conf)
    //在Driver端进行实例化
    val rules = new Rules

    val lines: RDD[String] = sc.textFile(args(0))

    val r = lines.map(word => {
      val hostname = InetAddress.getLocalHost.getHostName
      val threadName = Thread.currentThread().getName
	  //Task里面使用了一个Driver端的引用。
      (hostname, threadName, rules.rulesMap.getOrElse(word, 0), rules.toString)
    })

    r.saveAsTextFile(args(1))
    sc.stop()
  }

}
package day6


class Rules {

  val rulesMap = Map("spark" -> 1, "hadoop" -> 2)

}

在这里插入图片描述
Task not serializable,Task没有被实例化原因?
因为Task中引用了Rules对象,Rules没有被实例化,所以不能通过Rpc通信传输到executor中。

实例3

在这里插入图片描述

package day6

import java.net.InetAddress
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object SerTest {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("SerTest")
    val sc = new SparkContext(conf)
    //在Driver端进行实例化
    val rules = new Rules

    val lines: RDD[String] = sc.textFile(args(0))

    val r = lines.map(word => {
      val hostname = InetAddress.getLocalHost.getHostName
      val threadName = Thread.currentThread().getName

      (hostname, threadName, rules.rulesMap.getOrElse(word, 0), rules.toString)
    })
    r.saveAsTextFile(args(1))
    sc.stop()
  }
}
package day6
class Rules extends Serializable {
  val rulesMap = Map("spark" -> 1, "hadoop" -> 2)
}

在这里插入图片描述
在这里插入图片描述
由此得出,每一个Task对应一个Rules实例,同一个Executor中的不同的Task使用不同的Task,但是有多个Task使用相同的规则时,还是会造成内存浪费。

实例4

在这里插入图片描述

package day6
import java.net.InetAddress
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object SerTest {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("SerTest")
    val sc = new SparkContext(conf)
    //在Driver端进行实例化
    val rules = Rules
    val lines: RDD[String] = sc.textFile(args(0))

    val r = lines.map(word => {
      val hostname = InetAddress.getLocalHost.getHostName
      val threadName = Thread.currentThread().getName

      (hostname, threadName, rules.rulesMap.getOrElse(word, 0), rules.toString)
    })

    r.saveAsTextFile(args(1))
    sc.stop()
  }
}
package day6
object Rules extends Serializable {

  val rulesMap = Map("spark" -> 1, "hadoop" -> 2)

}

在这里插入图片描述
在这里插入图片描述
上面的结果表明:在一个Executor中只有一个Rules实例,在一个JVM进程中只有一个实例。上面的方法,在Driver端进行了初始化。

实例5

在这里插入图片描述

package day6
import java.net.InetAddress
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object SerTest {

  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("SerTest")
    val sc = new SparkContext(conf)
    val lines: RDD[String] = sc.textFile(args(0))
    val r = lines.map(word => {
      val hostname = InetAddress.getLocalHost.getHostName
      val threadName = Thread.currentThread().getName
      (hostname, threadName, Rules.rulesMap.getOrElse(word, 0), Rules.toString)
    })

    r.saveAsTextFile(args(1))
    sc.stop()
  }
}
package day6
import java.net.InetAddress

//第三种方法,希望Rules在Executor中被初始化,不走网络,就不用在Driver端进行初始化和序列化。
object Rules{
	//静态变量
  val rulesMap = Map("spark" -> 2.7, "hadoop" -> 2.3)
  val hostname = InetAddress.getLocalHost.getHostName

  println(hostname + "@@@@@@@@@@@@!!!!!!!!!!!")
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在Executor端的日志文件中可以看见初始化信息,只会读取一次,每个JVM中存放一个Rules对象。

Executor中多线程问题

案例1
package cn.edu360.game

import java.text.SimpleDateFormat

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/*
读取指定文件中的日志,选取在指定时间段内创建的新用户,并统计新用户的数量。
 */
object GameKPI {

  def main(args: Array[String]): Unit = {

    //"2016-02-01"
    val startDate = args(0)
    //"2016-02-02"
    val endDate = args(1)

    //查询条件
    val dateFormat1 = new SimpleDateFormat("yyyy-MM-dd")

    //查寻条件的的起始时间
    val startTime = dateFormat1.parse(startDate).getTime
    //查寻条件的的截止时间
    val endTime = dateFormat1.parse(endDate).getTime

    //Driver定义的一个simpledataformat,在Task中引用所以要发送到Executor中执行。
    val dateFormat2 = new SimpleDateFormat("yyyy年MM月dd日,E,HH:mm:ss")

    val conf = new SparkConf().setAppName("GameKPI").setMaster("local")
    val sc = new SparkContext(conf)

    //以后从哪里读取数据
    val lines: RDD[String] = sc.textFile(args(2))
    //整理并过滤
    val splited: RDD[Array[String]] = lines.map(line => line.split("[|]"))
    //按日期过过滤
    val filterd = splited.filter(fields => {
      val t = fields(0)
      val time = fields(1)
      val timeLong = dateFormat2.parse(time).getTime  //在Executor中使用了Driver端的对象
      t.equals("1") && timeLong >= startTime && timeLong < endTime  //过滤器的判断条件
    })

    val dnu = filterd.count()
    println(dnu)

    sc.stop()
  }
}
案例2
package cn.edu360.game

import java.text.SimpleDateFormat
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object GameKPIV2 {

  def main(args: Array[String]): Unit = {

    //"2016-02-01"
    val startDate = args(0)
    //"2016-02-02"
    val endDate = args(1)

    val dateFormat1 = new SimpleDateFormat("yyyy-MM-dd")
    val startTime = dateFormat1.parse(startDate).getTime
    val endTime = dateFormat1.parse(endDate).getTime

    val conf = new SparkConf().setAppName("GameKPI").setMaster("local[4]")
    val sc = new SparkContext(conf)

    val lines: RDD[String] = sc.textFile(args(2))
    val splited: RDD[Array[String]] = lines.map(line => line.split("[|]"))

    val filteredByType = splited.filter(fields => {
      //一个Task中会创建很多的FilterUtils实例,因为每处理一条就会创建一个实例
      val fu = new FilterUtilsV3
      fu.filterByType(fields,"1")
    })

    val filtered = filteredByType.filter(fields => {
      //一个Task中会创建很多的FilterUtils实例,因为每处理一条就会创建一个实例
      val fu = new FilterUtilsV3
      fu.filterByTime(fields, startTime, endTime)
    })

    val dnu = filtered.count()
    println(dnu)

    sc.stop()
  }

}
package cn.edu360.game

import java.text.SimpleDateFormat

class FilterUtilsV3{

  //如果object使用了成员变量,那么会出现线程安全问题,因为object是一个单例,多线程可以同时调用这个方法
  val dateFormat = new SimpleDateFormat("yyyy年MM月dd日,E,HH:mm:ss")

  def filterByType(fields: Array[String], tp: String) = {
    val _tp = fields(0)
    _tp == tp
  }

  def filterByTime(fields: Array[String], startTime: Long, endTime: Long) = {

    val time = fields(1)
    val timeLong = dateFormat.parse(time).getTime
    timeLong >= startTime && timeLong < endTime
  }
}
案例3
package cn.edu360.game

import java.text.SimpleDateFormat

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

/**
  * Created by zx on 2017/9/2.
  */
object GameKPIV3 {

  def main(args: Array[String]): Unit = {

    //"2016-02-01"
    val startDate = args(0)
    //"2016-02-02"
    val endDate = args(1)

    val dateFormat1 = new SimpleDateFormat("yyyy-MM-dd")
    val startTime = dateFormat1.parse(startDate).getTime
    val endTime = dateFormat1.parse(endDate).getTime


    val conf = new SparkConf().setAppName("GameKPI").setMaster("local[4]")
    val sc = new SparkContext(conf)

    //以后从哪里读取数据
    val lines: RDD[String] = sc.textFile(args(2))

    //整理并过滤
    val splited: RDD[Array[String]] = lines.map(line => line.split("[|]"))

    //FilterUtils是在Driver端创建的
    val fu = new FilterUtilsV3 with Serializable

    val filtered = splited.filter(fields => {
      fu.filterByTime(fields, startTime, endTime)
    })

    val dnu = filtered.count()
    println(dnu)
    sc.stop()


  }

}
package cn.edu360.game

import java.text.SimpleDateFormat

class FilterUtilsV3{

  //如果object使用了成员变量,那么会出现线程安全问题,因为object是一个单例,多线程可以同时调用这个方法
  val dateFormat = new SimpleDateFormat("yyyy年MM月dd日,E,HH:mm:ss")

  def filterByType(fields: Array[String], tp: String) = {
    val _tp = fields(0)
    _tp == tp
  }

  def filterByTime(fields: Array[String], startTime: Long, endTime: Long) = {

    val time = fields(1)
    val timeLong = dateFormat.parse(time).getTime
    timeLong >= startTime && timeLong < endTime
  }
}

案例4
package cn.edu360.game

import java.text.SimpleDateFormat

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

object GameKPIV4 {

  def main(args: Array[String]): Unit = {

    //"2016-02-01"
    val startDate = args(0)
    //"2016-02-02"
    val endDate = args(1)

    val dateFormat1 = new SimpleDateFormat("yyyy-MM-dd")
    val startTime = dateFormat1.parse(startDate).getTime
    val endTime = dateFormat1.parse(endDate).getTime

    val conf = new SparkConf().setAppName("GameKPI").setMaster("local[4]")
    val sc = new SparkContext(conf)

    //以后从哪里读取数据
    val lines: RDD[String] = sc.textFile(args(2))

    //整理并过滤
    val splited: RDD[Array[String]] = lines.map(line => line.split("[|]"))

    val filtered = splited.filter(fields => {
      FilterUtilsV4.filterByTime(fields, startTime, endTime)
    })

    val dnu = filtered.count()

    println(dnu)

    sc.stop()


  }

}
package cn.edu360.game

import java.text.SimpleDateFormat
import org.apache.commons.lang3.time.FastDateFormat

object FilterUtilsV4{

  //如果object使用了成员变量,那么会出现线程安全问题,因为object是一个单例,多线程可以同时调用这个方法
  val dateFormat = new SimpleDateFormat("yyyy年MM月dd日,E,HH:mm:ss")
  //FastDateFormat是线程安全的
  //val dateFormat = FastDateFormat.getInstance("yyyy年MM月dd日,E,HH:mm:ss")

  def filterByType(fields: Array[String], tp: String) = {
    val _tp = fields(0)
    _tp == tp
  }
//在同一个Executor中有一个FilterUtilsV4对象,一个Executor中可能有多个Task,不同的Task同时调用FilterUtilsV4的filterByTime方法,该方法中引用了SimpleDataFormat对象,当多个线程同时调用这一个对象时,由于线程不安全会导致异常。
  def filterByTime(fields: Array[String], startTime: Long, endTime: Long) = {
    val time = fields(1)
    val timeLong = dateFormat.parse(time).getTime
    timeLong >= startTime && timeLong < endTime
  }
}

Spark SQL(处理结构化数据)

Spark SQL is Apache Spark’s module for working with structured data.
Spark SQL与Hive的作用相同:将SQL语句解析成RDD(DataFrame)和Map Reduce,对相应的数据进行处理。
特点:
1.SparkSQL是Spark上的高级模块,Spark SQL是一个SQL解析引擎,将SQL解析成特殊的RDD(DataFrame),然后在Spark集群中运行。
2.Spark SQL是用来处理结构化数据的(先将非结构化的数据转换成结构化数据)
3.SparkSQL支持两种编程API:SQL方式,DataFrame的方式(DSL)
4.Spark SQL兼容hive(元数据库,SQL语法,UDF自定义函数,序列化,反序列化机制)
5.SparkSQL支持统一的数据源,可以读取多种类型的数据
6.Spark SQL提供了标准的连接(JDBC,ODBC),以后可以对接一下BI工具。

什么是Data Frames

与RDD相似,DataFrame也是一个分布式数据容器。然而DataFrame更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema。同时,与Hive类似,DataFrame也支持嵌套数据类型(struct、array和map)。从API易用性的角度上 看,DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好,门槛更低。由于与R和Pandas的DataFrame类似,Spark DataFrame很好地继承了传统单机数据分析的开发体验。

RDD和Data Frames有哪些区别

DataFrames里面存放的结构化数据的描述信息,DataFrame要有表头(表的描述信息),描述了有多少列,每一列叫什么名字,什么类型,能不能为空?
DataFrame是一个特殊的RDD(RDD+Schema信息就变成了DataFrame)
在这里插入图片描述

Spark SQL的第一个入门程序

首先在pom中添加spark SQL的依赖

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-sql_2.11</artifactId>
        <version>${spark.version}</version>
    </dependency>

SparkSQL1.x和2.x的编程API有一些变化,企业中都有使用,所以两种方式都将

用1.x的方式

	a.SQL
		创建一个SQLContext
			1.创建Spark Context,然后再创建SQL Context
			2.先创建RDD,对数据进行处理,然后关联case class,将非结构化数据转换成结构化数据
			3.显示的调用toDF方法将RDD转化成DataFrame
			4.注册临时表
			5.执行SQL(Transformation,lazy)
			6.执行Action
			=============
			1.创建Spark Context,然后再创建SQL Context
			2.先创建RDD,对数据进行处理,然后关联Row,将非结构化数据转换成结构化数据
			3.定义schema
			4.调用sqlContext的createDataFrame方法
			5.注册临时表
			6.执行SQL(Transformation,lazy)
			7.执行Action
	b.DSL(DataFrame)
import org.apache.spark.sql.{DataFrame, SQLContext}
import org.apache.spark.{SparkConf, SparkContext}
object SQLDemo1 {

  def main(args: Array[String]): Unit = {

    //提交的这个程序可以连接到Spark集群中
    val conf = new SparkConf().setAppName("SQLDemo1").setMaster("local[2]")

    //创建Spark SQL的连接(程序执行的入口)
    val sc = new SparkContext(conf)

    //sparkContext不能创建特殊的RDD(DataFrame)
    //将SparkContext包装进而增强
    val sqlContext = new SQLContext(sc)
    //创建特殊的RDD(DataFrame),就是有schema信息的RDD
    //先有一个普通的RDD,然后在关联上schema,进而转成DataFrame

    val lines = sc.textFile("hdfs://node1:8020/person")

    //将数据进行处理
    val boyRDD = lines.map(line => {
      val fields = line.split(",")
      val id = fields(0).toLong
      val name = fields(1)
      val age = fields(3).toInt
      val fv = fields(2).toDouble
      Boy(id, name, age, fv)
    })

    //该RDD装的是Boy类型的数据,有了shcam信息,但是还是一个RDD
    //将RDD转换成DataFrame
    //对原先的RDD进行增强,导入隐式转化
    import sqlContext.implicits._     //这个隐式转化在类里面,必须创建类的对象,才能导入
    val bdf: DataFrame = boyRDD.toDF()

    //变成DF后就可以使用两种API进行编程了
    //把DataFrame注册临时表,DataFrame=RDD+schema
    bdf.registerTempTable("t_boy")

    //书写SQL(SQL方法其实是Transformation)
    val result: DataFrame = sqlContext.sql("SELECT * FROM t_boy ORDER BY fv desc, age asc")

    //查看结果(触发Action)
    result.show()
    sc.stop()
  }
}
case class Boy(id: Long, name: String, age: Int, fv: Double)
package day6

import org.apache.spark.sql.types.{DoubleType, IntegerType, LongType, StringType, StructField, StructType}
import org.apache.spark.sql.{DataFrame, Row, SQLContext}
import org.apache.spark.{SparkConf, SparkContext}


object SQLDemo2 {

  def main(args: Array[String]): Unit = {

    //提交的这个程序可以连接到Spark集群中
    val conf = new SparkConf().setAppName("SQLDemo1").setMaster("local[2]")

    //创建Spark SQL的连接(程序执行的入口)
    val sc = new SparkContext(conf)

    //sparkContext不能创建特殊的RDD(DataFrame)
    //将SparkContext包装进而增强
    val sqlContext = new SQLContext(sc)
    //创建特殊的RDD(DataFrame),就是有schema信息的RDD
    //先有一个普通的RDD,然后在关联上schema,进而转成DataFrame

    val lines = sc.textFile("hdfs://node1:8020/person")

    //将数据进行处理
    val rowRDD = lines.map(line => {
      val fields = line.split(",")
      val id = fields(0).toLong
      val name = fields(1)
      val age = fields(3).toInt
      val fv = fields(2).toDouble
      Row(id, name, age, fv)
    })

    //结构类型,其实就是表头,用于描述DataFrame
    val schema = StructType(List(
      StructField("id", LongType, true),
      StructField("name", StringType, true),
      StructField("age", IntegerType, true),
      StructField("fv", DoubleType, true)
    ))
    //将Row RDD关联schema
    val bdf = sqlContext.createDataFrame(rowRDD, schema)

    //该RDD装的是Boy类型的数据,有了schema信息,但是还是一个RDD
    //将RDD转换成DataFrame
    //对原先的RDD进行增强,导入隐式转化
    //import sqlContext.implicits._     //这个隐式转化在类里面,必须创建类的对象,才能导入
    //val bdf: DataFrame = boyRDD.toDF()

    //变成DF后就可以使用两种API进行编程了
    //把DataFrame注册临时表,DataFrame=RDD+schema
    bdf.registerTempTable("t_boy")

    //书写SQL(SQL方法其实是Transformation)
    val result: DataFrame = sqlContext.sql("SELECT * FROM t_boy ORDER BY fv desc, age asc")

    //查看结果(触发Action)
    result.show()

    sc.stop()

  }
}

object SQLDemo3 {

  def main(args: Array[String]): Unit = {

    //提交的这个程序可以连接到Spark集群中
    val conf = new SparkConf().setAppName("SQLDemo3").setMaster("local[2]")

    //创建Spark SQL的连接(程序执行的入口)
    val sc = new SparkContext(conf)

    //sparkContext不能创建特殊的RDD(DataFrame)
    //将SparkContext包装进而增强
    val sqlContext = new SQLContext(sc)
    //创建特殊的RDD(DataFrame),就是有schema信息的RDD
    //先有一个普通的RDD,然后在关联上schema,进而转成DataFrame

    val lines = sc.textFile("hdfs://node1:8020/person")

    //将数据进行处理
    val rowRDD = lines.map(line => {
      val fields = line.split(",")
      val id = fields(0).toLong
      val name = fields(1)
      val age = fields(3).toInt
      val fv = fields(2).toDouble
      Row(id, name, age, fv)
    })

    //结构类型,其实就是表头,用于描述DataFrame
    val schema = StructType(List(
      StructField("id", LongType, true),
      StructField("name", StringType, true),
      StructField("age", IntegerType, true),
      StructField("fv", DoubleType, true)
    ))
    //将Row RDD关联schema
    val bdf: DataFrame = sqlContext.createDataFrame(rowRDD, schema)

    //不使用SQL的方式,就不用注册临时表了
    val df1: DataFrame = bdf.select("name", "age", "fv")

    import sqlContext.implicits._
    val df2: DataFrame = df1.orderBy($"fv" desc, $"age" asc)

    df2.show()

    sc.stop()

  }
}

用2.x的方式

SparkSQL会在执行之前指定执行计划,优化执行流程。

sql的API
package day6
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
import org.apache.spark.sql.types.{DoubleType, IntegerType, LongType, StringType, StructField, StructType}

object SQLTest1 {

  def main(args: Array[String]): Unit = {

    //spark2.x SQL的变成API(Spark Session)
    //是spark2.x SQL执行入口
    val session = SparkSession.builder()
        .appName("SQLTest1")
        .master("local[3]")
        .getOrCreate()

    //创建RDD
    val lines: RDD[String] = session.sparkContext.textFile("hdfs://node1:8020/person")

    //将数据进行处理
    val rowRDD = lines.map(line => {
      val fields = line.split(",")
      val id = fields(0).toLong
      val name = fields(1)
      val age = fields(3).toInt
      val fv = fields(2).toDouble
      Row(id, name, age, fv)
    })
    //结构类型,其实就是表头,用于描述DataFrame
    val schema = StructType(List(
      StructField("id", LongType, true),
      StructField("name", StringType, true),
      StructField("age", IntegerType, true),
      StructField("fv", DoubleType, true)
    ))
    //创建DataFram
    val df: DataFrame = session.createDataFrame(rowRDD, schema)

    import session.implicits._
    val df2 = df.where($"fv" > 99).orderBy($"fv" desc, $"age" asc)

    df2.show()
    session.stop()
  }
}
package day6
import org.apache.spark.sql.{DataFrame, Dataset, SparkSession}
/**
实现WordCount使用SQL的API。
*/
object SQLWordCount {

  def main(args: Array[String]): Unit = {

    //创建SparkSession
    val spark = SparkSession.builder()
      .appName("SQLWordCount")
      .master("local[2]")
      .getOrCreate()

    //(指定以后从哪里)读数据,是lazy
    //Dataset分布式数据集,是对RDD的进一步封装,是更加智能的RDD
    //dataset只有一列,默认这列叫value
    val lines: Dataset[String] = spark.read.textFile("hdfs://node1:8020/words")

    //整理数据
    //切分压平
    //导入隐式转换,flatMap是DataSet上面的方法。
    import spark.implicits._
    val words: Dataset[String] = lines.flatMap(_.split(" "))

    //注册表
    words.createTempView("v_wc")

    //执行SQL(Transformation)
    val result: DataFrame = spark.sql("SELECT value,COUNT(*) counts FROM v_wc GROUP BY value ORDER BY counts desc")

    //执行
    result.show()

    spark.stop()
  }
}
DataSet的API
package day6

import org.apache.spark.sql.{DataFrame, Dataset, SparkSession}
//使用Dataset数据结构实现
object DatasetWordCount {

  def main(args: Array[String]): Unit = {

    //创建SparkSession
    val spark = SparkSession.builder()
      .appName("DatasetWordCount")
      .master("local[2]")
      .getOrCreate()

    //(指定以后从哪里)读数据,是lazy
    //Dataset分布式数据集,是对RDD的进一步封装,是更加智能的RDD
    //dataset只有一列,默认这列叫value
    val lines: Dataset[String] = spark.read.textFile("hdfs://node1:8020/words")

    //整理数据
    //切分压平
    //导入隐式转换
    import spark.implicits._
    val words: Dataset[String] = lines.flatMap(_.split(" "))

    //使用Dataset的API(DSL)
    //val count = words.groupBy($"value" as "word").count().sort($"count" desc)

    //导入聚合函数
    import org.apache.spark.sql.functions._
    val counts = words.groupBy($"value" as "word").agg(count("*") as "counts").orderBy($"counts" desc)

    counts.show()

    spark.stop()
  }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值