版本说明:Spark-2.3.0

使用Spark SQL在对数据进行处理的过程中,可能会遇到对一列数据拆分为多列,或者把多列数据合并为一列。这里记录一下目前想到的对DataFrame列数据进行合并和拆分的几种方法。

1 DataFrame列数据的合并
例如:我们有如下数据,想要将三列数据合并为一列,并以“,”分割

+----+---+-----------+
|name|age| phone|
+----+---+-----------+
|Ming| ||
|hong| ||
| zhi| ||
+----+---+-----------+

1.1 使用map方法重写

使用map方法重写就是将DataFrame使用map取值之后,然后使用toSeq方法转成Seq格式,最后使用Seq的foldLeft方法拼接数据,并返回,如下所示:

//方法1:利用map重写
val separator = ","
df.map(_.toSeq.foldLeft("")(_ + separator + _).substring()).show() /**
* +-------------------+
* | value|
* +-------------------+
* |Ming,20,15552211521|
* |hong,19,13287994007|
* | zhi,21,15552211523|
* +-------------------+
*/

1.2 使用内置函数concat_ws

合并多列数据也可以使用SparkSQL的内置函数concat_ws()

//方法2: 使用内置函数 concat_ws
import org.apache.spark.sql.functions._
df.select(concat_ws(separator, $"name", $"age", $"phone").cast(StringType).as("value")).show() /**
* +-------------------+
* | value|
* +-------------------+
* |Ming,20,15552211521|
* |hong,19,13287994007|
* | zhi,21,15552211523|
* +-------------------+
*/

1.3 使用自定义UDF函数

自己编写UDF函数,实现多列合并

 //方法3:使用自定义UDF函数

    // 编写udf函数
def mergeCols(row: Row): String = {
row.toSeq.foldLeft("")(_ + separator + _).substring()
} val mergeColsUDF = udf(mergeCols _)
df.select(mergeColsUDF(struct($"name", $"age", $"phone")).as("value")).show()

完整代码:

import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.sql.types.StringType /**
* Created by shirukai on 2018/9/12
* DataFrame 合并列
*/
object MergeColsTest {
def main(args: Array[String]): Unit = {
val spark = SparkSession
.builder()
.appName(this.getClass.getSimpleName)
.master("local")
.getOrCreate() //从内存创建一组DataFrame数据
import spark.implicits._
val df = Seq(("Ming", , 15552211521L), ("hong", , 13287994007L), ("zhi", , 15552211523L))
.toDF("name", "age", "phone")
df.show()
/**
* +----+---+-----------+
* |name|age| phone|
* +----+---+-----------+
* |Ming| 20|15552211521|
* |hong| 19|13287994007|
* | zhi| 21|15552211523|
* +----+---+-----------+
*/
//方法1:利用map重写
val separator = ","
df.map(_.toSeq.foldLeft("")(_ + separator + _).substring()).show() /**
* +-------------------+
* | value|
* +-------------------+
* |Ming,20,15552211521|
* |hong,19,13287994007|
* | zhi,21,15552211523|
* +-------------------+
*/
//方法2: 使用内置函数 concat_ws
import org.apache.spark.sql.functions._
df.select(concat_ws(separator, $"name", $"age", $"phone").cast(StringType).as("value")).show() /**
* +-------------------+
* | value|
* +-------------------+
* |Ming,20,15552211521|
* |hong,19,13287994007|
* | zhi,21,15552211523|
* +-------------------+
*/
//方法3:使用自定义UDF函数 // 编写udf函数
def mergeCols(row: Row): String = {
row.toSeq.foldLeft("")(_ + separator + _).substring()
} val mergeColsUDF = udf(mergeCols _)
df.select(mergeColsUDF(struct($"name", $"age", $"phone")).as("value")).show() /**
* /**
* * +-------------------+
* * | value|
* * +-------------------+
* * |Ming,20,15552211521|
* * |hong,19,13287994007|
* * | zhi,21,15552211523|
* * +-------------------+
**/
*/
}
}

2 DataFrame列数据的拆分

上面我们将DataFrame的多列数据合并为一列如下所示,有时候我们也需要将单列数据,以某种拆分规则,拆分为多列。下面提供几种将一列拆分为多列的方法。

+-------------------+
| value|
+-------------------+
|Ming,,|
|hong,,|
| zhi,,|
+-------------------+

2.1 使用内置函数split,然后遍历添加列

该方法,先利用内置函数split将单列的数据拆分,然后遍历使用getItem(角标)方法获取拆分后的数据,依次使用withColumn方法添加新列,代码如下所示:

  //方法1: 使用内置函数split,然后遍历添加列
