Pyspark 将spark back中的mapType列与原始数据帧联接/展开

Pyspark 将spark back中的mapType列与原始数据帧联接/展开,pyspark,spark-dataframe,flatmap,Pyspark,Spark Dataframe,Flatmap,我在pySpark中有一个数据帧,其中1列来自类型“map”。我希望将该列展平或拆分为多个列,这些列应添加到原始数据帧中。我可以使用flatMap展开列,但是我松开了将展开列中的新数据帧与原始数据帧连接起来的键 我的模式如下: rroot |-- key: string (nullable = true) |-- metric: map (nullable = false) | |-- key: string | |-- value: float (valueCont

我在pySpark中有一个数据帧,其中1列来自类型“map”。我希望将该列展平或拆分为多个列,这些列应添加到原始数据帧中。我可以使用flatMap展开列,但是我松开了将展开列中的新数据帧与原始数据帧连接起来的键

我的模式如下:

    rroot
 |-- key: string (nullable = true)
 |-- metric: map (nullable = false)
 |    |-- key: string
 |    |-- value: float (valueContainsNull = true)
from pyspark.sql.functions import explode
df.select(explode("custom_dimensions")).select("key")
如您所见,“metric”列是一个映射字段。这是我要展平的列。在展平之前,它看起来像:

+----+---------------------------------------------------+
|key |metric                                             |
+----+---------------------------------------------------+
|123k|Map(metric1 -> 1.3, metric2 -> 6.3, metric3 -> 7.6)|
|d23d|Map(metric1 -> 1.5, metric2 -> 2.0, metric3 -> 2.2)|
|as3d|Map(metric1 -> 2.2, metric2 -> 4.3, metric3 -> 9.0)|
+----+---------------------------------------------------+
要将该字段转换为列,我需要

df2.select('metric').rdd.flatMap(lambda x: x).toDF().show()

   +------------------+-----------------+-----------------+
|           metric1|          metric2|          metric3|
+------------------+-----------------+-----------------+
|1.2999999523162842|6.300000190734863|7.599999904632568|
|               1.5|              2.0|2.200000047683716|
| 2.200000047683716|4.300000190734863|              9.0|
+------------------+-----------------+-----------------+
但是我没有看到键,因此我不知道如何将此数据添加到原始数据帧

我想要的是:

+----+-------+-------+-------+
| key|metric1|metric2|metric3|
+----+-------+-------+-------+
|123k|    1.3|    6.3|    7.6|
|d23d|    1.5|    2.0|    2.2|
|as3d|    2.2|    4.3|    9.0|
+----+-------+-------+-------+
因此,我的问题是:如果我最初不知道df,并且只有df2,那么如何将df2返回给df

要制作df2:

rdd = sc.parallelize([('123k', 1.3, 6.3, 7.6),
                      ('d23d', 1.5, 2.0, 2.2), 
                      ('as3d', 2.2, 4.3, 9.0)
                          ])
schema = StructType([StructField('key', StringType(), True),
                     StructField('metric1', FloatType(), True),
                     StructField('metric2', FloatType(), True),
                     StructField('metric3', FloatType(), True)])
df = sqlContext.createDataFrame(rdd, schema)


from pyspark.sql.functions import lit, col, create_map
from itertools import chain

metric = create_map(list(chain(*(
    (lit(name), col(name)) for name in df.columns if "metric" in name
)))).alias("metric")


df2 = df.select("key", metric)
您可以访问密钥和值,例如:

    rroot
 |-- key: string (nullable = true)
 |-- metric: map (nullable = false)
 |    |-- key: string
 |    |-- value: float (valueContainsNull = true)
from pyspark.sql.functions import explode
df.select(explode("custom_dimensions")).select("key")

找到它后,我似乎可以通过执行df从maptype中选择某个键。选择“maptypecolumn”。“键”

在我的例子中,我是这样做的:

columns= df2.select('metric').rdd.flatMap(lambda x: x).toDF().columns
for i in columns:
  df2= df2.withColumn(i,lit(df2.metric[i]))
希望这有帮助

从pyspark.sql.functions导入explode 从MapType“metric”列的键中获取原始数据帧的列名 col_names=df2.selectexplodemetric.selectkey.distinct.sortkey.rdd.flatmap lambda x:x.collect exprs=[colkey]+[colmetric.getItemk.aliask表示列名称中的k] df2_至_原始_df=df2。选择*exprs df2_至_原件_df.show 输出为:

+----+-------+-------+-------+
| key|metric1|metric2|metric3|
+----+-------+-------+-------+
|123k|    1.3|    6.3|    7.6|
|d23d|    1.5|    2.0|    2.2|
|as3d|    2.2|    4.3|    9.0|
+----+-------+-------+-------+

如果你能做一个比较容易的回答。是的,我同意,如果你提供一些样本数据,我会在下面给出答案。分解为每个值提供一行“自定义尺寸”列,而我希望地图“自定义尺寸”中的每个值都在另一列中。我正在搜索的键是与数据帧其余部分连接的键。而分解中的“键”应该是新的列名+。是的,谢谢。很难,通过上面的代码我可以获得更好的性能。再次感谢:@5nv很高兴它能帮上忙:也许你应该这么做,这样问题就可以被认为已经结束了。