spark从入门到放弃三十一:Spark Sql (4)数据源Parquet

文章地址:http://www.haha174.top/article/details/253452
项目源码:https://github.com/haha174/spark.git
1.简介

parquet 是面向分析型业务的列示存储格式.
列式存储比行式存储有哪些优势呢
1.可以跳过不符合条件的数据,只读取需要的数据,降低IO的数量。
2.压缩编码格式可以降低磁盘空间。由于同一列的数据类型是一样的,可以使用更高效的压缩编码进一步节省孔家
3.只要读取需要的列,支持向量运算能够获取更好的扫描性能。

2.加载数据

查询用户数据中的用户姓名
下面给出java 示例

public class ParquetLoadData {
    public static void main(String[] args) {
        SparkConf conf=new SparkConf().setAppName("ParquetLoadData");
        JavaSparkContext sc=new JavaSparkContext(conf);
        SQLContext sqlContext=new SQLContext(sc);
        DataFrameReader reader=sqlContext.read();
        Dataset ds= reader.json("hdfs://hadoop:8020/data/users.parquet");
        ds.show();
        ds.registerTempTable("users");
        Dataset userName=sqlContext.sql("select name from users");
        //对查询出来的dataSet 进行操作,处理打印
        List<String> userNameRDD=userName.javaRDD().map(new Function<Row,String>() {
            public String call(Row o) throws Exception {
                return "name:"+o.getString(0);
            }
        }).collect();
        for(String usernmae:userNameRDD){
            System.out.println(usernmae);
        }
    }
}

下面给出scala 示例

 object ParquetLoadData {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("ParquetLoadData")
    val sc = new SparkContext(conf)
    val sqlContext = new SQLContext(sc)
    val reader = sqlContext.read
    val ds = reader.json("hdfs://hadoop:8020/data/users.parquet")
    ds.show()
    ds.registerTempTable("users")
    val userName = sqlContext.sql("select name from users")
    //对查询出来的dataSet 进行操作,处理打印
    val userNameRDD = userName.javaRDD.map(line=>"name:"+line.getString(0)).collect
    import scala.collection.JavaConversions._
    for (usernmae <- userNameRDD) {
      println(usernmae)
    }
  }
}

3.自动分区推断

表分区是一种非常常见的优化方式,比如hive中就提供了表分区的特性,在一个分区表中,不同分区的数据通常存在不同的目录,分区列的值通常包含在分区目录名中。sparkSql中的parquet 支持自动更具目录名推断出分区信息。
如果将tableName 传入到SqlContext.read.parquet 或者SqlContext.read.load()
那么spark 会根据目录结构自动推断出分区信息。
此外 分区的数据类型也是自动被推断出来的。目前Spark Sql 仅支持自动推断出数字类型和字符类型,有时用户也许不希望SparkSql 自动判断分区列的数据类型,此时只需要设置一个配置即可,spark.sql.sources.partitionColumnTypeInference.enabled.默认为true,即自动推断分区类型,设置为false,不会推断。

下面给出java 示例:

public class ParquetDiscovery {
    public static void main(String[] args) {
        SparkConf conf=new SparkConf().setAppName("ParquetDiscovery");
        JavaSparkContext sc=new JavaSparkContext(conf);
        SQLContext sqlContext=new SQLContext(sc);
        DataFrameReader reader=sqlContext.read();
        Dataset ds= reader.json("hdfs://hadoop:8020/data/gender=male/country=us/users.parquet");
        ds.printSchema();
        ds.show();
       sc.close();
    }
}

下面给出scala 示例:

object ParquetDiscovery {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("ParquetDiscovery")
    val sc = new SparkContext(conf)
    val sqlContext = new SQLContext(sc)
    val reader = sqlContext.read
    val ds = reader.json("hdfs://hadoop:8020/data/gender=male/country=us/users.parquet")
    ds.printSchema()
    ds.show()
  }
}

4.合并元数据

parquet 支持合并元数据,用户可以在一开始的时候就定于一个简单的元数据,然后随着业务的发展逐渐的往元数据中添加更多的列,这种情况下用户,可能会创建多个partition 文件,有着不同但却互相兼容的元数据.parquet自动判断这种情况,并且进行多个文件的元数据合并。
因为合并元数据是一个比较耗时的操作大多情况下不太需要,所以默认是关闭的
可以通过如下的方式打开。
1.读取Parquet 将数据源选项,mergeSchema 设置为true.
2.使用SQlContext.setconf()将spark.sql.parquet.mergeSchema参数设置为true
下面给出scala 示例:

object ParquetMergeScaema {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("ParquetMergeScaema")
    val sc = new SparkContext(conf)
    val sqlContext = new SQLContext(sc)
    val reader = sqlContext.read
  //创建一个dataSet  作为学生信息
    import sqlContext.implicits._
    val studentWithNameAndAge=Array(("leo",20),("jack","25")).toSeq
    val studentWithNameAndAgeDF=sc.parallelize(studentWithNameAndAge,2).toDF("name","age");
    studentWithNameAndAgeDF.write.save("hdfs://hadoop:8020/data/ParquetMergeScaemaTest1");


    //再创建一个
    val studentWithNameAndId=Array(("leo",20),("jack","25")).toSeq
    val studentWithNameAndIdDF=sc.parallelize(studentWithNameAndId,2).toDF("name","Id");
    studentWithNameAndIdDF.write.save("hdfs://hadoop:8020/data/ParquetMergeScaemaTest2.json");
    //合并两个dataset
    val student=sqlContext.read.option("mergeSchema","true").parquet("hdfs://hadoop:8020/data/ParquetMergeScaemaResult")
    student.printSchema()
    student.show()
  }
}

欢迎关注,更多福利

《spark从入门到放弃三十一:Spark Sql (4)数据源Parquet》 这里写图片描述

    原文作者:意浅离殇
    原文地址: https://www.jianshu.com/p/bad931f597f8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