SPARK基础2(读入文件、转临时表、RDD与DataFrame)

上文介绍了spark的各种组件和入门,本文主要介绍spark读入文件以及数据格式(RDD/DataFrame)

1、读入文件与转临时表

1、json文件读取

val df = spark.read.json("E:/people.json")
df.show()//将DataFrame的内容显示到页面

2、CSV文件读取(注意编码要UTF-8)

df=spark.read.csv("E:/emp1.csv")

也可以这样设置

val result = spark.read.format("csv")
 .option("delimiter", "|")//分隔符,默认为逗号,
 .option("header", "true")//第一行不作为数据内容,作为标题
 .option("quote", "'")//quote 引号字符,默认为双引号"
 .option("nullValue", "\\N") //指定一个字符串代表 null 值
 .option("inferSchema", "true")//header 第一行不作为数据内容,作为标题
 .load("test-in/csv/csv_with_header.csv")

完整案例如下所示:

import org.apache.spark.sql.SparkSession
/**
  *scala版本的DataFrame的常用操作。
  *通常将DataFrame存储在一张临时表中,后面通过执行sql的方式执行操作。
  *@authoryangshaojun
  *#date2019/4/39:29
  *@version1.0
  */
object SparkSql_002_DataFrameNormalOperation{
  def main(args:Array[String]):Unit={
    val spark=SparkSession
      .builder()
      .master("local")
      .appName("SparkSql_003_DataFrameNormalOperation")
      .getOrCreate()
    //等同于SQLContext对象sc.read().json("../.json")以及sc.read().load(../.json)
    val df=spark.read.csv("E:/emp1.csv")
    val result=spark.read.format("csv")
      .option("delimiter",",")
      .option("inferSchema",true.toString)//这是自动推断属性列的数据类型。
      .option("header","true")
      .option("quote","'")
      .option("nullValue","\\N")
      .option("inferSchema","true")
      .load("E:/emp1.csv")
    result.show()
    result.createOrReplaceTempView("result")//创建临时表
    spark.sql("SELECT * FROM result where score>60").show()
  }
}

3、TXT
A、spark.read.textFile方法(返回是一个整体很难看)

val testtxt=spark.read.textFile("E:/emp1.txt")
testtxt.show()//成功读取文件数据
testtxt.createOrReplaceTempView("testtxt")//创建临时视图,此视图的生命周期与用于创建此数据集的[SparkSession]相关联。

±-----+
| value|
±-----+
| 张绣,98|
|张老三,55|
| 柳丝,87|
| 赵四,56|
|张无忌,99|
|朱元璋,91|
±-----+

2、(优先推荐)spark.sparkContext.textFile
返回的是个RDD,可以通过createDataFrame方法将RDD转为DataFrame进行查询

val spark = SparkSession
 .builder()
 .appName("testpeople")
 .master("local")
 .getOrCreate()
    // 使用createDataFrame
val FileRDD = spark.sparkContext.textFile("C:/Users/Administrator/Desktop/课程代码/testT.txt",2).map{
lines=>valline=lines.split(",")Row(line(0),line(1).toInt)
}

整体案例如下所示:

package com.cdpsql1
import org.apache.spark.sql.{Row,SparkSession}
import org.apache.spark.sql.types._
import scala.collection.mutable
import java.text.SimpleDateFormat
object SparkSqlExample1{
  def main(args:Array[String]):Unit={
    val spark=SparkSession
      .builder()
      .master("local")
      .appName("test")
      .config("spark.sql.shuffle.partitions","5")
      .getOrCreate()
    //表结构
    val ScoreSchema:StructType=StructType(mutable.ArraySeq(
      StructField("name",StringType,nullable=false),
      StructField("score",IntegerType,nullable=false)
    ))

    //导入数据
    val ScoreData=spark.sparkContext.textFile("E:/emp1.txt").map{
      lines=>val line=lines.split(",")
        Row(line(0),line(1).toInt)
    }
    //转表
    val ScoreTable=spark.createDataFrame(ScoreData,ScoreSchema)
    ScoreTable.createOrReplaceTempView("Score")
    spark.sql("select * from Score where score>60").show()

  }
}

也可以用case class定义表结构

