• Spark_总结四


    转载请标明出处http://www.cnblogs.com/haozhengfei/p/22bba3b1ef90cbfaf073eb44349c0757.html 


    Spark_总结四

    1.Spark SQL  

        Spark SQL 和 Hive on Spark 两者的区别?
            spark on hive:hive只是作为元数据存储的角色,解析,优化,执行都是spark做的    
            hive on spark: hive既作为存储的角色,又作为计算角色的一部分,hive将sql解析Spark任务,底层是Spark引擎hive2.0以后推荐使用Spark引擎,转化为Spark任务,hvie2.0以前都是转化为MR任务)
                
        Spark SQL 转化的过程(底层架构)
     
    【SQL/HQL-->解析器-->分析器-->优化器-->CostModel消耗模型(选出消耗最低的,就是效率最高的),最终将传入的SQL转换为RDD的计算】
     
    须知:
            若想使用SparkSQL必须创建SQLContext 必须是传入SparkContext 不能是SparkConf
     
    1.DataFrame与RDD的区别?   ||   什么是DataFrame?

    区别:
          Spark core是基于RDD的编程,Spark SQL是基于DataFrame的编程,DataFrame的底层就是封装的RDD,只不过DataFrame底层RDD的泛型是ROW(DataFrame <==> RDD<ROW>),另外,DataFrame中有对列的描述,但是RDD没有对列的描述。      
    What is DataFrame:
          DataFrame RDD 类似,DataFrame 是一个分布式数据容器,更像传统数据库的二维表格,除了数据以外,还掌握数据的结构信息(比如对列的描述), 即 schema。同时,与 Hive 类似,DataFrame 也支持嵌套数据类型(struct、 array 和 map)。 从 API 易用性的角度上 看,DataFrameAPI 提供的是一套高层的关系操作函数式的 RDDAPI 更加友好,门槛更低。 

    3.创建DataFrame的来源和方   ||   如何对DataFrame中封装的数据进行操作?

    3.1创建DataFrame的来源和方
     

    3.2如何对DataFrame中封装的数据进行操作?

       当我们的DataFrame构建好之后,里面封装了我们的数据,需要对数据进行操作即对DataFrame进行操作,有两种方式
    3.2.1   通过方法
            sqlContext.read()    返回DataFrameReader对象
            sqlContext.read().json("student.json")   读取一个json文件(这个json文件中的内容不能是嵌套的)读进来变成DataFrame,
            df.select("age").show(),如果没有show,这个程序就不会执行,这个show就类似与Spark中Action类型的算子,触发执行
     
    示例代码:
     1 package com.hzf.spark.exercise;
     2 
     3 import org.apache.spark.SparkConf;
     4 import org.apache.spark.api.java.JavaSparkContext;
     5 import org.apache.spark.sql.DataFrame;
     6 import org.apache.spark.sql.SQLContext;
     7 
     8 public class TestSparkSQL {
     9     public static void main(String[] args) {
    10         SparkConf conf = new SparkConf().setAppName("DataFrameOps").setMaster("local");
    11         
    12         JavaSparkContext sc = new JavaSparkContext(conf);
    13         SQLContext sqlContext = new SQLContext(sc);
    14         
    15         DataFrame df = sqlContext.read().json("people.json");
    16         
    17         
    18         /*
    19          * 操作DataFrame的第一种方式
    20          * */
    21         //类似 SQL的select from table;
    22         df.show();
    23         //desc table
    24         df.printSchema();
    25         
    26         //select age from table;
    27         df.select("age").show();
    28         //select name from table;
    29         df.select("name").show();
    30         //select name,age+10 from table;
    31         df.select(df.col("name"),df.col("age").plus(10)).show();
    32         //select * from table where age > 20
    33         df.filter(df.col("age").gt(20)).show();
    34     }
    35 }
    View Code
     
    result:
     
    3.2.2   通过注册临时表,传入SQL语句(推荐使用)
     
    示例代码:
     1 package com.hzf.spark.exercise;
     2 
     3 import org.apache.spark.SparkConf;
     4 import org.apache.spark.api.java.JavaSparkContext;
     5 import org.apache.spark.sql.DataFrame;
     6 import org.apache.spark.sql.SQLContext;
     7 
     8 public class TestSparkSQL01 {
     9     public static void main(String[] args) {
    10         SparkConf conf = new SparkConf().setAppName("DataFrameOps").setMaster("local");
    11         
    12         JavaSparkContext sc = new JavaSparkContext(conf);
    13         SQLContext sqlContext = new SQLContext(sc);
    14         
    15         DataFrame df = sqlContext.read().json("people.json");
    16         
    17         //将DataFrame中封装的数据注册为一张临时表,对临时表进行sql操作
    18         df.registerTempTable("people");
    19         DataFrame sql = sqlContext.sql("SELECT * FROM people WHERE age IS NOT NULL");
    20         sql.show(); 
    21     }
    22 }
    View Code
     
    result:
     
    3.3创建DataFrame的几种方式,来源(json,jsonRDD,parquet,非json格式,mysql)
     
    <1>读取Json格式文件-->DataFrame:Json 文件中不能有嵌套的格式
          加载json格式文件-->DataFrame有两种方式
               方式一:DataFrame df = sqlContext.read().format("json").load("people.json");
               方式二:DataFrame df = sqlContext.read().json("people.json");
     
    数据集:
     
    示例代码:
     1 package com.bjsxt.java.spark.sql.json;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 import org.apache.spark.SparkConf;
     7 import org.apache.spark.SparkContext;
     8 import org.apache.spark.api.java.JavaPairRDD;
     9 import org.apache.spark.api.java.JavaRDD;
    10 import org.apache.spark.api.java.JavaSparkContext;
    11 import org.apache.spark.api.java.function.Function;
    12 import org.apache.spark.api.java.function.PairFunction;
    13 import org.apache.spark.sql.DataFrame;
    14 import org.apache.spark.sql.Row;
    15 import org.apache.spark.sql.RowFactory;
    16 import org.apache.spark.sql.SQLContext;
    17 import org.apache.spark.sql.types.DataTypes;
    18 import org.apache.spark.sql.types.StructField;
    19 import org.apache.spark.sql.types.StructType;
    20 
    21 import scala.Tuple2;
    22 
    23 /**
    24  * JSON数据源
    25  * @author Administrator
    26  *
    27  */
    28 public class JSONDataSource {
    29 
    30     public static void main(String[] args) {
    31         SparkConf conf = new SparkConf()
    32                 .setAppName("JSONDataSource")
    33 //                .set("spark.default.parallelism", "100")
    34                 .setMaster("local");  
    35         JavaSparkContext sc = new JavaSparkContext(conf);
    36         SQLContext sqlContext = new SQLContext(sc);
    37         
    38         DataFrame studentScoresDF = sqlContext.read().json("student.json");  
    39         
    40         studentScoresDF.registerTempTable("student_scores");
    41         DataFrame goodStudentScoresDF = sqlContext.sql(
    42                 "select name,count(score) from student_scores where score>=80 group by name");
    43         
    44         List<String> goodStudentNames = goodStudentScoresDF.javaRDD().map(new Function<Row, String>() {
    45                     private static final long serialVersionUID = 1L;
    46                     
    47                     @Override
    48                     public String call(Row row) throws Exception {
    49                         return row.getString(0);
    50                     }
    51                     
    52         }).collect();
    53         
    54         for(String str: goodStudentNames){
    55             System.out.println(str);
    56         }
    57     }
    58 }
    View Code
     
    result:
     
    <2>jsonRDD-->DataFrame
     
    <3>读取Parquet格式文件-->DataFrame自动推测分区,合并 Schema。
    经验:将Spark中的文本转换为Parquet以提升性能

        parquet是一个基于列的存储格式,列式存储布局可以加速查询,因为它只检查所有需要的列并对它们的值执行计算,因此只读取一个数据文件或表的小部分数据。Parquet 还支持灵活的压缩选项,因此可以显著减少磁盘上的存储

       如果在 HDFS 上拥有基于文本的数据文件或表,而且正在使用 Spark SQL 对它们执行查询,那么强烈推荐将文本数据文件转换为 Parquet 数据文件,以实现性能和存储收益。当然,转换需要时间,但查询性能的提升在某些情况下可能达到 30 倍或更高,存储的节省可高达 75%!

    parquet的压缩比高,将一个普通的文本转化为parquet格式,如何去转?
           val lineRDD = sc.textFile()
           DF.save(parquet) //将RDD转化为DF
    parquet操作示例
       是否指定format--若存储时,指定format为json格式,那么则生成json格式文件,否则不指定format,默认文件以parquet形式进行存储 
    测试一:指定format为json格式,存储在本地
    测试数据:   top.txt
    测试代码

    测试结果
     
     
    测试二:不指定format,那么文件默认以parquet形式进行存储,存储在本地
     
    测试数据:   people.json
    测试代码
    测试结果
     
    测试三:读取本地parquet存储格式的文件
    测试代码

    测试结果
     
    测试四:读取hdfs上parquet形式的文件
    测试代码
    测试结果
     
    <4> RDD(非json格式变成DataFrame)
    读取txt 文件-->DataFrame从 txt 文件读取,然后转为 RDD,最后转为 DataFrame
                                           RDD 转为 DataFrame 有两种方式
                            (1)反射机制
                                  注意点:自定义的类一定要是 public,并且要实现序列化接口 Serializable
                                                 取数据的时候,在 JavaAPI 中会有顺序问题(因为 DataFrame 转为 RDD<Row> 的时候,会进行一次字典排序改变 Row 的位置,而Scala 的 API 则没有这个问题)
                            (2)动态创建 Schema,先将 RDD 中的每一行类型变 为 RDD<Row> 类型,然后创建 DataFrame 的元数据-->构建 StructType,用于最后 DataFrame 元数据的描述,基于现有的 StructType 以及 RDD<Row> 来构造 DataFrame。(如果列的信息比较长可以存到数据库里) 
    <4.1>反射机制
    数据
    示例代码:
    自定义类
     1 package com.bjsxt.java.spark.sql.createdf;
     2 
     3 import java.util.List;
     4 
     5 import org.apache.spark.SparkConf;
     6 import org.apache.spark.api.java.JavaRDD;
     7 import org.apache.spark.api.java.JavaSparkContext;
     8 import org.apache.spark.api.java.function.Function;
     9 import org.apache.spark.sql.DataFrame;
    10 import org.apache.spark.sql.Row;
    11 import org.apache.spark.sql.SQLContext;
    12 
    13 /**
    14  * 使用反射的方式将RDD转换成为DataFrame
    15  * 1、自定义的类必须是public
    16  * 2、自定义的类必须是可序列化的
    17  * 3、RDD转成DataFrame的时候,他会根据自定义类中的字段名进行排序。
    18  * @author zfg
    19  *
    20  */
    21 
    22 public class RDD2DataFrameByReflection {
    23 
    24     public static void main(String[] args) {
    25         SparkConf conf = new SparkConf().setMaster("local").setAppName("RDD2DataFrameByReflection");
    26         JavaSparkContext sc = new JavaSparkContext(conf);
    27         SQLContext sqlcontext = new SQLContext(sc);
    28         
    29         JavaRDD<String> lines = sc.textFile("Peoples.txt");
    30         JavaRDD<Person> personsRdd = lines.map(new Function<String, Person>() {
    31             
    32             private static final long serialVersionUID = 1L;
    33 
    34             @Override
    35             public Person call(String line) throws Exception {
    36                 String[] split = line.split(",");
    37                 Person p = new Person();
    38                 p.setId(Integer.valueOf(split[0].trim()));
    39                 p.setName(split[1]);
    40                 p.setAge(Integer.valueOf(split[2].trim()));
    41                 return p;
    42             }
    43         });
    44         
    45         //传入进去Person.class的时候,sqlContext是通过反射的方式创建DataFrame
    46         //在底层通过反射的方式或得Person的所有field,结合RDD本身,就生成了DataFrame
    47         DataFrame df = sqlcontext.createDataFrame(personsRdd, Person.class);
    48      
    49         //命名table的名字为person
    50         df.registerTempTable("personTable");
    51         
    52         DataFrame resultDataFrame = sqlcontext.sql("select * from personTable where age > 7");
    53         resultDataFrame.show();
    54         
    55          //将df转成rdd
    56         JavaRDD<Row> resultRDD = resultDataFrame.javaRDD();
    57         JavaRDD<Person> result = resultRDD.map(new Function<Row, Person>() {
    58             
    59             private static final long serialVersionUID = 1L;
    60 
    61             @Override
    62             public Person call(Row row) throws Exception {
    63                  Person p = new Person();
    64                  p.setAge(row.getInt(0));
    65                  p.setId(row.getInt(1));
    66                  p.setName(row.getString(2));
    67                 return p;
    68             }
    69         });
    70         
    71          List<Person> personList = result.collect();
    72          
    73          for (Person person : personList) {
    74             System.out.println(person.toString());
    75         } 
    76     }
    77 }
    View Code
     
     
    result:

    <4.2>动态创建Schema方式
    数据
     
    示例代码:
     1 package com.bjsxt.java.spark.sql.createdf;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 import org.apache.spark.SparkConf;
     7 import org.apache.spark.api.java.JavaRDD;
     8 import org.apache.spark.api.java.JavaSparkContext;
     9 import org.apache.spark.api.java.function.Function;
    10 import org.apache.spark.sql.DataFrame;
    11 import org.apache.spark.sql.Row;
    12 import org.apache.spark.sql.RowFactory;
    13 import org.apache.spark.sql.SQLContext;
    14 import org.apache.spark.sql.types.DataTypes;
    15 import org.apache.spark.sql.types.StructField;
    16 import org.apache.spark.sql.types.StructType;
    17 
    18 
    19 public class RDD2DataFrameByProgrammatically {
    20     public static void main(String[] args) {
    21         SparkConf conf = new SparkConf().setMaster("local").setAppName("RDD2DataFrameByReflection");
    22         JavaSparkContext sc = new JavaSparkContext(conf);
    23         SQLContext sqlcontext = new SQLContext(sc);
    24         /**
    25          * 在RDD的基础上创建类型为Row的RDD
    26          */
    27         JavaRDD<String> lines = sc.textFile("Peoples.txt");
    28         JavaRDD<Row> rowRDD = lines.map(new Function<String, Row>() {
    29             
    30             private static final long serialVersionUID = 1L;
    31 
    32             @Override
    33             public Row call(String line) throws Exception {
    34                 String[] split = line.split(",");
    35                 return RowFactory.create(Integer.valueOf(split[0]),split[1],Integer.valueOf(split[2]));
    36             }
    37         });
    38         
    39         /**
    40          * 动态构造DataFrame的元数据,一般而言,有多少列以及每列的具体类型可能来自于Json,也可能来自于DB
    41          */
    42         ArrayList<StructField> structFields = new ArrayList<StructField>();
    43         structFields.add(DataTypes.createStructField("id", DataTypes.IntegerType, true));
    44         structFields.add(DataTypes.createStructField("name", DataTypes.StringType, true));
    45         structFields.add(DataTypes.createStructField("age", DataTypes.IntegerType, true));
    46         //构建StructType,用于最后DataFrame元数据的描述
    47         StructType schema = DataTypes.createStructType(structFields);
    48         
    49         /**
    50          * 基于已有的MetaData以及RDD<Row> 来构造DataFrame
    51          */
    52         DataFrame df = sqlcontext.createDataFrame(rowRDD, schema);
    53         
    54         /**
    55          *注册成为临时表以供后续的SQL操作查询
    56          */
    57         df.registerTempTable("persons");
    58         
    59         /**
    60          * 进行数据的多维度分析
    61          */
    62         DataFrame result = sqlcontext.sql("select * from persons where age > 7");
    63         result.show();
    64 
    65         /**
    66          * 对结果进行处理,包括由DataFrame转换成为RDD<Row>
    67          */
    68          List<Row> listRow = result.javaRDD().collect();
    69          for (Row row : listRow) {
    70             System.out.println(row);
    71         }
    72     }
    73 }
    View Code
     
    result:

    <5> 读取MySql 中表里的数据-->DataFrame
           Spark Build-in内置支持的json jdbc mysql,hive...如果数据库支持jdbc连接,Spark 就可以基于这个数据库尽行数据的处理
     
    示例代码:
     1 package com.bjsxt.java.spark.sql.jdbc;
     2 
     3 import org.apache.spark.SparkConf;
     4 import org.apache.spark.api.java.JavaSparkContext;
     5 import org.apache.spark.sql.DataFrame;
     6 import org.apache.spark.sql.DataFrameReader;
     7 import org.apache.spark.sql.SQLContext;
     8 
     9 /**
    10  * JDBC数据源
    11  * 
    12  * @author Administrator
    13  *
    14  */
    15 public class JDBCDataSource {
    16 
    17     public static void main(String[] args) {
    18         SparkConf conf = new SparkConf().setAppName("JDBCDataSource").setMaster("local");
    19         JavaSparkContext sc = new JavaSparkContext(conf);
    20         SQLContext sqlContext = new SQLContext(sc);
    21         
    22         // 方法1、分别将mysql中两张表的数据加载为DataFrame
    23         /*
    24          * Map<String, String> options = new HashMap<String, String>();
    25          * options.put("url", "jdbc:mysql://hadoop1:3306/testdb");
    26          * options.put("driver", "com.mysql.jdbc.Driver"); 
    27          * options.put("user","spark");
    28          * options.put("password", "spark2016");
    29          
    30          * options.put("dbtable", "student_info"); 
    31          * DataFrame studentInfosDF = sqlContext.read().format("jdbc").options(options).load();
    32          * options.put("dbtable", "student_score"); 
    33          * DataFrame studentScoresDF = sqlContext.read().format("jdbc") .options(options).load();
    34          */
    35         // 方法2、分别将mysql中两张表的数据加载为DataFrame
    36         DataFrameReader reader = sqlContext.read().format("jdbc");
    37         reader.option("url", "jdbc:mysql://node4:3306/testdb");
    38         reader.option("driver", "com.mysql.jdbc.Driver");
    39         reader.option("user", "root");
    40         reader.option("password", "123");
    41         
    42         reader.option("dbtable", "student_info");
    43         DataFrame studentInfosDF = reader.load();
    44         reader.option("dbtable", "student_score");
    45         DataFrame studentScoresDF = reader.load();
    46         
    47         // 将两个DataFrame转换为JavaPairRDD,执行join操作
    48         studentInfosDF.registerTempTable("studentInfos");
    49         studentScoresDF.registerTempTable("studentScores");
    50         
    51         String sql = "SELECT studentInfos.name,age,score "
    52                 + "        FROM studentInfos JOIN studentScores"
    53                 + "         ON (studentScores.name = studentInfos.name)"
    54                 + "     WHERE studentScores.score > 80";
    55         
    56         DataFrame sql2 = sqlContext.sql(sql);
    57         sql2.show();
    58     }
    59 }
    View Code

    result:

    4. 如何将DataFrame中的值写入到外部存储中去?

    存储模式SaveMode.Overwrite || Ignore || Append   ||   ErrorifExit)
    <1> 读取本地json格式文件,并以json形式写入到hdfs(不指定format,默认是parquet)
    测试代码

    测试结果
     
    补充:
    1.什么是下推过滤器?
           在join之前过滤,而不是join之后进行过滤
     
    2.select * from table 在SparkSQL和Hive on MR中的区别?
          SparkSQL 中 select * from table 在spark中是要具体执行spark任务的,而在 Hive on MR 中 select * from table直接读取数据,所以SparkSQL 中执行select * from不一定比Hive on MR中的快
     
    3.如何将一个DataFrame变成一个RDD?
        JavaRDD<ROW> rdd = resultFrame.javaRDD()
     

    5.整合Spark和Hive?

        6.1Spark 目录下面的 conf 下放一个配置文件 hive-site.xml 文件。
        6.2在 hive 的服务端启动 MetaStore Server因为 HiveContext 会用到 metastore 服务。(在 Spark-shell 里面使用 HiveContext 的时候,要记住导入 HiveContext)】(hive --service metastore)
        6.3启动hdfs【因为hive的数据是存在hdfs上的Spark集群(start-all.sh spark-start-all.sh)
        6.4进入Spark shell,测试Spark 和 Hive是否整合成功
    1. scala>import org.apache.spark.sql.hive.HiveContext
    2. scala>val hiveContext =newHiveContext(sc)
    3. scala>hiveContext.sql("show tables").show
        6.5整合测试(详见Spark_some配置)注意!将代码提交到Spark集群上运行时,需要将hdfs-site.xml拷贝到SPARK_HOME/conf下

    6.SqlContext和HiveContext的关系?

           SQLcontext 是 HiveContext 的父类
           在集群中运行的时候用 HiveContext,可以基于 Hive 来操作 Hive 表,对源数据进行CRUD的操作。 
     
     
     
  • 相关阅读:
    让sublime text3支持Vue语法高亮显示
    让sublime text3支持Vue语法高亮显示
    flutter中使用redux之多界面互动
    flutter中使用redux之多界面互动
    flutter中使用redux之多界面互动
    flutter中使用redux之多界面互动
    普通视频转高清:10个基于深度学习的超分辨率神经网络
    javaweb学习总结(二十七)——jsp简单标签开发案例和打包
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/haozhengfei/p/22bba3b1ef90cbfaf073eb44349c0757.html
Copyright © 2020-2023  润新知