我正在将Apache Beam与Java结合使用。 我正在尝试使用本地模式在预先部署的Spark env上使用SparkRunner读取csv文件并将其写入拼花格式。 DirectRunner一切正常,但是SparkRunner无法正常工作。 我正在使用Maven Shade插件构建胖子。
代码如下:
Java:
public class ImportCSVToParquet{
-- ommitted
File csv = new File(filePath);
PCollection<String> vals = pipeline.apply(TextIO.read().from(filePath));
String parquetFilename = csv.getName().replaceFirst("csv", "parquet");
String outputLocation = FolderConventions.getRawFilePath(confETL.getHdfsRoot(), parquetFilename);
PCollection<GenericRecord> processed = vals.apply(ParDo.of(new ProcessFiles.GenericRecordFromCsvFn()))
.setCoder(AvroCoder.of(new Config().getTransactionSchema()));
LOG.info("Processed file will be written to: " + outputLocation);
processed.apply(FileIO.<GenericRecord>write().via(ParquetIO.sink(conf.getTransactionSchema())).to(outputLocation));
pipeline.run().waitUntilFinish();
}
POM依赖项:
<dependencies>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-sdks-java-core</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-direct-java</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-spark</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-sdks-java-io-parquet</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.11</artifactId>
<version>2.2.3</version>
</dependency>
/dependencies>
火花脚本:
spark-submit \
--class package.ImportCSVToParquet \
--master local[*] \
--executor-cores 2 \
--executor-memory 2g \
--driver-memory 2g \
--driver-cores 2 \
--conf spark.sql.codegen.wholeStage=false \
--conf spark.wholeStage.codegen=false \
--conf spark.sql.shuffle.partitions=2005 \
--conf spark.driver.maxResultSize=2g \
--conf spark.executor.memoryOverhead=4048 \
--conf "spark.executor.extraJavaOptions=-XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=35" \
--conf "spark.driver.extraJavaOptions=-Djava.io.tmpdir=/path-to-tmp/" \
--conf "spark.driver.extraClassPath=./" \
--jars path-to-jar \
/path-to-jar "$@"
我收到以下错误:
2019-08-07 13:37:49 ERROR Executor:91 - Exception in task 3.0 in stage 0.0 (TID 3)
org.apache.beam.sdk.util.UserCodeException: java.lang.NoSuchMethodError: org.apache.parquet.hadoop.ParquetWriter$Builder.<init>(Lorg/apache/parquet/io/OutputFile;)V
at org.apache.beam.sdk.util.UserCodeException.wrap(UserCodeException.java:34)
at org.apache.beam.sdk.io.WriteFiles$WriteUnshardedTempFilesFn$DoFnInvoker.invokeProcessElement(Unknown Source)
at org.apache.beam.runners.core.SimpleDoFnRunner.invokeProcessElement(SimpleDoFnRunner.java:214)
at org.apache.beam.runners.core.SimpleDoFnRunner.processElement(SimpleDoFnRunner.java:176)
at org.apache.beam.runners.spark.translation.DoFnRunnerWithMetrics.processElement(DoFnRunnerWithMetrics.java:65)
at org.apache.beam.runners.spark.translation.SparkProcessContext$ProcCtxtIterator.computeNext(SparkProcessContext.java:137)
at org.apache.beam.vendor.guava.v20_0.com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:145)
at org.apache.beam.vendor.guava.v20_0.com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:140)
at scala.collection.convert.Wrappers$JIteratorWrapper.hasNext(Wrappers.scala:42)
at org.apache.spark.storage.memory.MemoryStore.putIteratorAsValues(MemoryStore.scala:215)
at org.apache.spark.storage.BlockManager$$anonfun$doPutIterator$1.apply(BlockManager.scala:1038)
at org.apache.spark.storage.BlockManager$$anonfun$doPutIterator$1.apply(BlockManager.scala:1029)
at org.apache.spark.storage.BlockManager.doPut(BlockManager.scala:969)
at org.apache.spark.storage.BlockManager.doPutIterator(BlockManager.scala:1029)
at org.apache.spark.storage.BlockManager.getOrElseUpdate(BlockManager.scala:760)
at org.apache.spark.rdd.RDD.getOrCompute(RDD.scala:334)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:285)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:49)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:49)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:49)
at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)
at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)
at org.apache.spark.scheduler.Task.run(Task.scala:109)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:344)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NoSuchMethodError: org.apache.parquet.hadoop.ParquetWriter$Builder.<init>(Lorg/apache/parquet/io/OutputFile;)V
at org.apache.parquet.avro.AvroParquetWriter$Builder.<init>(AvroParquetWriter.java:162)
at org.apache.parquet.avro.AvroParquetWriter$Builder.<init>(AvroParquetWriter.java:153)
at org.apache.parquet.avro.AvroParquetWriter.builder(AvroParquetWriter.java:43)
at org.apache.beam.sdk.io.parquet.ParquetIO$Sink.open(ParquetIO.java:304)
at org.apache.beam.sdk.io.FileIO$Write$ViaFileBasedSink$1$1.prepareWrite(FileIO.java:1359)
at org.apache.beam.sdk.io.FileBasedSink$Writer.open(FileBasedSink.java:937)
at org.apache.beam.sdk.io.WriteFiles$WriteUnshardedTempFilesFn.processElement(WriteFiles.java:533)
似乎该作业可以进行读取和转换,但是在尝试写入文件系统时会失败。我目前不使用HDFS。有什么想法吗?
答案 0 :(得分:5)
我确定ParquetIO依赖于Parquet 1.10+版本,该版本为Parquet文件读取器/写入器添加了“与Hadoop无关的” API。
Spark 2.2.3 depends on Parquet 1.8.2,它没有Beam ParquetIO使用的builder(...)构造函数,该异常已得到确认。
如果可能的话,最简单的解决方案是将Spark升级到Spark 2.4,使Parquet版本升至1.10.0。
如果您无法升级Spark版本,则有两种技术可以覆盖Spark带来的jar:
您可以将spark.(driver|executor).userClassPathFirst
设置为true
,这会将类放在您的胖罐中,而不是spark提供的罐中。这可能行得通,或者可能引入新的依赖冲突。
您可以尝试将本地Spark安装中的parquet-xx-1.8.2.jar
替换为parquet-xx-1.10.0
(假设它们是临时替代品)。如果可行,则可以通过在提交作业时设置spark.yarn.jars
属性,将相同的策略应用于群集中的Spark作业。
您可以在胖罐中尝试遮蔽光束ParquetIO及其对木地板的依赖性。
编辑:这是一个已知问题BEAM-5164。
编辑(解决方法):
通过遵循instructions进行一些修改,我设法使它适用于Spark 2.2.3:
我使用了scala 2.11依赖项并将其设置为<scope>provided</scope>
(可能是可选的)。
我在maven-shade-plugin
上添加了以下三个位置:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
... unchanged ...
</filters>
<relocations>
<relocation>
<pattern>org.apache.parquet</pattern>
<shadedPattern>shaded.org.apache.parquet</shadedPattern>
</relocation>
<!-- Some packages are shaded already, and on the original spark classpath. Shade them more. -->
<relocation>
<pattern>shaded.parquet</pattern>
<shadedPattern>reshaded.parquet</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.avro</pattern>
<shadedPattern>shaded.org.apache.avro</shadedPattern>
</relocation>
</relocations>
</configuration>
<executions>
... unchanged ...
</executions>
</plugin>
</plugins>
</build>
答案 1 :(得分:1)
请勿使用spark.driver.userClassPathFirst
和spark.executor.userClassPathFirst
,因为尚处于实验阶段。但实际上,请使用spark.driver.extraClassPath
和spark.executor.extraClassPath
。
官方documentation的定义:“要在驱动程序的类路径之前附加类路径条目。”
示例:
-conf spark.driver.extraClassPath = C:\ Users \ Khalid \ Documents \ Projects \ libs \ jackson-annotations-2.6.0.jar; C:\ Users \ Khalid \ Documents \ Projects \ libs \ jackson- core-2.6.0.jar; C:\ Users \ Khalid \ Documents \ Projects \ libs \ jackson-databind-2.6.0.jar
这解决了我的问题(我要使用的Jackson版本与正在使用的火花之间存在冲突)。
希望有帮助。