Spark Sql介绍

概况

Spark SQL是用于结构化数据处理的Spark模块。与基本的Spark RDD API不同,Spark SQL提供的接口为Spark提供了关于数据结构和正在执行的计算的更多信息。在内部,Spark SQL使用这些额外的信息来执行额外的优化。有几种与Spark SQL进行交互的方式,包括SQL和Dataset API。在计算结果时,使用相同的执行引擎,而不管使用哪种API /语言表示计算。这种统一意味着开发人员可以轻松地在不同的API之间来回切换,基于这些API提供了表达给定转换的最自然的方式。

SQL

Spark SQL的一个用途是执行SQL查询。Spark SQL也可以用来从现有的Hive安装中读取数据。有关如何配置此功能的更多信息,请参阅Hive表部分。从另一种编程语言中运行SQL时,结果将作为数据集/数据框返回。您还可以使用命令行 或通过JDBC / ODBC与SQL接口进行交互。

DataFrames

DataFrame是分布式数据集合,组织到命名列中。它的作用上相当于关系数据库中的表格或R / Python中的DataFrames,但具有更丰富的优化。DataFrame可以从各种各样的源构建,例如:结构化数据文件,Hive中的表,外部数据库或现有的RDD。相对于Rdd,DataFrames具有更好的性能优化。spark sql的查询结果最后以DataFrames的形式返回

从Rdd转换为DataFrames有两种方式:
- 利用反射推断模式
- 编程指定模式

利用反射推断模式
package sql

import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkContext, SparkConf}

/**
  * Created by Administrator on 2018/1/12.
  */
object RddToDf_1 {

  case class Person(name: String, age: Int)
  def main(args: Array[String]) {

    // 屏蔽不必要的日志显示在终端上
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)

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

    val sqlContext = new org.apache.spark.sql.SQLContext(sc)

    // this is used to implicitly convert an RDD to a DataFrame.
    import sqlContext.implicits._

    // Define the schema using a case class.
    // Note: Case classes in Scala 2.10 can support only up to 22 fields. To work around this limit,
    // you can use custom classes that implement the Product interface.


//    // Create an RDD of Person objects and register it as a table.
    val people = sc.textFile("E:\\wgz\\hadoop\\Spark\\SparkLearning\\data\\people.txt").map(_.split(",")).map(p => Person(p(0), p(1).trim.toInt)).toDF()
    people.registerTempTable("people")

    // SQL statements can be run by using the sql methods provided by sqlContext.
    val teenagers = sqlContext.sql("SELECT name, age FROM people WHERE age >= 13 AND age <= 19")

    // The results of SQL queries are DataFrames and support all the normal RDD operations.
    // The columns of a row in the result can be accessed by field index:
    teenagers.map(t => "Name: " + t(0)).collect().foreach(println)

    // or by field name:
    teenagers.map(t => "Name: " + t.getAs[String]("name")).collect().foreach(println)

    // row.getValuesMap[T] retrieves multiple columns at once into a Map[String, T]
    teenagers.map(_.getValuesMap[Any](List("name", "age"))).collect().foreach(println)
    // Map("name" -> "Justin", "age" -> 19)


  }
}

编程指定模式
import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkContext, SparkConf}

/**
  * Created by Administrator on 2018/1/12.
  */
object RddToDf_1 {

  case class Person(name: String, age: Int)
  def main(args: Array[String]) {

    // 屏蔽不必要的日志显示在终端上
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)

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

    val sqlContext = new org.apache.spark.sql.SQLContext(sc)

    // this is used to implicitly convert an RDD to a DataFrame.
    import sqlContext.implicits._

    // Define the schema using a case class.
    // Note: Case classes in Scala 2.10 can support only up to 22 fields. To work around this limit,
    // you can use custom classes that implement the Product interface.


//    // Create an RDD of Person objects and register it as a table.
    val people = sc.textFile("E:\\wgz\\hadoop\\Spark\\SparkLearning\\data\\people.txt").map(_.split(",")).map(p => Person(p(0), p(1).trim.toInt)).toDF()
    people.registerTempTable("people")

    // SQL statements can be run by using the sql methods provided by sqlContext.
    val teenagers = sqlContext.sql("SELECT name, age FROM people WHERE age >= 13 AND age <= 19")

    // The results of SQL queries are DataFrames and support all the normal RDD operations.
    // The columns of a row in the result can be accessed by field index:
    teenagers.map(t => "Name: " + t(0)).collect().foreach(println)