//定义case class,相当于表结构
case class People(var name:String,var sc:Int)
import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.sql.{SparkSession}
object TestDataFrame1 {
  def main(args: Array[String]): Unit = {
    val spark=SparkSession
      .builder()
      .master("local")
      .appName("test")
      .config("spark.sql.shuffle.partitions","5")
      .getOrCreate()
     val sqlContext=spark.sqlContext
    //先将RDD转化成case class 数据类型,然后再通过toDF()方法隐式转换成DataFrame
    import sqlContext.implicits._
    // 将本地的数据读入 RDD, 并将 RDD 与 case class 关联
    val peopleRDD = spark.sparkContext.textFile("E:/emp1.txt")
      .map{line => People(line.split(",")(0), line.split(",")(1).trim.toInt)}

    // 将RDD 转换成 DataFrames
    val df = peopleRDD.toDF()
    //将DataFrames创建成一个临时的视图

    df.createOrReplaceTempView("people")
    //使用SQL语句进行查询
    df.show()

  }
}
//定义case class,相当于表结构
case class People(var name:String,var sc:Int)
import org.apache.spark.sql.{SparkSession}
object TestDataFrame1 {
  def main(args: Array[String]): Unit = {

    val spark=SparkSession
      .builder()
      .master("local")
      .appName("test")
      .config("spark.sql.shuffle.partitions","5")
      .getOrCreate()
    //先将RDD转化成case class 数据类型,然后再通过toDF()方法隐式转换成DataFrame
    import spark.implicits._
    // 将本地的数据读入 RDD, 并将 RDD 与 case class 关联
    val peopleRDD = spark.sparkContext.textFile("E:/emp1.txt")
      .map{line => People(line.split(",")(0), line.split(",")(1).trim.toInt)}
    // 将RDD 转换成 DataFrames
    val df = peopleRDD.toDF()
    //将DataFrames创建成一个临时的视图
    df.createOrReplaceTempView("people")
    //使用SQL语句进行查询
    df.show()
  }
package t1
import org.apache.spark.sql.{SparkSession,Row}
object r4 {
  def main(a: Array[String])={
    val spark=SparkSession
      .builder()
      .master("local")
      .appName("test")
      //.config("spark.sql.shuffle.partitions","1")
      .getOrCreate()
    import spark.implicits._
    val pd=spark.sparkContext.textFile("E:/emp1.txt").map{
      lines => val line=lines.split(",")
        person(line(0), line(1).toInt)
    }
    val pe=pd.toDF()
    pe.show()
  }
}

分列读入,方便后期filter过滤

