Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.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 如何在ApacheSpark中处理拼花地板模式的更改_Apache Spark_Apache Spark Sql_Spark Dataframe_Emr_Parquet - Fatal编程技术网

Apache spark 如何在ApacheSpark中处理拼花地板模式的更改

Apache spark 如何在ApacheSpark中处理拼花地板模式的更改,apache-spark,apache-spark-sql,spark-dataframe,emr,parquet,Apache Spark,Apache Spark Sql,Spark Dataframe,Emr,Parquet,我遇到了一个问题,在S3中,我将拼花地板数据作为每日块(以S3://bucketName/prefix/YYYY/MM/DD/的形式),但我无法从不同的日期读取AWS EMR Spark中的数据,因为某些列类型不匹配,并且我遇到了许多异常之一,例如: java.lang.ClassCastException: optional binary element (UTF8) is not a group 当在某些文件中有一个数组类型具有值,但在其他文件中同一列可能具有null值,而这些文件随后被推

我遇到了一个问题,在S3中,我将拼花地板数据作为每日块(以
S3://bucketName/prefix/YYYY/MM/DD/
的形式),但我无法从不同的日期读取AWS EMR Spark中的数据,因为某些列类型不匹配,并且我遇到了许多异常之一,例如:

java.lang.ClassCastException: optional binary element (UTF8) is not a group
当在某些文件中有一个数组类型具有值,但在其他文件中同一列可能具有
null
值,而这些文件随后被推断为字符串类型时,会出现此消息

我在S3中有JSON格式的原始数据,我最初的计划是创建一个自动作业,它启动一个EMR集群,读入前一个日期的JSON数据,并将其作为拼花写回S3

JSON数据也分为日期,即键有日期前缀。阅读JSON很好。无论当前读取了多少数据,都会从数据中推断出模式

但是当拼花文件被写入时,问题就出现了。据我所知,当我使用元数据文件编写拼花地板时,这些文件包含拼花地板文件的所有部分/分区的模式。在我看来,这也可以是不同的模式。当我禁用写入元数据时,Spark被认为是从给定拼花地板路径中的第一个文件推断出整个模式,并假定它在其他文件中保持不变

当某些列(应该是
double
类型)在给定的一天内只有整数值时,从JSON(这些数字是整数,没有浮点数)读取它们会使Spark认为它是类型为
long
的列。即使我可以在编写拼花文件之前将这些列转换为两倍,这仍然不好,因为模式可能会更改,可以添加新的列,并且跟踪这一点是不可能的

我见过一些人有同样的问题,但我还没有找到一个足够好的解决办法


这方面的最佳实践或解决方案是什么

这些是我用于将拼花地板写入S3的选项;关闭模式合并可以提高写回性能——这也可以解决您的问题

val PARQUET_OPTIONS = Map(
 "spark.sql.parquet.mergeSchema" -> "false",
 "spark.sql.parquet.filterPushdown" -> "true")

当我从JSON中读取每日数据块并写入每日S3文件夹中的Parquet时,在读取JSON时没有指定自己的模式,也没有在写入Parquet之前将容易出错的列转换为正确的类型,Spark可能会根据数据实例中的值为不同天数的数据推断不同的模式,并使用冲突模式编写拼花文件

这可能不是一个完美的解决方案,但我发现用不断发展的模式解决问题的唯一方法是:

在批量处理前一天数据的日常(更具体地说是夜间)cron作业之前,我正在创建一个虚拟对象,其中大部分是空值

我确保ID是可识别的,例如,由于真实数据具有唯一的ID-s,我将“伪”字符串作为ID添加到伪数据对象中

然后,我将为具有易出错类型的属性提供预期值,例如,我将提供浮点/双精度非零值,因此当编组为JSON时,它们肯定会使用十进制分隔符,例如“0.2”而不是“0”(当编组为JSON时,具有0值的双精度/浮点将显示为“0”而不是“0.0”)

字符串、布尔值和整数可以很好地工作,但是除了double/float之外,我还需要将数组实例化为空数组,并使用相应的空对象实例化其他类/结构的对象,这样它们就不会是“null”-s,因为Spark在字符串中读取null-s


然后,如果我已经填充了所有必需的字段,我将把对象整理成JSON,并将文件写入S3

然后,我会在Scala批处理脚本中使用这些文件来读取它们,将模式保存到一个变量中,并在读取真实JSON数据时将此模式作为参数,以避免Spark进行自己的模式推断

这样我就知道所有字段都是同一类型的,只有在添加新字段时才需要合并模式来连接模式


当然,它增加了一个缺点,即在添加易出错类型的新字段时手动更新虚拟对象创建,但这是目前的一个小缺点,因为这是我发现的唯一有效的解决方案。

只要创建一个rdd[String],其中每个字符串都是json,将rdd设置为数据帧时,使用primitiveAsString选项将所有数据类型设置为字符串

 val binary_zip_RDD = sc.binaryFiles(batchHolder.get(i), minPartitions = 50000)
 // rdd[String]  each string is a json ,lowercased json
    val TransformedRDD = binary_zip_RDD.flatMap(kv => ZipDecompressor.Zip_open_hybrid(kv._1, kv._2, proccessingtimestamp))
 // now the schema of dataframe would be consolidate schema of all json strings
    val jsonDataframe_stream = sparkSession.read.option("primitivesAsString", true).json(TransformedRDD)

    println(jsonDataframe_stream.printSchema())


    jsonDataframe_stream.write.mode(SaveMode.Append).partitionBy(GetConstantValue.DEVICEDATE).parquet(ApplicationProperties.OUTPUT_DIRECTORY)

嗨,我要试试这个。但我想知道,在编写拼花时,是否在
.option()
函数中包含此
PARQUET\u OPTIONS
映射?但是读书怎么样?我只使用了
sqlContext.read.option(“mergeSchema”,true)。parquet(“path”)
,但仍然使用没有选项的常规写操作。我尝试了使用
.option(“mergeSchema”,“false”)。option(“filterPushdown”,“true”)
进行读写操作,但没有任何改变。当mergeSchema为true时,我得到
无法合并不兼容的数据类型DoubleType和LongType
,当它为false时,读取数据有效。打印架构显示该列为双重类型,
show()
命令显示了前20行,但该列上的筛选和分组失败:
Cost声明的类型(java.lang.double)与文件元数据中找到的架构不匹配。
听起来有些文件的架构不一致,而最近发布的架构不一致。他们的一个关键主题是“永远不要删除字段,只在末尾添加它们”。毕竟,如果您将字段标记为可选,则可以忽略数据。就像我说的,这不是我工作的领域。我所知道的是,模式合并需要parquet在每个文件的末尾读取模式,这是非常昂贵的,尤其是在Hadoop<2.8上,在s3a上查找是非常昂贵的。如果你必须进行合并,你必须承担责任。抱歉是的,当前合并没有帮助,因为它无法选择一种类型并使用它。它所做的唯一一件事是在读取模式不符合matc时抛出异常
 val binary_zip_RDD = sc.binaryFiles(batchHolder.get(i), minPartitions = 50000)
 // rdd[String]  each string is a json ,lowercased json
    val TransformedRDD = binary_zip_RDD.flatMap(kv => ZipDecompressor.Zip_open_hybrid(kv._1, kv._2, proccessingtimestamp))
 // now the schema of dataframe would be consolidate schema of all json strings
    val jsonDataframe_stream = sparkSession.read.option("primitivesAsString", true).json(TransformedRDD)

    println(jsonDataframe_stream.printSchema())


    jsonDataframe_stream.write.mode(SaveMode.Append).partitionBy(GetConstantValue.DEVICEDATE).parquet(ApplicationProperties.OUTPUT_DIRECTORY)