Spark SQL 之 DataFrame
来源:互联网 发布:云计算 搭建 openstack 编辑:程序博客网 时间:2024/05/02 00:00
概述(Overview)
Spark SQL是Spark的一个组件,用于结构化数据的计算。Spark SQL提供了一个称为DataFrames的编程抽象,DataFrames可以充当分布式SQL查询引擎。
DataFrames
DataFrame是一个分布式的数据集合,该数据集合以命名列的方式进行整合。DataFrame可以理解为关系数据库中的一张表,也可以理解为R/Python中的一个data frame。DataFrames可以通过多种数据构造,例如:结构化的数据文件、hive中的表、外部数据库、Spark计算过程中生成的RDD等。
DataFrame的API支持4种语言:Scala、Java、Python、R。
入口:SQLContext(Starting Point: SQLContext)
Spark SQL程序的主入口是SQLContext类或它的子类。创建一个基本的SQLContext,你只需要SparkContext,创建代码示例如下:
- Scala
val sc: SparkContext // An existing SparkContext.val sqlContext = new org.apache.spark.sql.SQLContext(sc)
- Java
JavaSparkContext sc = ...; // An existing JavaSparkContext.SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc);
除了基本的SQLContext,也可以创建HiveContext。SQLContext和HiveContext区别与联系为:
- SQLContext现在只支持SQL语法解析器(SQL-92语法)
- HiveContext现在支持SQL语法解析器和HiveSQL语法解析器,默认为HiveSQL语法解析器,用户可以通过配置切换成SQL语法解析器,来运行HiveSQL不支持的语法。
- 使用HiveContext可以使用Hive的UDF,读写Hive表数据等Hive操作。SQLContext不可以对Hive进行操作。
- Spark SQL未来的版本会不断丰富SQLContext的功能,做到SQLContext和HiveContext的功能容和,最终可能两者会统一成一个Context
HiveContext包装了Hive的依赖包,把HiveContext单独拿出来,可以在部署基本的Spark的时候就不需要Hive的依赖包,需要使用HiveContext时再把Hive的各种依赖包加进来。
SQL的解析器可以通过配置spark.sql.dialect参数进行配置。在SQLContext中只能使用Spark SQL提供的”sql“解析器。在HiveContext中默认解析器为”hiveql“,也支持”sql“解析器。
创建DataFrames(Creating DataFrames)
使用SQLContext,spark应用程序(Application)可以通过RDD、Hive表、JSON格式数据等数据源创建DataFrames。下面是基于JSON文件创建DataFrame的示例:
- Scala
val sc: SparkContext // An existing SparkContext.val sqlContext = new org.apache.spark.sql.SQLContext(sc)val df = sqlContext.read.json("examples/src/main/resources/people.json")// Displays the content of the DataFrame to stdoutdf.show()
- Java
JavaSparkContext sc = ...; // An existing JavaSparkContext.SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc);DataFrame df = sqlContext.read().json("examples/src/main/resources/people.json");// Displays the content of the DataFrame to stdoutdf.show();
DataFrame操作(DataFrame Operations)
DataFrames支持Scala、Java和Python的操作接口。下面是Scala和Java的几个操作示例:
- Scala
val sc: SparkContext // An existing SparkContext.val sqlContext = new org.apache.spark.sql.SQLContext(sc)// Create the DataFrameval df = sqlContext.read.json("examples/src/main/resources/people.json")// Show the content of the DataFramedf.show()// age name// null Michael// 30 Andy// 19 Justin// Print the schema in a tree formatdf.printSchema()// root// |-- age: long (nullable = true)// |-- name: string (nullable = true)// Select only the "name" columndf.select("name").show()// name// Michael// Andy// Justin// Select everybody, but increment the age by 1df.select(df("name"), df("age") + 1).show()// name (age + 1)// Michael null// Andy 31// Justin 20// Select people older than 21df.filter(df("age") > 21).show()// age name// 30 Andy// Count people by agedf.groupBy("age").count().show()// age count// null 1// 19 1// 30 1
- Java
JavaSparkContext sc // An existing SparkContext.SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc)// Create the DataFrameDataFrame df = sqlContext.read().json("examples/src/main/resources/people.json");// Show the content of the DataFramedf.show();// age name// null Michael// 30 Andy// 19 Justin// Print the schema in a tree formatdf.printSchema();// root// |-- age: long (nullable = true)// |-- name: string (nullable = true)// Select only the "name" columndf.select("name").show();// name// Michael// Andy// Justin// Select everybody, but increment the age by 1df.select(df.col("name"), df.col("age").plus(1)).show();// name (age + 1)// Michael null// Andy 31// Justin 20// Select people older than 21df.filter(df.col("age").gt(21)).show();// age name// 30 Andy// Count people by agedf.groupBy("age").count().show();// age count// null 1// 19 1// 30 1
详细的DataFrame API请参考 API Documentation。
除了简单列引用和表达式,DataFrames还有丰富的library,功能包括string操作、date操作、常见数学操作等。详细内容请参考 DataFrame Function Reference。
运行SQL查询程序(Running SQL Queries Programmatically)
Spark Application可以使用SQLContext的sql()方法执行SQL查询操作,sql()方法返回的查询结果为DataFrame格式。代码如下:
- Scala
val sqlContext = ... // An existing SQLContextval df = sqlContext.sql("SELECT * FROM table")
- Java
SQLContext sqlContext = ... // An existing SQLContextDataFrame df = sqlContext.sql("SELECT * FROM table")
DataFrames与RDDs的相互转换(Interoperating with RDDs)
Spark SQL支持两种RDDs转换为DataFrames的方式:
- 使用反射获取RDD内的Schema
- 当已知类的Schema的时候,使用这种基于反射的方法会让代码更加简洁而且效果也很好。
- 通过编程接口指定Schema
- 通过Spark SQL的接口创建RDD的Schema,这种方式会让代码比较冗长。
- 这种方法的好处是,在运行时才知道数据的列以及列的类型的情况下,可以动态生成Schema
使用反射获取Schema(Inferring the Schema Using Reflection)
Spark SQL支持将JavaBean的RDD自动转换成DataFrame。通过反射获取Bean的基本信息,依据Bean的信息定义Schema。当前Spark SQL版本(Spark 1.5.2)不支持嵌套的JavaBeans和复杂数据类型(如:List、Array)。创建一个实现Serializable接口包含所有属性getters和setters的类来创建一个JavaBean。通过调用createDataFrame并提供JavaBean的Class object,指定一个Schema给一个RDD。示例如下:
public static class Person implements Serializable { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}
// sc is an existing JavaSparkContext.SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc);// Load a text file and convert each line to a JavaBean.JavaRDD<Person> people = sc.textFile("examples/src/main/resources/people.txt").map( new Function<String, Person>() { public Person call(String line) throws Exception { String[] parts = line.split(","); Person person = new Person(); person.setName(parts[0]); person.setAge(Integer.parseInt(parts[1].trim())); return person; } });// Apply a schema to an RDD of JavaBeans and register it as a table.DataFrame schemaPeople = sqlContext.createDataFrame(people, Person.class);schemaPeople.registerTempTable("people");// SQL can be run over RDDs that have been registered as tables.DataFrame teenagers = sqlContext.sql("SELECT name 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 ordinal.List<String> teenagerNames = teenagers.javaRDD().map(new Function<Row, String>() { public String call(Row row) { return "Name: " + row.getString(0); }}).collect();
通过编程接口指定Schema(Programmatically Specifying the Schema)
当JavaBean不能被预先定义的时候,编程创建DataFrame分为三步:
- 从原来的RDD创建一个Row格式的RDD
- 创建与RDD中Rows结构匹配的StructType,通过该StructType创建表示RDD的Schema
- 通过SQLContext提供的createDataFrame方法创建DataFrame,方法参数为RDD的Schema
示例如下:
import org.apache.spark.api.java.function.Function;// Import factory methods provided by DataTypes.import org.apache.spark.sql.types.DataTypes;// Import StructType and StructFieldimport org.apache.spark.sql.types.StructType;import org.apache.spark.sql.types.StructField;// Import Row.import org.apache.spark.sql.Row;// Import RowFactory.import org.apache.spark.sql.RowFactory;// sc is an existing JavaSparkContext.SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc);// Load a text file and convert each line to a JavaBean.JavaRDD<String> people = sc.textFile("examples/src/main/resources/people.txt");// The schema is encoded in a stringString schemaString = "name age";// Generate the schema based on the string of schemaList<StructField> fields = new ArrayList<StructField>();for (String fieldName: schemaString.split(" ")) { fields.add(DataTypes.createStructField(fieldName, DataTypes.StringType, true));}StructType schema = DataTypes.createStructType(fields);// Convert records of the RDD (people) to Rows.JavaRDD<Row> rowRDD = people.map( new Function<String, Row>() { public Row call(String record) throws Exception { String[] fields = record.split(","); return RowFactory.create(fields[0], fields[1].trim()); } });// Apply the schema to the RDD.DataFrame peopleDataFrame = sqlContext.createDataFrame(rowRDD, schema);// Register the DataFrame as a table.peopleDataFrame.registerTempTable("people");// SQL can be run over RDDs that have been registered as tables.DataFrame results = sqlContext.sql("SELECT name FROM people");// 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 ordinal.List<String> names = results.javaRDD().map(new Function<Row, String>() { public String call(Row row) { return "Name: " + row.getString(0); }}).collect();
- Spark SQL 之 DataFrame
- Spark-Sql之DataFrame实战详解
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL 之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark-SQL之DataFrame操作大全
- Spark SQL中的DataFrame
- spark sql DataFrame操作
- Spark SQL与DataFrame
- spark sql dataframe操作
- view的刷新机制
- Android IPC机制(二)用Messenger进行进程间通信
- GTK+和C语言实现的哈夫曼文件压缩工具
- jQuery性能优化的28个建议
- Mac开发中,请问如何编码实现操作finder打开指定目录,谢谢!
- Spark SQL 之 DataFrame
- BZOJ2091: [Poi2010]The Minima Game
- 怎样在xcode中改变文件夹的颜色
- 自由运动的小球
- 【leetcode】94. Binary Tree Inorder Traversal【java】
- iOS 支付宝快捷支付 请求参数错误
- Qt移植字体解决方案:Android/ios/嵌入式通用
- 深度搜索算法C语言实现--以走迷宫为例
- 聊聊C语言的预编译指令include