J'essaie de tester l'écriture de données dans HDFS 2.7 à l'aide de Spark 2.1. Mes données sont une simple séquence de valeurs factices et la sortie doit être partitionnée par les attributs: id et clé .
// Simple case class to cast the data
case class SimpleTest(id:String, value1:Int, value2:Float, key:Int)
// Actual data to be stored
val testData = Seq(
SimpleTest("test", 12, 13.5.toFloat, 1),
SimpleTest("test", 12, 13.5.toFloat, 2),
SimpleTest("test", 12, 13.5.toFloat, 3),
SimpleTest("simple", 12, 13.5.toFloat, 1),
SimpleTest("simple", 12, 13.5.toFloat, 2),
SimpleTest("simple", 12, 13.5.toFloat, 3)
)
// Spark's workflow to distribute, partition and store
// sc and sql are the SparkContext and SparkSession, respectively
val testDataP = sc.parallelize(testData, 6)
val testDf = sql.createDataFrame(testDataP).toDF("id", "value1", "value2", "key")
testDf.write.partitionBy("id", "key").parquet("/path/to/file")
Je m'attends à obtenir l'arborescence suivante dans HDFS:
- /path/to/file
|- /id=test/key=1/part-01.parquet
|- /id=test/key=2/part-02.parquet
|- /id=test/key=3/part-03.parquet
|- /id=simple/key=1/part-04.parquet
|- /id=simple/key=2/part-05.parquet
|- /id=simple/key=3/part-06.parquet
Mais quand je lance le code précédent, j'obtiens le résultat suivant:
/path/to/file/id=/key=24/
|-/part-01.parquet
|-/part-02.parquet
|-/part-03.parquet
|-/part-04.parquet
|-/part-05.parquet
|-/part-06.parquet
Je ne sais pas s'il y a quelque chose qui cloche dans le code ou s'il y a autre chose que Spark est en train de faire.
J'exécute spark-submit
comme suit:
spark-submit --name APP --master local --driver-memory 30G --executor-memory 30G --executor-core 8 --num-executors 8 --conf spark.io.compression.codec = lzf --conf spark.akka.frameSize = 1024 --conf spark.driver.maxResultSize = 1g --conf spark.sql.orc.compression.codec = non compressé --conf spark.sql.parquet.filterPushdown = true - classe myClass myFatJar.jar
J'ai trouvé une solution! Selon Cloudera, il s'agit d'un problème de configuration mapred-site.xml (consultez le lien ci-dessous). De plus, au lieu d’écrire le cadre de données sous la forme suivante: testDf.write.partitionBy("id", "key").parquet("/path/to/file")
Je l'ai fait comme suit: testDf.write.partitionBy("id", "key").parquet("hdfs://<namenode>:<port>/path/to/file")
. Vous pouvez remplacer <namenode>
et <port>
par le nom et le port du code de masquage du HDFS.
Un merci spécial à @ jacek-laskowski, pour sa précieuse contribution.
Références:
https://community.cloudera.com/t5/Batch-SQL-Apache-Hive/MKDirs-failed-to-create-file/m-p/36363#M1090
Intéressant depuis ... bon ... "ça marche pour moi" .
Lorsque vous décrivez votre ensemble de données à l'aide de la classe de cas SimpleTest
dans Spark 2.1, vous devez quitter import spark.implicits._
pour avoir une Dataset
saisie.
Dans mon cas, spark
est sql
.
En d'autres termes, vous n'avez pas besoin de créer testDataP
et testDf
(en utilisant sql.createDataFrame
).
import spark.implicits._
...
val testDf = testData.toDS
testDf.write.partitionBy("id", "key").parquet("/path/to/file")
Dans un autre terminal (après avoir sauvegardé dans le répertoire /tmp/testDf
):
$ tree /tmp/testDf/
/tmp/testDf/
├── _SUCCESS
├── id=simple
│ ├── key=1
│ │ └── part-00003-35212fd3-44cf-4091-9968-d9e2e05e5ac6.c000.snappy.parquet
│ ├── key=2
│ │ └── part-00004-35212fd3-44cf-4091-9968-d9e2e05e5ac6.c000.snappy.parquet
│ └── key=3
│ └── part-00005-35212fd3-44cf-4091-9968-d9e2e05e5ac6.c000.snappy.parquet
└── id=test
├── key=1
│ └── part-00000-35212fd3-44cf-4091-9968-d9e2e05e5ac6.c000.snappy.parquet
├── key=2
│ └── part-00001-35212fd3-44cf-4091-9968-d9e2e05e5ac6.c000.snappy.parquet
└── key=3
└── part-00002-35212fd3-44cf-4091-9968-d9e2e05e5ac6.c000.snappy.parquet
8 directories, 7 files