通过例子学习spark dataframe -- transformations函数(1)

    • 说明
    • dataframe类型化函数Typed transformations
      • coalesce
      • dropDuplicates
      • where
      • sort
      • select
      • distinct
      • intersect
      • union
      • limit
      • groupByKey
      • map
      • mapPartitions

说明

transformations函数分为两类:
* Typed transformations
这类函数的返回值一般都是dataset,也就是说不会改变原来的数据集的类型。
* Untyped transformations
这类函数的返回值,会根据不同的函数返回不同的类型。

本文讲解的是第一类的函数,也就是说返回的类型基本上是相同的都是dataset。
本文的所有例子,都是基于spark-2.1进行操作。

本文的所有例子,都是基于以下简单的csv数据集进行讲解:

scala> import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.SparkSession

scala> val spark = SparkSession.builder().appName("Spark SQL basic example").config("spark.some.config.option", "some-value").getOrCreate()
17/11/28 07:08:49 WARN SparkSession$Builder: Using an existing SparkSession; some configuration may not take effect.
spark: org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@c45908c

scala> import spark.implicits._
import spark.implicits._

scala> val df = spark.read.format("csv").option("header", true).load("/user/hadoop/csvdata/csvdata")
df: org.apache.spark.sql.DataFrame = [id: string, name: string ... 1 more field]

scala> df.show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  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|
+---+----+-----+

dataframe类型化函数(Typed transformations)

说明:这些函数最后返回的都是一个类型,也就是Dataset[T]。这类dataframe是dataset的行集合。

coalesce

  • 功能
    若你需要更少的分区,可以通过该函数来得到具有确定分区数的新的数据集。如果请求更多的分区,它将保持在当前的分区数量。类似于在RDD上定义的合并,该操作导致狭窄的依赖性,例如,如果你从1000个分区转到100个分区,那么就不会有shuffle,而是100个新分区中的每一个都会声称当前分区有10个。
    但是,如果您正在进行激烈的合并,例如到numPartitions = 1,这可能会导致你的计算发生在比你喜欢的节点更少的节点上(例如numPartitions = 1的情况下是一个节点)。为了避免这种情况,您可以调用repartition。这将增加一个shuffle步骤,但意味着当前的上游分区将并行执行(无论当前分区是什么)。

  • 原型

def coalesce(numPartitions: Int): Dataset[T] 
  • 例子1
    从下面的代码可以看出,新的dataframe分区数据减少了。
scala> val df3 = spark.read.format("csv").option("header", false).load("/warehouse/spark/testdata/")
df3: org.apache.spark.sql.DataFrame = [_c0: string, _c1: string ... 34 more fields]

scala> df3.rdd.partitions.length
res10: Int = 15

scala> df3.coalesce(10)
res11: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [_c0: string, _c1: string ... 34 more fields]

scala> df3.rdd.partitions.length
res12: Int = 15

scala> val df4 = df3.coalesce(10)
df4: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [_c0: string, _c1: string ... 34 more fields]

scala> df4.rdd.partitions.length
res13: Int = 10

dropDuplicates

  • 功能
    按照某个字段去重。

  • 原型

def dropDuplicates(colNames: Array[String]): Dataset[T] 
def dropDuplicates(col1: String, cols: String*): Dataset[T] 
def dropDuplicates(colNames: Seq[String]): Dataset[T] 

// 按所有字段去重
def dropDuplicates(): Dataset[T] 
  • 例子1
scala> df.sort().dropDuplicates("id").show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  7|  n6|   60|
|  1|  n1|   10|
|  6|  n6|   60|
|  4|  n4|   40|
|  8|  n8|   60|
|  3|  n3|   30|
|  2|  n2|   20|
|  5|  n5|   50|
|  9|  n9|   60|
+---+----+-----+

where

  • 功能
    对dataframe满足条件的列进行过滤。

  • 原型
    where的原型有两种:

def where(conditionExpr: String): Dataset[T] 
def where(condition: Column): Dataset[T] 