val separator = ","
lazy val first = df.first() val numAttrs = first.toString().split(separator).length
val attrs = Array.tabulate(numAttrs)(n => "col_" + n)
//按指定分隔符拆分value列,生成splitCols列
var newDF = df.withColumn("splitCols", split($"value", separator))
attrs.zipWithIndex.foreach(x => {
newDF = newDF.withColumn(x._1, $"splitCols".getItem(x._2))
})
newDF.show()
/**
* +-------------------+--------------------+-----+-----+-----------+
* | value| splitCols|col_0|col_1| col_2|
* +-------------------+--------------------+-----+-----+-----------+
* |Ming,20,15552211521|[Ming, 20, 155522...| Ming| 20|15552211521|
* |hong,19,13287994007|[hong, 19, 132879...| hong| 19|13287994007|
* | zhi,21,15552211523|[zhi, 21, 1555221...| zhi| 21|15552211523|
* +-------------------+--------------------+-----+-----+-----------+

2.2 使用UDF函数创建多列数据,然后合并
该方法是使用udf函数,生成多个列,然后合并到原来的数据。该方法参考了VectorDisassembler(与spark ml官网提供的VectorAssembler相反),这是一个第三方的spark ml向量拆分算法,该方法github地址:https://github.com/jamesbconner/VectorDisassembler。代码如下所示:

//方法2:使用udf函数创建多列,然后合并
val attributes: Array[Attribute] = {
val numAttrs = first.toString().split(separator).length
//生成attributes
Array.tabulate(numAttrs)(i => NumericAttribute.defaultAttr.withName("value" + "_" + i))
}
//创建多列数据
val fieldCols = attributes.zipWithIndex.map(x => {
val assembleFunc = udf {
str: String =>
str.split(separator)(x._2)
}
assembleFunc(df("value").cast(StringType)).as(x._1.name.get, x._1.toMetadata())
})
//合并数据
df.select(col("*") +: fieldCols: _*).show() /**
* +-------------------+-------+-------+-----------+
* | value|value_0|value_1| value_2|
* +-------------------+-------+-------+-----------+
* |Ming,20,15552211521| Ming| 20|15552211521|
* |hong,19,13287994007| hong| 19|13287994007|
* | zhi,21,15552211523| zhi| 21|15552211523|
* +-------------------+-------+-------+-----------+
*/

完整代码:

import org.apache.spark.ml.attribute.{Attribute, NumericAttribute}
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.types.StringType /**
* Created by shirukai on 2018/9/12
* 拆分列
*/
object SplitColTest {
def main(args: Array[String]): Unit = {
val spark = SparkSession
.builder()
.appName(this.getClass.getSimpleName)
.master("local")
.getOrCreate() //从内存中创建DataFrame
import spark.implicits._
val df = Seq("Ming,20,15552211521", "hong,19,13287994007", "zhi,21,15552211523")
.toDF("value")
df.show() /**
* +-------------------+
* | value|
* +-------------------+
* |Ming,20,15552211521|
* |hong,19,13287994007|
* | zhi,21,15552211523|
* +-------------------+
*/ import org.apache.spark.sql.functions._
//方法1: 使用内置函数split,然后遍历添加列
val separator = ","
lazy val first = df.first() val numAttrs = first.toString().split(separator).length
val attrs = Array.tabulate(numAttrs)(n => "col_" + n)
//按指定分隔符拆分value列,生成splitCols列
var newDF = df.withColumn("splitCols", split($"value", separator))
attrs.zipWithIndex.foreach(x => {
newDF = newDF.withColumn(x._1, $"splitCols".getItem(x._2))
})
newDF.show() /**
* +-------------------+--------------------+-----+-----+-----------+
* | value| splitCols|col_0|col_1| col_2|
* +-------------------+--------------------+-----+-----+-----------+
* |Ming,20,15552211521|[Ming, 20, 155522...| Ming| 20|15552211521|
* |hong,19,13287994007|[hong, 19, 132879...| hong| 19|13287994007|
* | zhi,21,15552211523|[zhi, 21, 1555221...| zhi| 21|15552211523|
* +-------------------+--------------------+-----+-----+-----------+
*/ //方法2:使用udf函数创建多列,然后合并
val attributes: Array[Attribute] = {
val numAttrs = first.toString().split(separator).length
//生成attributes
Array.tabulate(numAttrs)(i => NumericAttribute.defaultAttr.withName("value" + "_" + i))
}
//创建多列数据
val fieldCols = attributes.zipWithIndex.map(x => {
val assembleFunc = udf {
str: String =>
str.split(separator)(x._2)
}
assembleFunc(df("value").cast(StringType)).as(x._1.name.get, x._1.toMetadata())
})
//合并数据
df.select(col("*") +: fieldCols: _*).show() /**
* +-------------------+-------+-------+-----------+
* | value|value_0|value_1| value_2|
* +-------------------+-------+-------+-----------+
* |Ming,20,15552211521| Ming| 20|15552211521|
* |hong,19,13287994007| hong| 19|13287994007|
* | zhi,21,15552211523| zhi| 21|15552211523|
* +-------------------+-------+-------+-----------+
*/
}
}

