修改ArrayType中的所有元素

时间:2019-10-25 11:31:40

标签: apache-spark pyspark pyspark-sql pyspark-dataframes

我有一个ArrayType(StringType)列的DataFrame:

+------------------------------------+
|colname                             |
+------------------------------------+
|[foo_XX_foo, bar_YY_bar]            |
|[qwe_ZZ_rty, asd_AA_fgh, zxc_BB_vbn]|
+------------------------------------+

我现在想提取第一个_和第二个+------------+ |newcolname | +------------+ |[XX, YY] | |[ZZ, AA, BB]| +------------+ 之间的字符串,即预期输出为:

expr()

this answer之后,我尝试将transformArrayType一起使用,但是我没有设法使其正常工作。甚至上面引用的答案中将所有字符串都更改为大写的示例对我也不起作用,我得到以下错误:

  

pyspark.sql.utils.ParseException:u“ \下一个输入'>'期望{'(','SELECT',...

如何修改udf中的所有元素?我想避免使用{{1}}。

2 个答案:

答案 0 :(得分:5)

有点不安全,但是请尝试以下操作:

android:screenOrientation

其结果是:

df = spark.sparkContext.parallelize([
  [["foo_XX_foo", "bar_YY_bar"]],
  [["qwe_ZZ_rty", "asd_AA_fgh", "zxc_BB_vbn"]]
]).toDF(['colname'])

df.selectExpr('transform(colname, x -> split(x, "_")[1]) as newcolname').show()

答案 1 :(得分:4)

由于您使用的是Spark版本2.3.2,因此transform不可用。因此,如post you linked中所述,最好的方法通常是使用udf

但是,在这种特定情况下,您可能可以避免使用一些骇人的正则表达式替换udf

from pyspark.sql.functions import col, concat_ws, regexp_replace, split, trim

df.withColumn(
    "newcolname",
    regexp_replace(concat_ws(",", col("colname")), "((?<=_)[^_,]+(?=_))", " $1 ")
).withColumn(
    "newcolname",
    regexp_replace(col("newcolname"), "(_[^_ ]+_)", "")
).withColumn(
    "newcolname",
    regexp_replace(col("newcolname"), "([^_ ]+_)", "")
).withColumn(
    "newcolname",
    regexp_replace(col("newcolname"), "_([^_ ]+)", "")
).withColumn(
    "newcolname",
    split(trim(col("newcolname")), "\s+")
).show(truncate=False)
#+------------------------------------+------------+
#|colname                             |newcolname  |
#+------------------------------------+------------+
#|[foo_XX_foo, bar_YY_bar]            |[XX, YY]    |
#|[qwe_ZZ_rty, asd_AA_fgh, zxc_BB_vbn]|[ZZ, AA, BB]|
#+------------------------------------+------------+

说明

首先,我们使用ArrayType(StringType())列并将元素连接在一起以形成一个字符串。我使用逗号作为分隔符,仅当逗号未出现在数据中时,该分隔符才起作用。

接下来,我们执行一系列regexp_replace调用。

第一个模式((?<=_)[^_,]+(?=_))标识您实际要提取的内容:下划线括起来的文本。然后,将匹配组替换为由空格" $1 "包围的匹配组。像以前使用逗号分隔符一样,这​​假定空格不会出现在数据中。

例如:

df.select(
    regexp_replace(
        concat_ws(",", col("colname")), 
        "((?<=_)[^_,]+(?=_))", 
        " $1 "
    ).alias("pattern1")
).show(truncate=False)
#+--------------------------------------+
#|pattern1                              |
#+--------------------------------------+
#|foo_ XX _foo,bar_ YY _bar             |
#|qwe_ ZZ _rty,asd_ AA _fgh,zxc_ BB _vbn|
#+--------------------------------------+

接下来对regexp_replace的3个调用有选择地删除此字符串中不需要的部分。

最后,仅保留所需的内容。对该字符串进行修剪以除去尾随/前导空格,并在空格上分割以获取最终结果。