web-dev-qa-db-ja.com

Apacheで寄木細工スキーマの変更を処理する方法Spark

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倍にキャストできたとしても、スキーマが変更される可能性があり、新しい列を追加でき、これを追跡することはできません。

一部の人々が同じ問題を抱えているのを見てきましたが、まだ十分な解決策を見つけていません。

このためのベストプラクティスまたはソリューションは何ですか?

18
V. Samma

これらは、寄せ木張りをS3に書き込むために使用するオプションです。スキーマのマージをオフにすると、ライトバックのパフォーマンスが向上します-問題に対処することもできます

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

データフレームとして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)
0
siva krishna