spark从字符串中提取值并指定为列

vq8itlhq  于 2021-05-19  发布在  Spark
关注(0)|答案(1)|浏览(1105)

需要帮助解析字符串,其中包含每个属性的值。下面是我的示例字符串。。。

Type=<Series VR> Model=<1Ac4> ID=<34> conn seq=<2>
Type=<SeriesX> Model=<12Q3> ID=<231> conn seq=<3423123>

在上面,我必须生成具有如下值的列。

Type | Model | Id | conn seq
----------------------------
Series VR | 1Ac4 | 34 | 2
SeriesX | 12Q3 | 231 | 3423123

不知道如何通过regex/split和使用withcolumn()解析它。
谢谢你的帮助。谢谢

mspsb9vt

mspsb9vt1#

根据您的示例,您可以使用sparksql函数str_to_map将字符串转换为map,然后从所需的map键中选择值(下面的代码假定stringtype列名为 value ):

from pyspark.sql import functions as F

keys = ['Type', 'Model', 'ID', 'conn seq']

df.withColumn("m", F.expr("str_to_map(value, '> *', '=<')")) \
    .select("*", *[ F.col('m')[k].alias(k) for k in keys ]) \
    .show()
+--------------------+--------------------+---------+-----+---+--------+
|               value|                   m|     Type|Model| ID|conn seq|
+--------------------+--------------------+---------+-----+---+--------+
|Type=<Series VR> ...|[Type -> Series V...|Series VR| 1Ac4| 34|       2|
|Type=<SeriesX> Mo...|[Type -> SeriesX,...|  SeriesX| 12Q3|231| 3423123|
+--------------------+--------------------+---------+-----+---+--------+

注意:这里我们使用regex模式 > * 分割成对和图案 =< 拆分键/值。如果需要,请检查此链接 keys 的Map是动态的,不能预定义,只需确保过滤掉空键。
编辑:基于注解,对Map键进行不区分大小写的搜索。对于spark 2.3,我们可以使用udf对 value 使用str\u to\u map函数前的列:
为匹配的键设置regex模式(在组1中)。我们用这个 (?i) 设置不区分大小写的匹配,并添加两个定位点 \b 以及 (?==) ,这样匹配的子字符串必须在左边有一个单词边界,后跟一个 = 向右标记。

ptn = "(?i)\\b({})(?==)".format('|'.join(keys))
print(ptn)

# (?i)\b(Type|Model|ID|conn seq)(?==)

设置udf以便使用series.str.replace()并将回调(小写$1)设置为替换:

lower_keys = F.pandas_udf(lambda s: s.str.replace(ptn, lambda m: m.group(1).lower()), "string")

将所有匹配的键转换为小写:

df1 = df.withColumn('value', lower_keys('value'))
+-------------------------------------------------------+
|value                                                  |
+-------------------------------------------------------+
|type=<Series VR> model=<1Ac4> id=<34> conn seq=<2>     |
|type=<SeriesX> model=<12Q3> id=<231> conn seq=<3423123>|
+-------------------------------------------------------+

使用str-to-map创建Map,然后使用 k.lower() 作为键来找到它们对应的值。

df1.withColumn("m", F.expr("str_to_map(value, '> *', '=<')")) \
    .select("*", *[ F.col('m')[k.lower()].alias(k) for k in keys ]) \
    .show()

注意:如果您将来可以使用spark 3.0+,请跳过以上步骤,改用transform\u keys功能:

df.withColumn("m", F.expr("str_to_map(value, '> *', '=<')")) \
    .withColumn("m", F.expr("transform_keys(m, (k,v) -> lower(k))")) \
    .select("*", *[ F.col('m')[k.lower()].alias(k) for k in keys ]) \
    .show()

对于spark 2.4+,更换 transform_keys(...) 包括以下内容:

map_from_entries(transform(map_keys(m), k -> (lower(k), m[k])))

相关问题