Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 使用PySpark将数组值分解为多列_Apache Spark_Pyspark_Apache Spark Sql_Pyspark Dataframes - Fatal编程技术网

Apache spark 使用PySpark将数组值分解为多列

Apache spark 使用PySpark将数组值分解为多列,apache-spark,pyspark,apache-spark-sql,pyspark-dataframes,Apache Spark,Pyspark,Apache Spark Sql,Pyspark Dataframes,我是pyspark的新手,我希望以这样一种方式分解数组值,即每个值都分配给一个新列。我尝试使用explode,但无法获得所需的输出。下面是我的输出 这是密码 from pyspark.sql import * from pyspark.sql.functions import explode if __name__ == "__main__": spark = SparkSession.builder \ .master("local[3]"

我是pyspark的新手,我希望以这样一种方式分解数组值,即每个值都分配给一个新列。我尝试使用explode,但无法获得所需的输出。下面是我的输出

这是密码

from pyspark.sql import *
from pyspark.sql.functions import explode
if __name__ == "__main__":
spark = SparkSession.builder \
    .master("local[3]") \
    .appName("DataOps") \
    .getOrCreate()

dataFrameJSON = spark.read \
    .option("multiLine", True) \
    .option("mode", "PERMISSIVE") \
    .json("data.json")

dataFrameJSON.printSchema()
sub_DF = dataFrameJSON.select(explode("values.line").alias("new_values"))
sub_DF.printSchema()

sub_DF2 = sub_DF.select("new_values.*")
sub_DF2.printSchema()
sub_DF.show(truncate=False)

new_DF = sub_DF2.select("id", "period.*", "property")
new_DF.show(truncate=False)
new_DF.printSchema()
这是数据:

{
        "values" : {
            "line" : [
                {
                    "id" : 1,
                    "period" : {
                        "start_ts" : "2020-01-01T00:00:00",
                        "end_ts" : "2020-01-01T00:15:00"
                    },
                    "property" : [
                        {
                            "name" : "PID",
                            "val" : "P120E12345678"
                        },
                        {
                            "name" : "EngID",
                            "val" : "PANELID00000000"
                        },
                        {
                            "name" : "TownIstat",
                            "val" : "12058091"
                        },
                        {
                            "name" : "ActiveEng",
                            "val" : "5678.1"
                        }
                    ]
                }
}

你能用数据代替截图吗

同时,假设
df
是正在使用的数据帧,我们需要做的是创建一个新的数据帧,同时将
vals
从以前的
property
数组提取到新列,最后删除
property
列:

from pyspark.sql.functions import col
output_df = df.withColumn("PID", col("property")[0].val).withColumn("EngID", col("property")[1].val).withColumn("TownIstat", col("property")[2].val).withColumn("ActiveEng", col("property")[3].val).drop("property")
如果
元素
的类型为
阵列类型
,请使用以下命令:

from pyspark.sql.functions import col
output_df = df.withColumn("PID", col("property")[0][1]).withColumn("EngID", col("property")[1][1]).withColumn("TownIstat", col("property")[2][1]).withColumn("ActiveEng", col("property")[3][1]).drop("property")

Explode将数组分解为新行,而不是新列,请参见:

这是一种通用解决方案,即使JSON很凌乱,也能正常工作(元素顺序不同或缺少某些元素)

首先,您需要将“属性”列展平,
regexp\u替换为split,最后是pivot。这也避免了新列名的硬编码

构建数据帧:

from pyspark.sql.types import *
from pyspark.sql import functions as F
from pyspark.sql.functions import col
from pyspark.sql.functions import *

schema = StructType([StructField("id", IntegerType()), StructField("start_ts", StringType()), StructField("end_ts", StringType()), \
    StructField("property", ArrayType(StructType(  [StructField("name", StringType()),  StructField("val", StringType())]    )))])

data = [[1, "2010", "2020", [["PID", "P123"], ["Eng", "PA111"], ["Town", "999"], ["Act", "123.1"]]],\
         [2, "2011", "2012", [["PID", "P456"], ["Eng", "PA222"], ["Town", "777"], ["Act", "234.1"]]]]

df = spark.createDataFrame(data,schema=schema)

df.show(truncate=False)
+---+--------+------+------------------------------------------------------+    
|id |start_ts|end_ts|property                                              |
+---+--------+------+------------------------------------------------------+
|1  |2010    |2020  |[[PID, P123], [Eng, PA111], [Town, 999], [Act, 123.1]]|
|2  |2011    |2012  |[[PID, P456], [Eng, PA222], [Town, 777], [Act, 234.1]]|
+---+--------+------+------------------------------------------------------+
展开和旋转:

df_flatten = df.rdd.flatMap(lambda x: [(x[0],x[1], x[2], y) for y in x[3]]).toDF(['id', 'start_ts', 'end_ts', 'property'])\
            .select('id', 'start_ts', 'end_ts', col("property").cast("string"))

df_split = df_flatten.select('id', 'start_ts', 'end_ts', regexp_replace(df_flatten.property, "[\[\]]", "").alias("replacced_col"))\
                .withColumn("arr", split(col("replacced_col"), ", "))\
                .select(col("arr")[0].alias("col1"), col("arr")[1].alias("col2"), 'id', 'start_ts', 'end_ts')

final_df = df_split.groupby(df_split.id,)\
                        .pivot("col1")\
                        .agg(first("col2"))\
                        .join(df,'id').drop("property")
输出:

final_df.show()
+---+-----+-----+----+----+--------+------+
| id|  Act|  Eng| PID|Town|start_ts|end_ts|
+---+-----+-----+----+----+--------+------+
|  1|123.1|PA111|P123| 999|    2010|  2020|
|  2|234.1|PA222|P456| 777|    2011|  2012|
+---+-----+-----+----+----+--------+------+

请将代码示例、错误输出放在文本而不是图像中,以便社区更容易帮助您。@Mikayel Saghyan,我希望现在代码和示例数据对您可见?我正在尝试生成上面链接中给出的所需输出感谢您的回复,我尝试了您建议的代码,但我得到了以下错误:TypeError:col()缺少1个必需的位置参数:“strg”您能在上面的问题中包含您的代码吗?有数据样本吗?编辑时,请尝试编辑您自己的问题,而不是我的答案,您的路径代码正确,示例数据现在可用,请帮助我生成我在屏幕截图中提供的所需输出,提前感谢您您可能忘记在col()中插入“property”字符串,你能在使用我的答案后显示你所有的代码吗?我只是在DataRicks上使用了相同的代码,它工作得很好,没有错误sub_DF=dataFrameJSON.select(“UrbanDataset.values.line”)sub_DF2=dataFrameJSON.select(explode(“UrbanDataset.values.line”).alias(“new_values”))sub_DF3=sub_DF2.select(“new_values.*)_DF=sub_DF3.select(“id”、“period.*”、“property”)new_DF.show(truncate=False)output\u df=new\u df.withColumn(“PID”,col(“property”)[0][1])\。withColumn(“EngID”,col(“property”)[1][1])\。withColumn(“TownIstat”,col(“property”)[2][1])\。withColumn(“ActiveEng”,col property”)[3][1])。drop(“property”)output\u df show(truncate=False)非常感谢您的回复,通过使用您的代码,我得到了以下错误:TypeError:col()缺少1个必需的位置参数:“strg”,我想我对col软件包有问题?你能分享完整的代码,包括所有的导入吗?谢谢你,我已经添加了导入。你从哪里得到错误?非常感谢你的回复,它现在也对我起作用了。为什么不简单地提取rele,而需要这么多麻烦通过访问数据来获取数据,然后创建新列?我不明白,这会使事情变得复杂。因为这是一个通用的解决方案。我知道,在这个问题上只使用索引更简单。但是如果“属性”中元素的顺序发生了变化,或者其中一个元素丢失,索引方法将无法工作。我正在分解在这种情况下,我的解决方案中会出现混乱的JSON(并且没有列名的硬编码。适用于“n”个元素)