    val pd = spark.sparkContext.textFile("E:/emp1.txt").map {
      line => {
        val f=line.split(",")
        val name=f(0)
        val sc=f(1).toInt
        (name,sc)
      }
    }
    val x=pd.filter(t => t._2.toInt > 60)
    x.foreach(println)

val pd=spark.sparkContext.textFile("E:/emp1.txt").map{
line=>person(line.split(",")(0),line.split(",")(1).toInt)
}.toDF("X1","X2")
pd.show()
val x=pd.filter($"X2">60)
x.show()

2、RDD与DataFrame

接下来说的是spark中的数据格式:RDD与DataFrame
RDD和DataFrame在前文已经介绍很多次了,这里我们详细介绍这两种数据格式

2.1 RDD

RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。
1.弹性 正常情况下,数据是存放到内存里的,但是如果说内存放不下这么多数据时,这时候就会写到磁盘。RDD的这种自动进行内存和磁盘之间权衡和切换的机制,就是RDD的弹性的特点所在。对用户来说是透明的。

2.分布式
简单说就是数据存放到不同机器上,1个Rdd=多个Partition,Parition就是分区,这个分区其实是个非常重要的概念,为什么这么说呢?Paritition本质上只是一部分数据,它和Task是一一对应的,task在提交的时候又有什么依据呢?其实又跟这个有关系

3.数据集
数据集这个概念也是相当有意思,你以为就是简单的一堆数据吗?答案是否定 ,RDD可以理解为“数据+对数据操作”,RDD的基本单位是partition,以及每个分片的操作函数,也就是算子。当然了,RDD还“记录”着自身的血缘关系,对parent RDD的依赖,官方叫“lineage”。仅仅这么简单吗?这涉及到RDD的容错性,当某个节点挂掉了,这时候数据就丢失了,怎么办?spark程序挂掉了?那这也太low了,RDD是有很强的容错性的,当它发现自己的数据丢失了以后,会自动从自己来源的数据进行重计算,重新获取自己这份数据,这就是“血缘关系”。

由上可知,RDD特点为:分区,不可变,并行操作。
a, 分区
每一个 RDD都被分为多个分区,每个分区 运行在集群的不同节点上。
RDD可以包含PYTHON、JAVA、scala中任意类型的对象,甚至是用户自定义对象。
逻辑上我们可以将 RDD 理解成一个大的数组,数组中的每个元素就代表一个分区 (Partition) 。

在物理存储中,每个分区指向一个存储在内存或者硬盘中的数据块 (Block) ,其实这个数据块就是每个 task 计算出的数据块,它们可以分布在不同的节点上。

所以,RDD 只是抽象意义的数据集合,分区内部并不会存储具体的数据,只会存储它在该 RDD 中的 index,通过该 RDD 的 ID 和分区的 index 可以唯一确定对应数据块的编号,然后通过底层存储层的接口提取到数据进行处理。

在集群中,各个节点上的数据块会尽可能的存储在内存中,只有当内存没有空间时才会放入硬盘存储,这样可以最大化的减少硬盘 IO 的开销。

b,不可变
不可变性是指每个 RDD 都是只读的,它所包含的分区信息是不可变的。由于已有的 RDD 是不可变的,所以我们只有对现有的 RDD 进行转化 (Transformation) 操作,才能得到新的 RDD ,一步一步的计算出我们想要的结果。

这样会带来这样的好处:我们在 RDD 的计算过程中,不需要立刻去存储计算出的数据本身,我们只要记录每个 RDD 是经过哪些转化操作得来的,即:依赖关系,这样一方面可以提高计算效率,一方面是错误恢复会更加容易。如果在计算过程中,第 N 步输出的 RDD 的节点发生故障,数据丢失,那么可以根据依赖关系从第 N-1 步去重新计算出该 RDD,这也是 RDD 叫做"弹性"分布式数据集的一个原因。

c,并行操作
因为 RDD 的分区特性,所以其天然支持并行处理的特性。即不同节点上的数据可以分别被处理,然后生成一个新的 RDD。
RDD的创建方式一般有三种,1、读入文件;2、创建,sc.parallelize(array),3其他形式转化
下文会接着介绍RDD的特性与算子

2.2DataFrame

DataFrame与RDD的区别:
SPARK基础2(读入文件、转临时表、RDD与DataFrame)_第1张图片
从上面的图中可以看出DataFrame和RDD的区别。RDD是分布式的 Java对象的集合,比如,RDD[Person]是以Person为类型参数,但是,Person类的内部结构对于RDD而言却是不可知的。DataFrame是一种以RDD为基础的分布式数据集,也就是分布式的Row对象的集合(每个Row对象代表一行记录),提供了详细的结构信息,也就是我们经常说的模式(schema),Spark SQL可以清楚地知道该数据集中包含哪些列、每列的名称和类型。

和RDD一样,DataFrame的各种变换操作也采用惰性机制,只是记录了各种转换的逻辑转换路线图(是一个DAG图),不会发生真正的计算,这个DAG图相当于一个逻辑查询计划,最终,会被翻译成物理查询计划,生成RDD DAG,按照之前介绍的RDD DAG的执行方式去完成最终的计算得到结果。
RDD怎么转化为DATAFRAME?
一般来说有两种方法:class case和StructType
参照上文读入文件的方法解决。
综上,SPARK中的DATAFRAME特点如下:
1)分布式的数据集,并且以列的方式组合的。相当于具有schema的RDD
2)相当于关系型数据库中的表,但是底层有优化
3)提供了一些抽象的操作,如select、filter、aggregation、plot(具体api操作在下文中:SPARK基础3(DataFrame操作))
4)它是由于R语言或者Pandas语言处理小数据集的经验应用到处理分布式大数据集上
5)在1.3版本之前,叫SchemaRDD

你可能感兴趣的:(spark)