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

来源:互联网 发布:如何查看淘宝客佣金 编辑:程序博客网 时间:2024/06/08 05:26

    • 说明
    • 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.SparkSessionimport org.apache.spark.sql.SparkSessionscala> 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@c45908cscala> 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.lengthres10: Int = 15scala> 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.lengthres12: Int = 15scala> 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.lengthres13: 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 javadef groupByKey[K](func: MapFunction[T, K], encoder: Encoder[K]): KeyValueGroupedDataset[K, T]// for scaladef 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 javadef map[U](func: MapFunction[T, U], encoder: Encoder[U]): Dataset[U]// for scaladef 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]
原创粉丝点击