spark dataframe实战(持续更新)

来源:互联网 发布:linux c 多线程编程 编辑:程序博客网 时间:2024/05/16 06:32

spark dataframe实战

说明:该文基于spark-2.0+

dataframe介绍

dataframe是dataset的行的集合。

Dataset是分布式数据集合。Dataset是Spark 1.6+中添加的一个新接口,它提供了RDD的很多优点。 (强类型化,使用强大的lambda函数的功能),以及Spark SQL优化执行引擎的优点。数据集可以从JVM对象构建,然后使用函数转换(map,flatMap,filter等)进行操作。数据集API可用于Scala和Java。
Python不支持数据集API。但是由于Python的动态特性,数据集API的许多优点已经可用(即,您可以通过自然的row.columnName名称来访问行的字段)。R的情况是相似的。

一个DataFrame是一个数据集组织成命名列。它在概念上等同于关系数据库中的表或R / Python中的(dataframe)数据框,但是在实现引擎层面有更多的优化。
DataFrame可以从各种各样的源构建,例如:结构化数据文件,Hive中的表,外部数据库或现有的RDD。DataFrame API可用于Scala,Java,Python和R.在Scala和Java中,DataFrame由行数据集表示。在Scala API中,DataFrame只是Dataset [Row]的类型别名。而在Java API中,用户需要使用Dataset 来表示一个DataFrame。

在整篇文档中,我们经常将Scala / Java数据集作为DataFrames。

sparkSession

在spark-2.0以后,引入了sparkSession来对资源进行管理。包括管理spark Context等。创建一个sparkSession的代码如下。

import org.apache.spark.sql.SparkSessionval spark = SparkSession.builder().appName("Spark SQL basic example").config("spark.some.config.option", "some-value").getOrCreate()// For implicit conversions like converting RDDs to DataFramesimport spark.implicits._

创建Dataframe

通过toDs来创建dataframe

val ds = Seq(1, 2, 3).toDS()

加载文件数据创建

dataframe可以加载各种格式的文件。
下面的例子会通过一个数据文件进行讲解,该文件的内容如下:

$ hadoop fs -cat /user/zxh/csvdata/csvdataid,name,subject,score1,n1,s1,102,n2,s2,203,n3,s3,303,n3,s1,204,n4,s2,405,n5,s3,506,n6,s1,607,n6,s2,408,n8,s3,908,n9,s1,309,n9,s1,209,n9,s2,70
  • 加载csv文件
    注意:spark是开始创建的sparkSession实体。
val spark = SparkSession.builder().appName("Spark SQL basic example").config("spark.some.config.option", "some-value").getOrCreate()import spark.implicits._val df = spark.read.csv("/user/hadoop/csvdata/csvdata")scala> val df = spark.read.option("header",true).csv("/user/hadoop/csvdata/csvdata")df: org.apache.spark.sql.DataFrame = [id: string, name: string ... 2 more fields]scala> df.show()+---+----+-------+-----+| id|name|subject|score|+---+----+-------+-----+|  1|  n1|     s1|   10||  2|  n2|     s2|   20||  3|  n3|     s3|   30||  3|  n3|     s1|   20||  4|  n4|     s2|   40||  5|  n5|     s3|   50||  6|  n6|     s1|   60||  7|  n6|     s2|   40||  8|  n8|     s3|   90||  8|  n9|     s1|   30||  9|  n9|     s1|   20||  9|  n9|     s2|   70|+---+----+-------+-----+
  • 加载json文件
$ hadoop fs -cat /user/zxh/jsondata/jsondata{ "name":"Yin", "address":{ "city":"Columbus", "state":"Ohio" }}scala> val df = spark.read.json("/user/zxh/jsondata/jsondata")df: org.apache.spark.sql.DataFrame = [address: struct<city: string, state: string>, name: string]scala> df.show()+---------------+----+|        address|name|+---------------+----+|[Columbus,Ohio]| Yin|+---------------+----+
  • 加载parquet文件
val peopleDF = spark.read.format("json").load("examples/src/main/resources/people.json")peopleDF.select("name", "age").write.format("parquet").save("namesAndAges.parquet")
val sqlDF = spark.sql("SELECT * FROM parquet.`examples/src/main/resources/users.parquet`")
val usersDF = spark.read.load("examples/src/main/resources/users.parquet")usersDF.select("name", "favorite_color").write.save("namesAndFavColors.parquet")

从JDBC加载数据

  • 通过JDBC读取数据
// Note: JDBC loading and saving can be achieved via either the load/save or jdbc methods// Loading data from a JDBC sourceval jdbcDF = spark.read  .format("jdbc")  .option("url", "jdbc:postgresql:dbserver")  .option("dbtable", "schema.tablename")  .option("user", "username")  .option("password", "password")  .load()val connectionProperties = new Properties()connectionProperties.put("user", "username")connectionProperties.put("password", "password")val jdbcDF2 = spark.read  .jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties)// Saving data to a JDBC sourcejdbcDF.write  .format("jdbc")  .option("url", "jdbc:postgresql:dbserver")  .option("dbtable", "schema.tablename")  .option("user", "username")  .option("password", "password")  .save()jdbcDF2.write  .jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties)// Specifying create table column data types on writejdbcDF.write  .option("createTableColumnTypes", "name CHAR(64), comments VARCHAR(1024)")  .jdbc("jdbc:postgresql:dbserver", "schema.tablename", connectionProperties)

操作Dataframe

  • 为dataframe设置新的字段名(列名)
scala> val newNames = Seq("id1", "name1", "score1")newNames: Seq[String] = List(id1, name1, score1)scala> val dfRenamed = df.toDF(newNames: _*)dfRenamed: org.apache.spark.sql.DataFrame = [id1: string, name1: string ... 1 more field]scala> dfRenamed.show()+---+-----+------+|id1|name1|score1|+---+-----+------+|  1|   n1|    10||  2|   n2|    20||  3|   n3|    30||  4|   n4|    40||  5|   n5|    50||  6|   n6|    60||  7|   n6|    60||  8|   n8|    60||  8|   n9|    60||  9|   n9|    60|+---+-----+------+
  • 添加一个新列:通过其他列的值来添加
    为了添加一列,我们可以使用withColumn函数来
scala> val df2 = df.withColumn("newscore", df("score")+50)df2: org.apache.spark.sql.DataFrame = [id: string, name: string ... 2 more fields]scala> df2.show()+---+----+-----+--------+| id|name|score|newscore|+---+----+-----+--------+|  1|  n1|   10|    60.0||  2|  n2|   20|    70.0||  3|  n3|   30|    80.0||  4|  n4|   40|    90.0||  5|  n5|   50|   100.0||  6|  n6|   60|   110.0||  7|  n6|   60|   110.0||  8|  n8|   60|   110.0||  8|  n9|   60|   110.0||  9|  n9|   60|   110.0|+---+----+-----+--------+
  • 条件去重
    通过select可以选择要返回的列,通过where函数可以对列进行筛选。在使用distinct函数去重。
scala> val df3 = df.select("name").where($"score">50).distinct()df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [name: string]scala> df3.show()+----+|name|+----+|  n8||  n9||  n6|+----+
  • 根据多列的值去重
    可以看到以下代码按name,score这两列的值进行去重。
scala> val df3 = df.select("name", "score").where($"score">50).distinct()df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [name: string, score: string]scala> df3.show()+----+-----+|name|score|+----+-----+|  n9|   60||  n8|   60||  n6|   60|+----+-----+