数据分析引擎:Spark SQL

一、什么是Spark SQL?特点、数据模型DataFrame

1、是Spark的一个模块,用于处理结构化数据

spark Sql 就是把spark-core中rdd的数据进行结构化,使之能用sql语句的方式进行处理这些数据。

2、特点

  • 容易集成,已经被集成到了Spark中
  • 提供统一的数据访问方式:Oracle、MySQL、JSON、CSV等等 —> 数据模型DataFrame
  • 兼容Hive:在实际工作中,用得很少
  • 支持标准的JDBC、ODBC

3、数据模型DataFrame -----> 表

表(DataFrame) = 表结构(Schema) + 数据(RDD)
Schema可以用case class表示(样本类),还有其他方式
DataFrame从本质上,就是一个RDD,表现形式就是RDD

4、Demo:创建DataFrame:数据员工表emp.csv

Java版:
添加依赖

	<dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.11</artifactId>
            <version>2.3.2</version>
        </dependency>
    </dependencies>

(1)使用case class
既然spark SQL就是对rdd中的数据进行结构化,那我们是不是可以提前把数据进行规范,用对象将数据进行规范,最后在把转化为sparksql。

public class SparkSqlCase {
    public static void main(String[] args) {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR);
        Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);

        SparkConf conf = new SparkConf().setMaster("local").setAppName("SparkJavaSql");
        JavaSparkContext sc = new JavaSparkContext(conf);
        // 从这里可以看出,sparksql是作用在spark core上面。
        // 就是对rdd进一步的封装。
        SQLContext sqlc = new SQLContext(sc);

        
        // 既然spark SQL就是对rdd中的数据进行结构化,那我们是不是可以提前把数据进行
        // 规范,用对象将数据进行规范,最后在把转化为sparksql

        JavaRDD<Emp> map = sc.textFile("sparkSql/src/main/resources/emp.csv").map(new Function<String, Emp>() {
            @Override
            public Emp call(String s) throws Exception {
                // "empno":7369,"ename":"SMITH","job":"CLERK","mgr":"7902","hiredate":"1980/12/17"
                // ,"sal":800,"comm":"","deptno":20
                String[] split = s.split(",");
                Emp emp = new Emp();
                emp.setEmpno(Integer.parseInt(split[0]));
                emp.setEname(split[1]);
                emp.setJob(split[2]);
                emp.setMgr(Integer.parseInt(split[3]));
                emp.setHiredate(split[4]);
                emp.setSal(Integer.parseInt(split[5]));
                emp.setComm(split[6]);
                emp.setDeptno(Integer.parseInt(split[7]));
                return emp;
            }
        });

        Dataset<Row> dataFrame = sqlc.createDataFrame(map, Emp.class);

        dataFrame.createOrReplaceTempView("emp");

        sqlc.sql("select * from emp").show();

		sc.stop();
    }
}

(2)使用StructType
注意下面代码的编写思路,

public class SparkJavaSql {
    public static void main(String[] args) {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR);
        Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);

        SparkConf conf = new SparkConf().setMaster("local").setAppName("SparkJavaSql");
        JavaSparkContext sc = new JavaSparkContext(conf);
        // 从这里可以看出,sparksql是作用在spark core上面。
        // 就是对rdd进一步的封装。
        SQLContext sqlc = new SQLContext(sc);

        // "empno":7369,"ename":"SMITH","job":"CLERK","mgr":"7902","hiredate":"1980/12/17"
        //,"sal":800,"comm":"","deptno":20

        // 首先用spark core读出数据,并定义row行数据

        JavaRDD<Row> rowrdd = sc.textFile("sparkSql/src/main/resources/emp.csv").map(new Function<String, Row>() {
            @Override
            public Row call(String s) throws Exception {
                String[] split = s.split(",");
                // 通过工厂模式进行构造row
                return RowFactory.create(Integer.parseInt(split[0]),split[1],split[2],Integer.parseInt(split[3]),split[4],
                Integer.parseInt(split[5]),split[6],Integer.parseInt(split[7]));
            }
        });


        // 构建StructType,用于最后DataFrame元数据的描述
        List<StructField> listfields = new ArrayList<StructField>();
        listfields.add(DataTypes.createStructField("empno", DataTypes.IntegerType, false));
        listfields.add(DataTypes.createStructField("ename", DataTypes.StringType, false));
        listfields.add(DataTypes.createStructField("job", DataTypes.StringType, false));
        listfields.add(DataTypes.createStructField("mgr", DataTypes.IntegerType, false));
        listfields.add(DataTypes.createStructField("hiredate", DataTypes.StringType, false));
        listfields.add(DataTypes.createStructField("sal", DataTypes.IntegerType, false));
        listfields.add(DataTypes.createStructField("comm", DataTypes.StringType, true));
        listfields.add(DataTypes.createStructField("deptno", DataTypes.IntegerType, false));

        StructType structType = DataTypes.createStructType(listfields);
        // 将spark core读出的数据进行封装为spark sql
        // 主要分为两部分,定义行数据,定义列的类型。
        Dataset<Row> dataFrame = sqlc.createDataFrame(rowrdd, structType);

        dataFrame.createOrReplaceTempView("emp");

        sqlc.sql("select * from emp").show();
		sc.stop();


    }
}

(3)使用SparkSession.read.load函数-----> 最简单
上面的两种都是把rdd的数据进行转换,而sparksql也可以直接读取文件,直接转化为sparksql。