    // or by field name:
    teenagers.map(t => "Name: " + t.getAs[String]("name")).collect().foreach(println)

    // row.getValuesMap[T] retrieves multiple columns at once into a Map[String, T]
    teenagers.map(_.getValuesMap[Any](List("name", "age"))).collect().foreach(println)
    // Map("name" -> "Justin", "age" -> 19)


  }
}

数据源

sparksql的数据大致分为以下四种
- RDDs
- parquet文件
- JSON数据集
- Hive表

RDDs

详情可以参考rdd To DataFrames

    val people = sc.textFile("E:\\wgz\\hadoop\\Spark\\SparkLearning\\data\\people.txt").map(_.split(",")).map(p => Person(p(0), p(1).trim.toInt)).toDF()
    people.registerTempTable("people")

    // SQL statements can be run by using the sql methods provided by sqlContext.
    val teenagers = sqlContext.sql("SELECT name, age FROM people WHERE age >= 13 AND age <= 19")

parquet

parquet可以加速查询,因为它只检查所有需要的列并对它们的值执行计算,因此只读取一个数据文件或表的小部分数据。Parquet 还支持灵活的压缩选项,因此可以显著减少磁盘上的存储。
如果您在 HDFS 上拥有基于文本的数据文件或表,而且正在使用 Spark SQL 对它们执行查询,那么强烈推荐将文本数据文件转换为 Parquet 数据文件,以实现性能和存储收益。当然,转换需要时间,但查询性能的提升在某些情况下可能达到 30 倍或更高,存储的节省可高达 75%!

    val sqlContext = new org.apache.spark.sql.SQLContext(sc)

    val df = sqlContext.read.load("data\\users.parquet")
    //val df = sqlContext.parquetFile("data\\users.parquet")
//    val df = sqlContext.sql("SELECT * FROM parquet.`E:\\wgz\\hadoop\\Spark\\SparkLearning\\data\\users.parquet`")
    df.show()

JSON

    val sqlContext = new org.apache.spark.sql.SQLContext(sc)

    val df = sqlContext.read.json("data\\people.json")

    df.show()
//    +----+-------+
//    | age|   name|
//    +----+-------+
//    |null|Michael|
//      |  30|   Andy|
//      |  19| Justin|
//      +----+-------+
Hive表
// sc is an existing SparkContext.
val sqlContext = new org.apache.spark.sql.hive.HiveContext(sc)

sqlContext.sql("CREATE TABLE IF NOT EXISTS src (key INT, value STRING)")
sqlContext.sql("LOAD DATA LOCAL INPATH 'examples/src/main/resources/kv1.txt' INTO TABLE src")

// Queries are expressed in HiveQL
sqlContext.sql("FROM src SELECT key, value").collect().foreach(println)

性能优化

在内存中缓存数据
  • sqlContext.cacheTable(“tableName”)
  • dataFrame.cache()
  • sqlContext.uncacheTable(“tableName”)

Spark SQL可以通过调用sqlContext.cacheTable(“tableName”)或使用内存中的列格式缓存表dataFrame.cache()。然后,Spark SQL将只扫描所需的列,并自动调整压缩以最大限度地减少内存使用和GC压力。你可以调用sqlContext.uncacheTable(“tableName”)从内存中删除表。

SQLContext.setConf 的配置选项

属性名称默认含义
spark.sql.inMemoryColumnarStorage.compressedTrue设置为true时,Spark SQL将根据数据的统计信息自动为每列选择压缩编解码器。
spark.sql.inMemoryColumnarStorage.batchSize10000控制列式高速缓存的批量大小。较大的批量大小可以提高内存利用率和压缩率,但是在缓存数据时会面临OOM风险。
spark.sql.tungsten.enabledTrue当为true时,特定查询中的表达式求值的代码将会在运行时动态生成。对于一些拥有复杂表达式的查询,此选项可导致显著速度提升。然而,对于简单的查询,这个选项会减慢查询的执行
spark.sql.shuffle.partitions200配置shuffer的分区数

运行Spark SQL CLI

Spark SQL CLI是一种方便的工具,可以在本地模式下运行Hive Metastore服务,并从命令行执行查询输入。请注意,Spark SQL CLI无法与Thrift JDBC服务器通信。使用方法和原生的hive语句一样

要启动Spark SQL CLI,请在Spark目录中运行以下命令:

./bin/spark-sql

前提是需要hive-site.xml,core-site.xml和hdfs-site.xml拷贝到conf/下

资源下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值