通过以上原型,可以看出,一种是直接添加字符串,一种是通过列来对数据进行过滤。

  • 例子1
scala> val df3 = df.select("id", "name").where($"score">50).distinct()
df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string]

scala> df3.show()
+---+----+                                                                      
| id|name|
+---+----+
|  7|  n6|
|  9|  n9|
|  6|  n6|
|  8|  n8|
|  8|  n9|
+---+----+

以上例子也可以写成下面的形式,结果是一样的:

val df3 = df.select("name", "score").where("score>50").distinct()
  • 例子2
    添加多个条件进行过滤。
scala> val df3 = df.select("name", "score").where("score>10 and score<50").distinct()
df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [name: string, score: string]

scala> df3.show()
+----+-----+
|name|score|
+----+-----+
|  n4|   40|
|  n2|   20|
|  n3|   30|
+----+-----+

也可以写成以下形式:

val df3 = df.select("name", "score").where($"score">10 && $"score" > 50).distinct()

sort

  • 功能
    可以根据特定的列或排序表达式进行排序。同时还可以指定按升序还是降序排序。
    注意:默认情况下,sort是按升序排列的。

  • 函数原型

def sort(sortExprs: Column*): Dataset[T] 
def sort(sortCol: String, sortCols: String*): Dataset[T]
  • 例子1

按score降序排列以下记录。

scala> val df3 = df.select("id","name", "score").where("score<50").sort($"score".desc)
df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string ... 1 more field]

// 可以看到记录已按score成降序排列
scala> df3.show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  4|  n4|   40|
|  3|  n3|   30|
|  2|  n2|   20|
|  1|  n1|   10|
+---+----+-----+
  • 例子2
    按两列进行排序。
scala> val df3 = df.select("id","name", "score").where("score>50").sort($"id".desc, $"score".desc)
df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string ... 1 more field]

scala> df3.show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  9|  n9|   60|
|  8|  n9|   60|
|  8|  n8|   60|
|  7|  n6|   60|
|  6|  n6|   60|
+---+----+-----+

select

  • 功能
    选择需要返回的列,并可以对列进行一些操作。

  • 原型

def select[U1, U2, U3](c1: TypedColumn[T, U1], c2: TypedColumn[T, U2], c3: TypedColumn[T, U3]): Dataset[(U1, U2, U3)] 
def select[U1, U2](c1: TypedColumn[T, U1], c2: TypedColumn[T, U2]): Dataset[(U1, U2)] 
def select[U1](c1: TypedColumn[T, U1]): Dataset[U1] 
  • 例子1:选取列
scala> val df3 = df.select("id", "name").limit(2)
df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string]

scala> df3.show()
+---+----+
| id|name|
+---+----+
|  1|  n1|
|  2|  n2|
+---+----+
  • 例子2:选取列时,为列选取别名
scala> val df2 = df.select($"id" as "id2")
df2: org.apache.spark.sql.DataFrame = [id2: string]
  • 例子3:选取列时,改变列的值和列的数据类型
scala> val df4 = df.select($"id", expr("score+10").as[Double] as "newscore").limit(2)
df4: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, newscore: double]

scala> df4.show()
+---+--------+
| id|newscore|
+---+--------+
|  1|    20.0|
|  2|    30.0|
+---+--------+

distinct

  • 功能说明
    对数据集去重。

  • 函数原型

def distinct(): Dataset[T] 
  • 例子1
scala> df.select("id").distinct().sort("id").collect()
res5: Array[org.apache.spark.sql.Row] = Array([1], [2], [3], [4], [5], [6], [7], [8], [9])

intersect

  • 功能说明
    对两个数据集取交集,返回两个数据集共有的行。

  • 函数原型

def intersect(other: Dataset[T]): Dataset[T] 
  • 例子1
scala> val df2 = df.where($"score">50)
df2: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string ... 1 more field]

scala> df2.show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  6|  n6|   60|
|  7|  n6|   60|
|  8|  n8|   60|
|  8|  n9|   60|
|  9|  n9|   60|
+---+----+-----+