Spark DataFrame列的合并与拆分的更多相关文章

  1. spark dataframe操作集锦(提取前几行,合并,入库等)

    https://blog.csdn.net/sparkexpert/article/details/51042970 spark dataframe派生于RDD类,但是提供了非常强大的数据操作功能.当 ...

  2. spark DataFrame 常见操作

    spark dataframe派生于RDD类,但是提供了非常强大的数据操作功能.当然主要对类SQL的支持. 在实际工作中会遇到这样的情况,主要是会进行两个数据集的筛选.合并,重新入库. 首先加载数据集 ...

  3. Pandas: 如何将一列中的文本拆分为多行? | Python

    Pandas: 如何将一列中的文本拆分为多行? 在数据处理过程中,经常会遇到以下类型的数据: 在同一列中,本该分别填入多行中的数据,被填在一行里了,然而在分析的时候,需要拆分成为多行. 在上图中,列名 ...

  4. excel技巧--单元格合并与拆分

    如果要将上图的地区列做成下图的合并单一列: 有如下做法: (以下图表格为例) 1.选择要排序的表格,点击“开始”-->排序和筛选-->自定义排序.在对话框选择“业务项目”进行排序: 2.选 ...

  5. Spark DataFrame中的join使用说明

    spark sql 中join的类型 Spark DataFrame中join与SQL很像,都有inner join, left join, right join, full join; 类型 说明 ...

  6. Spire.Cloud.SDK for Java 合并、拆分Excel单元格

    Spire.Cloud.SDK for Java 是Spire.Cloud云产品系列中,用于处理Word.Excel.PowerPoint以及PDF文档的JAR文件,可执行文档编辑.转换.保存等操作. ...

  7. C# 合并及拆分Word文档

    本文简要分析一下如何如何使用C#简单实现合并和拆分word文档.平时我们在处理多个word文档时,可能会想要将两个文档合并为一个,或者是将某个文档的一部分添加到另一个文档中,有的时候也会想要将文档拆分 ...

  8. C# 合并及拆分PDF文件

    C# 合并及拆分PDF文件 有时我们可能会遇到下图这样一种情况 — 我们需要的资料或教程被分成了几部分存放在多个PDF文件中,不管是阅读还是保存都不是很方便,这时我们肯定想要把这些PDF文件合并为一个 ...

  9. spark dataframe unionall

    今天本来想写一个spark dataframe unionall的demo,由于粗心报下面错误: Exception in thread "main" org.apache.spa ...

随机推荐

  1. 在 Ubuntu 14.04 服务器上部署 Hexo 博客

    版权声明:本文由宋秉金 原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/241080001487926962 来源:腾云阁  ...

  2. xrdp完美实现Windows远程访问Ubuntu 16.04

    前言: 在很多场景下,我们需要远程连接到Linux服务器(本文是Ubuntu),传统的连接主要分为两种. 第一种:通过SSH服务(使用xshell等工具)来远程访问,编写终端命令,不过这个是无界面的, ...

  3. 【CF944G】Coins Exhibition DP+队列

    [CF944G]Coins Exhibition 题意:Jack去年参加了一个珍稀硬币的展览会.Jack记得一共有 $k$ 枚硬币,这些硬币排成一行,从左到右标号为 $1$ 到 $k$ ,每枚硬币是正 ...

  4. day_6.14py网络编程

    被动套接字和新建出套接字的区别 单任务,单线程,非阻塞!!!!服务器! #2018-6-14 16:51:25 #!--*--coding:utf-8 --*-- ''' 单进程,单任务 少的可以,多 ...

  5. 网络通信协议八之UDP协议详解

    视频传输中使用UDP协议比较多 UDP协议的责任 >>创建进程到进程间的通信(由端口号完成) >>有限的差错控制,出现差错悄悄丢弃报文(注意这点和TCP协议的区别)

  6. MySQL语言 数据库练习题分解。

    一.            设有一数据库,包括四个表:学生表(Student).课程表(Course).成绩表(Score)以及教师信息表(Teacher).四个表的结构分别如表1-1的表(一)~表( ...

  7. TOP100summit【分享实录-网易】构建云直播分发网络

    本篇文章内容来自2016年TOP100summit网易视频云.网易杭州研究院服务端技术专家邵峰的案例分享.编辑:Cynthia 邵峰:网易视频云.网易杭州研究院服务端技术专家浙江大学计算机专业博士毕业 ...

  8. angular 表单元素的使用总结

    工作中form表单元素最常用的是input,问题没有太多,现在总结下select ,radio组,checkbox的使用 1 select 常用的使用方式,如下 var Cityis = [{id:0 ...

  9. [skill] C与C++对于类型转换的验证

    不多说了,代码说明一切. /home/tong/Src/copyleft/test [tong@T7] [:] > gcc .c /home/tong/Src/copyleft/test [to ...

  10. python知识点杂记2

    1. 如果已经有一个list或者tuple,要调用一个可变参数怎么办?2. >>> nums = [1, 2, 3]3. >>> calc(*nums)4. 14* ...