spark sql實戰—拆分數據

拆分的數據

有時在進行數據時我們需要把一列數據分割成多列數據,把一個字段值,分割成多個值。本節介紹如何通過spark sql提供的函數來進行數據的分割。

1. 數據拆分概述

數據拆分操作

在進行數據處理時,通常我們需要對數據進行拆分。比如:把一列拆分成多行,多列,把一行拆分成多行,多列等。

在spark-sql中提供了多個函數用來進行數據拆分。

數據拆分的函數

  • split
  • explode
  • postexplode
  • substring

2. 數據的拆分

2.1 通過explode系列函數進行拆分

  • 把一個數組值的列拆分成多行**: explode

通過explode函數可以把一個list類型的值,拆分成多行。

>>> import pyspark.sql.functions as F
>>> list_data = [(1, "abc", ["p", "q", "r"]), (2, "def", ["x", "y", "z"])]
>>> schema = ["id", "col1", "col2"]
>>> 
>>> df = spark.createDataFrame(list_data, schema)
>>> df.show()
+---+----+---------+
| id|col1|     col2|
+---+----+---------+
|  1| abc|[p, q, r]|
|  2| def|[x, y, z]|
+---+----+---------+

>>> df.withColumn("col2", F.explode("col2")).show()
+---+----+----+
| id|col1|col2|
+---+----+----+
|  1| abc|   p|
|  1| abc|   q|
|  1| abc|   r|
|  2| def|   x|
|  2| def|   y|
|  2| def|   z|
+---+----+----+
  • 把一個map值的列拆分成多個列和多行: explode

通過explode函數也可以把一個map值拆分成key,value兩個值。若該map中有多個key-value鍵值對,會對這些key-value值進行全部拆分。

>>> from pyspark.sql import Row
>>> 
>>> rows = [
...     Row(a=1, mapfield={"a": "b"}),
...     Row(a=2, mapfield={"a1": "b1"}),
...     Row(a=3, mapfield={"a2": "b2"}),
...     Row(a=4, mapfield={"a3": "b3", "a4": "b4", "a5": {"key5": "value5"}})
... ]
>>> 
>>> eDF = spark.createDataFrame(rows)
>>> eDF.show(truncate=False)
+---+-----------------------------------------+
|a  |mapfield                                 |
+---+-----------------------------------------+
|1  |[a -> b]                                 |
|2  |[a1 -> b1]                               |
|3  |[a2 -> b2]                               |
|4  |[a3 -> b3, a4 -> b4, a5 -> {key5=value5}]|
+---+-----------------------------------------+

>>> eDF.select("a", F.explode(eDF.mapfield).alias("key", "value")).show()
+---+---+-------------+
|  a|key|        value|
+---+---+-------------+
|  1|  a|            b|
|  2| a1|           b1|
|  3| a2|           b2|
|  4| a3|           b3|
|  4| a4|           b4|
|  4| a5|{key5=value5}|
+---+---+-------------+

可以看到:explode函數先把map值的key-value進行拆分成兩列:key,value,若map中有多個key-value值,則會創建新的行,其他列的值保存不變。但注意:該函數只會拆分一層的key-value值,不會對嵌套的map值進行拆分。

  • 對list和map值進行拆分,並且添加一個index號(從0開始)posexplode
pyspark.sql.functions.posexplode(col)

通過該函數可以把list或map值的列拆分成兩列,多行。並且會根據值在list或map中的位置添加一列索引值。該索引值從0開始。

>>> eDF = spark.createDataFrame([Row(a=1, intlist=[1,2,3], mapfield={"a": "b", "c": "d"})])
>>> eDF.show()
+---+---------+----------------+
|  a|  intlist|        mapfield|
+---+---------+----------------+
|  1|[1, 2, 3]|[a -> b, c -> d]|
+---+---------+----------------+

# 拆分map值的列,並添加一列pos
>> eDF.select("a","intlist",F.posexplode(eDF.mapfield)).show()
+---+---------+---+---+-----+
|  a|  intlist|pos|key|value|
+---+---------+---+---+-----+
|  1|[1, 2, 3]|  0|  a|    b|
|  1|[1, 2, 3]|  1|  c|    d|
+---+---------+---+---+-----+

# 拆分數組值的列,並添加一列索引值pos
>>> eDF.select("a","mapfield",F.posexplode(eDF.intlist)).show()
+---+----------------+---+---+
|  a|        mapfield|pos|col|
+---+----------------+---+---+
|  1|[a -> b, c -> d]|  0|  1|
|  1|[a -> b, c -> d]|  1|  2|
|  1|[a -> b, c -> d]|  2|  3|
+---+----------------+---+---+
  • **拆分時對空值進行填充:**posexplode_outer(spark-2.3開始)

從spark-2.3開始,提供了一個函數posexplode_outer,該函數的行爲和explode一樣,不同的是,若是數組或map值中存在None,則會以null替換。

df = spark.createDataFrame(
...     [(1, ["foo", "bar"], {"x": 1.0}), (2, [], {}), (3, None, None)],
...     ("id", "an_array", "a_map")
... )
>>> df.select("id", "an_array", posexplode_outer("a_map")).show()
+---+----------+----+----+-----+
| id|  an_array| pos| key|value|
+---+----------+----+----+-----+
|  1|[foo, bar]|   0|   x|  1.0|
|  2|        []|null|null| null|
|  3|      null|null|null| null|
+---+----------+----+----+-----+
>>> df.select("id", "a_map", posexplode_outer("an_array")).show()
+---+----------+----+----+
| id|     a_map| pos| col|
+---+----------+----+----+
|  1|[x -> 1.0]|   0| foo|
|  1|[x -> 1.0]|   1| bar|
|  2|        []|null|null|
|  3|      null|null|null|
+---+----------+----+----+

2.2 split拆分數據

split函數可以把一個字符串值拆分成一個數組值,而且split函數還支持按正則表達式來進行拆分。

pyspark.sql.functions.split(str, pattern)
>>> df = spark.createDataFrame([('ab12cd',"aaaa")], ['c1','c2'])
>>> df.show()
+------+----+
|    c1|  c2|
+------+----+
|ab12cd|aaaa|
+------+----+

# 以下可以看到,拆分後的值都變成了數組值
>>> df.select('c2', F.split(df.c1, '[0-9]+').alias('r')).show()
+----+--------+
|  c2|       r|
+----+--------+
|aaaa|[ab, cd]|
+----+--------+

>>> df.select('c1', F.split(df.c2, '[0-9]+').alias('r')).show()
+------+------+
|    c1|     r|
+------+------+
|ab12cd|[aaaa]|
+------+------+

3. 總結

本節介紹瞭如何通過spark-sql對數據進行拆分操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章