scala> val df3 = df.intersect(df2)
df3: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string ... 1 more field]

scala> df3.sort("id").show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  6|  n6|   60|
|  7|  n6|   60|
|  8|  n8|   60|
|  8|  n9|   60|
|  9|  n9|   60|
+---+----+-----+

union

  • 函数功能
    合并两个数据集。注意:合并的两个数据集(dataset)的列数必须相同,否则会报错。

  • 函数原型

def union(other: Dataset[T]): Dataset[T] 
  • 例子1
scala> val df4 = df.union(df3)
df4: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string ... 1 more field]

scala> df4.show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  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|
|  8|  n8|   60|
|  7|  n6|   60|
|  9|  n9|   60|
|  6|  n6|   60|
|  8|  n9|   60|
+---+----+-----+

limit

  • 功能
    返回数据集的前n行,不同于head的是:limit返回的是一个dataset,而head返回的是array。

  • 函数原型

def limit(n: Int): Dataset[T]
  • 例子1
scala> val df2 = df.limit(2)
df2: org.apache.spark.sql.Dataset[org.apache.spark.sql.Row] = [id: string, name: string ... 1 more field]

scala> df2.show()
+---+----+-----+
| id|name|score|
+---+----+-----+
|  1|  n1|   10|
|  2|  n2|   20|
+---+----+-----+

groupByKey

  • 功能
    根据特定的函数对数据进行聚合。然后返回一个KeyValueGroupedDataset类型的dataset。
    注意:该函数会通过HashPartitioner的方式把数据重按key的值新分区,把相同key的值分到同一分区中,这样在大部分的情况下会导致shuffle。完成这个过程后,会在本地的分区上执行aggregation。

  • 函数原型

// for java
def groupByKey[K](func: MapFunction[T, K], encoder: Encoder[K]): KeyValueGroupedDataset[K, T]
// for scala
def groupByKey[K](func: (T) => K)(implicit arg0: Encoder[K]): KeyValueGroupedDataset[K, T]
  • 例子1
scala> df.groupByKey(l=>l.getString(0)).count.show()
+-----+--------+
|value|count(1)|
+-----+--------+
|    7|       1|
|    1|       1|
|    6|       1|
|    4|       1|
|    8|       2|
|    3|       1|
|    2|       1|
|    5|       1|
|    9|       1|
+-----+--------+
  • 例子2
scala> df.groupByKey(r=>r.getString(0)).mapValues(r=>r.getString(1)).reduceGroups( (id, name) => (id+","+name)).show()
+-----+----------------------------------+
|value|ReduceAggregator(java.lang.String)|
+-----+----------------------------------+
|    7|                                n6|
|    1|                                n1|
|    6|                                n6|
|    4|                                n4|
|    8|                             n8,n9|
|    3|                                n3|
|    2|                                n2|
|    5|                                n5|
|    9|                                n9|
+-----+----------------------------------+

map

  • 功能
    对数据集上的每一行使用函数func进行处理,并返回一个新的dataset。
    注意:dataframe的map和rdd的不同,这里需要返回一个新的dataset。

  • 函数原型

// for java
def map[U](func: MapFunction[T, U], encoder: Encoder[U]): Dataset[U]
// for scala
def map[U](func: (T) ⇒ U)(implicit arg0: Encoder[U]): Dataset[U]
  • 例子1
scala> val df2 = df.map(r=>(r.getString(0),r.getString(1))).limit(2)
df2: org.apache.spark.sql.Dataset[(String, String)] = [_1: string, _2: string]

scala> df2.show()
+---+---+
| _1| _2|
+---+---+
|  1| n1|
|  2| n2|
+---+---+

mapPartitions

  • 功能
    在数据集的每个分区上使用函数func

  • 函数原型

def mapPartitions[U](f: MapPartitionsFunction[T, U], encoder: Encoder[U]): Dataset[U]
def mapPartitions[U](func: (Iterator[T]) ⇒ Iterator[U])(implicit arg0: Encoder[U]): Dataset[U]

你可能感兴趣的:(spark,大数据处理)