ParquetデータがS3の毎日のチャンクとして(s3://bucketName/prefix/YYYY/MM/DD/
の形式で)ある問題に遭遇しましたが、一部の列タイプのために異なる日付からAWS EMR Sparkのデータを読み取ることができません一致せず、次のような多くの例外の1つを受け取ります。
Java.lang.ClassCastException: optional binary element (UTF8) is not a group
一部のファイルに値を持つ配列型があるが、同じ列が他のファイルにnull
値を持つ場合に表示されます。この値はその後、String型として推測されます。
または
org.Apache.spark.SparkException: Job aborted due to stage failure: Task 23 in stage 42.0 failed 4 times, most recent failure: Lost task 23.3 in stage 42.0 (TID 2189, ip-172-31-9-27.eu-west-1.compute.internal):
org.Apache.spark.SparkException: Failed to merge incompatible data types ArrayType(StructType(StructField(Id,LongType,true), StructField(Name,StringType,true), StructField(Type,StringType,true)),true)
JSON形式のS3の未加工データがあり、私の最初の計画は、EMRクラスターを開始し、前の日付のJSONデータを読み取り、単純に寄木細工としてS3に書き込む自動ジョブを作成することでした。
JSONデータも日付に分割されます。つまり、キーには日付プレフィックスが付きます。 JSONの読み取りは正常に機能します。現在読み込まれているデータの量に関係なく、スキーマはデータから推測されます。
しかし、寄せ木細工のファイルが書き込まれると、問題が発生します。理解しているように、メタデータファイルで寄木細工を書くとき、これらのファイルには、寄木細工ファイルのすべてのパーツ/パーティションのスキーマが含まれています。私には、異なるスキーマを使用することもできます。メタデータの書き込みを無効にすると、Sparkは、指定されたParquetパス内の最初のファイルからスキーマ全体を推測し、他のファイルでも同じままであると推測されました。
double
型であるはずの一部の列が特定の日の整数値のみを持ち、JSON(これらの数値を整数として、浮動小数点なしで)から読み取ると、Sparkが考えられますタイプはlong
の列です。 Parquetファイルを書き込む前にこれらの列を2倍にキャストできたとしても、スキーマが変更される可能性があり、新しい列を追加でき、これを追跡することはできません。
一部の人々が同じ問題を抱えているのを見てきましたが、まだ十分な解決策を見つけていません。
このためのベストプラクティスまたはソリューションは何ですか?
これらは、寄せ木張りをS3に書き込むために使用するオプションです。スキーマのマージをオフにすると、ライトバックのパフォーマンスが向上します-問題に対処することもできます
val PARQUET_OPTIONS = Map(
"spark.sql.parquet.mergeSchema" -> "false",
"spark.sql.parquet.filterPushdown" -> "true")
データフレームとしてrddを作成するときに、各文字列がjsonであるrdd [String]を作成するだけで、primitiveAsStringオプションを使用してすべてのデータ型をStringにする
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)