public class sparkSqlLoad {
    public static void main(String[] args) {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR);
        Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);

        SparkConf conf = new SparkConf().setMaster("local").setAppName("SparkJavaSql");
        JavaSparkContext sc = new JavaSparkContext(conf);
        // 从这里可以看出,sparksql是作用在spark core上面。
        // 就是对rdd进一步的封装。
        SQLContext sqlc = new SQLContext(sc);

        Dataset<Row> jsondata = sqlc.read().json("sparkSql/src/main/resources/emp.json");
        jsondata.createOrReplaceTempView("emp");
        sqlc.sql("select * from emp").write()
        .format("json").save("sparkSql/src/main/resources/emp1");
        sc.stop();
    }
}

连接Oracle数据库

5、视图

(1)局部视图:只能在当前会话中使用

df.createOrReplaceTempView("emp1");
spark.sql("select * from emp1 order by sal").show();

(2)全局视图:可以在不同的会话中使用

df.createOrReplaceGlobalTempView("emp2");
注意:全局视图是一个命名空间的global_temp
spark.sql("select * from global_temp.emp2 order by sal").show()

在一个新会话中,执行查询

spark.newSession.sql("select * from emp1 order by sal").show  ---> 错误
spark.newSession.sql("select * from global_temp.emp2 order by sal").show

二、Spark SQL的数据源

使用的就是spark sql直接读取文件。
1、Parquet文件:是Spark SQL默认的数据源,是一种列式存储的文件
支持表(DataFrame)的合并
还可以把其他格式的数据,转换成是Parquet文件
2、数据源JSON、CSV与在上面也都介绍过

3、数据源也可以是jdbc,进行连接Oracle、MySQL数据库

  • 将数据加载到Oracle上面。
public class SparkSqlOjdbc {
    public static void main(String[] args) throws Exception {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR);
        Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);

        SparkConf conf = new SparkConf().setMaster("local").setAppName("SparkJavaSql");
        JavaSparkContext sc = new JavaSparkContext(conf);
        // 从这里可以看出,sparksql是作用在spark core上面。
        // 就是对rdd进一步的封装。
        SQLContext sqlc = new SQLContext(sc);
        Dataset<Row> jsondata = sqlc.read().json("sparkSql/src/main/resources/emp.json");
        jsondata.createOrReplaceTempView("emp");

        Properties oracleprops = new Properties();
        oracleprops.setProperty("user","scott");
        oracleprops.setProperty("password","scott");
        oracleprops.setProperty("driver","oracle.jdbc.driver.OracleDriver");

        Dataset<Row> sql = sqlc.sql("select * from emp");

        sql.write().mode(SaveMode.Overwrite).jdbc("jdbc:oracle:thin:@192.168.92.135:1521/orcl"
                ,"scott.emp",oracleprops);
        sc.stop();
    }
}

  • 从Oracle上面加载数据
public class OracleInput {
    public static void main(String[] args) {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR);
        Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);

        SparkConf conf = new SparkConf().setMaster("local").setAppName("SparkJavaSql");
        JavaSparkContext sc = new JavaSparkContext(conf);
        // 从这里可以看出,sparksql是作用在spark core上面。
        // 就是对rdd进一步的封装。
        SQLContext sqlc = new SQLContext(sc);

        Properties oracleprops = new Properties();
        oracleprops.setProperty("user","scott");
        oracleprops.setProperty("password","scott");
        oracleprops.setProperty("driver","oracle.jdbc.driver.OracleDriver");
        Dataset<Row> jdbc = sqlc.read().jdbc("jdbc:oracle:thin:@192.168.92.135:1521/orcl", "scott.emp",
                oracleprops);
        jdbc.show();

		sc.stop();
    }
}

方式二:将上面sqlc改成下面代码
				Dataset<Row> jdbc = sqlc.read().format("jdbc")
                .option("url", "jdbc:oracle:thin:@192.168.92.135:1521/orcl")
                .option("dbtable", "scott.emp")
                .option("user", "scott")
                .option("password", "scott").load();



4、集成Hive

1、只需要将以下文件拷贝到$SPARK_HOME/conf的目录下,即可

$HIVE_HOME/conf/hive-site.xml
$HADOOP_CONF_DIR/core-site.xml
$HADOOP_CONF_DIR/hdfs-site.xml

2、重启Spark
3、启动Spark Shell,需要加载mysql的驱动

bin/spark-shell --master spark://bigdata111:7077 --jars /root/jars/mysql-connector-java-5.1.43-bin.jar

三、Spark SQL的优化

在性能调优这一块,我们主要做的是缓存数据,我们不在把数据注册成一个视图,而是注册成一张表registerTempTable(“tableName”),然后使用cacheTable(“tableName”),把这张表缓存下来,以便下次更快的调用数据。

1、从Oracle数据库中读取数据,生成DataFrame

上面已经提到,这里不再赘述

2、将DataFrame注册成表

df.registerTempTable("emp")

3、将表进行缓存

spark.sqlContext.cacheTable("emp")

4、清空缓存

spark.sqlContext.cacheTable("emp")
spark.sqlContext.clearCache

java demo code

public class OracleInput {
    public static void main(String[] args) {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR);
        Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF);

        SparkConf conf = new SparkConf().setMaster("local").setAppName("SparkJavaSql");
        JavaSparkContext sc = new JavaSparkContext(conf);
        // 从这里可以看出,sparksql是作用在spark core上面。
        // 就是对rdd进一步的封装。
        SQLContext sqlc = new SQLContext(sc);
        Dataset<Row> jdbc = sqlc.read().format("jdbc")
                .option("url", "jdbc:oracle:thin:@192.168.92.135:1521/orcl")
                .option("dbtable", "scott.emp")
                .option("user", "scott")
                .option("password", "scott").load();

        // 注册表
        sqlc.registerDataFrameAsTable(jdbc,"emp");
        // 缓存表
        sqlc.cacheTable("emp");
        // 清空缓存
        sqlc.clearCache();
        jdbc.show();
        
		sc.stop();

    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值