sparkSQL
介绍
-
sparkSQL将SQL解析成spark任务来执行 , 使用更友好 .
-
Shark是基于Spark计算框架之上且兼容Hive语法的SQL执行引擎, 底层的计算采用了Spark , 性能比MapReduce的Hive大约快2倍之上 . 当数据全部加载到内存的情况下 , 性能几乎快10倍. Shark完全兼容了Hive , 但是Shark对于HIve的依赖性太强 , 不能和spark其他组件进行太好的集成 , 难以长远发展 .
Spark on Hive 和 Hive on Spark
-
hive on spark : 数据源来自hive表 , hive即负责存储有又负责sql的解析优化 , spark负责执行任务 .
-
spark on hive : 数据源在hive上 , hive只作为储存角色 , 执行任务的是spark , 负责sql的解析优化和执行 .
DataFrame
-
DataFrame 是一个分布式数据容器 , 与RDD类似 , 但是比较起来 DataFrame更加像mysql数据库的二维表格 , 数据的结构信息被称为schema . 和hive相似 ,DataFrame也支持嵌套数据类型(struct , array 和 map) . 从API上看 , DataFrame提供一套高层的关系操作 , 比RDD API要更加简单 , 友好 .
-
DataFrame的底层封装是RDD , 不过RDD的泛型是Row类型 .
SparkSQL的数据源
- SparkSQL的数据来源可以是JSON类型的字符串 , JDBC操作的数据库 , Parquet , hive , mysql , HDFS , SQL , amazonS3等等 . 额外还有AVRO , CSV , HBASE , elasticsearch 等 .
sparkSQL底层框架
sql语句解析后成为一批未被解决的逻辑计划 , 在经过分析得到分析后的逻辑计划 , 再进过一批优化规则转换成一批最佳优化的逻辑计划 , 再经过SparkPlanner的策略转化成一批物理计划 .随后经过消费模型转换成一个个的Spark任务执行 .
SQl结果sql解析器变成一个未被解决的逻辑计划 , 经过分析器变成一个被分析好的逻辑计划 , 经过优化后成为优化后的逻辑计划 , 在经过Spark的操作成为物理计划 , 经过一系列操作后最后变成RDD .
谓词下推
API
- json格式创建
package com.java;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SQLContext;
/**
* Created by Administrator on 2019/2/21.
*/
public class SparkSql_json {
public static void main(String[] args){
SparkConf conf = new SparkConf();
conf.setMaster("local").setAppName("josn_sql");
JavaSparkContext sparkContext = new JavaSparkContext(conf);
// sparkSQL操作对象
SQLContext sqlcont = new SQLContext(sparkContext);
// 设置json模式和json格式数据的位置 , 不能读取嵌套的json格式
DataFrame json = sqlcont.read().format("json").load("json");
// 查看数据
//json.show();
// 查看scheme信息
//json.printSchema();
// 原生API
// json.select("name","age").where(json.col("age").gt(18)).show(20); //age>18 . 打印20条信息
json.registerTempTable("jsonTable"); //将json数据加载到内存,注册成临时表 .
DataFrame sql = sqlcont.sql("select name , age from jsonTable where age > 18"); //从临时表操作数据 , 返回到一个结果集
sql.show();
// JavaRDD<Row> rowJavaRDD = sql.javaRDD(); //DataFram还可以直接转换成RDD , row类对象有getString(0),getString(1)...的方法来获取参数值.
sparkContext.stop();
}
}
- 非JSON格式反射创建
package com.java;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
/**
* Created by Administrator on 2019/2/21.
*/
public class sparkSql_txt {
public static void main(String[] args){
SparkConf conf = new SparkConf().setMaster("local").setAppName("txt_sql");
JavaSparkContext jsc = new JavaSparkContext(conf);
SQLContext sql = new SQLContext(jsc);
//读取数据
JavaRDD<String> stringJavaRDD = jsc.textFile("./person.txt");
JavaRDD<Person> pers = stringJavaRDD.map(new Function<String, Person>() {
private static final long serialVersionUID = 1L ;
@Override
public Person call(String s) throws Exception {
Person p = new Person();
p.setId(s.split(",")[0]);
p.setName(s.split(",")[1]);
p.setAge(Integer.parseInt(s.split(",")[2]));
return p;
}
});
// 传入Person.class , sqlContext通过反射创建DataFrame
DataFrame dataFrame = sql.createDataFrame(pers, Person.class);
dataFrame.show();
dataFrame.printSchema();
}
}
(person)
package com.java;
import java.io.Serializable;
/**
* Created by Administrator on 2019/2/21.
*/
public class Person implements Serializable{
private static final long setrialVersionUID = 1L;
private String id;
private String name;
private Integer age;
public static long getSetrialVersionUID() {
return setrialVersionUID;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
(非JSON格式动态创建)
package com.java;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.types.DataType;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
/**
* Created by Administrator on 2019/2/21.
*/
public class sparkSql_struct {
public static void main(String[] args){
SparkConf sc = new SparkConf().setMaster("local").setAppName("struct");
JavaSparkContext jsc = new JavaSparkContext(sc);
SQLContext sql = new SQLContext(jsc);
JavaRDD<String> stringJavaRDD = jsc.textFile("./person.txt");
//拿到数据
JavaRDD<Row> map = stringJavaRDD.map(new Function<String, Row>() {
@Override
public Row call(String s) throws Exception {
return RowFactory.create(
s.split(",")[0],
s.split(",")[1],
Integer.parseInt(s.split(",")[2])
);
}
});
// 拿到元数据信息
List<StructField> asList = Arrays.asList(
DataTypes.createStructField("id",DataTypes.StringType,true), //字段名 , 类型 , 值是否可以为空
DataTypes.createStructField("name",DataTypes.StringType,true),
DataTypes.createStructField("age",DataTypes.IntegerType,true)
);
StructType schema = DataTypes.createStructType(asList);
//生成DataFrame
DataFrame df = sql.createDataFrame(map, schema);
df.printSchema();
df.show();
jsc.stop();
}
}
- parquet格式创建
- parquet格式数据
// 与json模式操作相同 , 不同之处在于以下代码 DataFrame json = sqlcont.read().format("parquet").load("./parquet");
- JDBC
- parquet格式数据
package com.java;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.SQLContext;
import org.apache.spark.sql.SaveMode;
import java.util.HashMap;
import java.util.Properties;
/**
* Created by Administrator on 2019/2/21.
*/
public class sparkSQL_jdbc {
public static void main(String[] args){
SparkConf conf = new SparkConf();
conf.setMaster("local").setAppName("mysql");
//配置jion或者聚合操作shuffle数据时 分区的数量
conf.set("spark.sql.shuffle.partitions","1");
JavaSparkContext jsc = new JavaSparkContext(conf);
SQLContext sqlContext = new SQLContext(jsc);
HashMap<String, String> sqlContextHashMap = new HashMap<>();
sqlContextHashMap.put("url","jdbc:mysql://localhost:3306/diy"); //数据库IP地址/数据库
sqlContextHashMap.put("driver","com.mysql.jdbc.Driver");//驱动包
sqlContextHashMap.put("user","root");//账号
sqlContextHashMap.put("password","123456");//密码
sqlContextHashMap.put("dbtable","tb_user");//数据库的表
// jdbc模式读取数据库的数据
DataFrame jdbc = sqlContext.read().format("jdbc").options(sqlContextHashMap).load();
jdbc.show();
// 写到数据库
/**
* SaveMode:
* Overwrite:覆盖
* Append:追加
* ErrorIfExists:如果存在就报错
* Ignore:如果存在就忽略
*/
Properties p = new Properties();
p.setProperty("user","root");
p.setProperty("password","123456");
jdbc.write().mode(SaveMode.Append).jdbc("jdbc:mysql://localhost:3306/diy","result2",p);
}
}