解决Spark读取tmp结尾的文件报错的问题

文章讲述了在Flume采集文件到HDFS过程中,文件会有.tmp后缀,Spark读取Hive外部表时会遇到找不到.xxx.tmp文件的问题。通过实现Hadoop的PathFilter接口,创建自定义的ExcludeTmpFile类来过滤掉.tmp文件,打包成jar并引入到Spark程序中,通过配置mapred.input.pathFilter.class参数来解决这个问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

业务场景

flume采集文件到hdfs中,在采集中的文件会添加.tmp后缀。一个批次完成提交后,会将.tmp后缀重名名,将tmp去掉。
所以,当Spark程序读取到该hive外部表映射的路径时,在出现找不到xxx.tmp文件的问题出现。

解决思路:

Hdfs提供了读取文件筛选的接口PathFilter。
image
这个接口在hadoop-common包中,所以我们实现这个接口即可。

解决方法:

1.实现PathFilter接口,添加过滤文件后缀的逻辑。

新建了一个项目HdfsFileFilter,在项目中新建了一个类ExcludeTmpFile,如下

package org.apache.hadoop.hdfs;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.PathFilter;

/**
 * @Author: KingWang
 * @Date: 2023/4/13
 * @Desc: 解决读取hive外部表时,过滤tmp后缀的文件
 **/
class ExcludeTmpFile implements PathFilter {

    @Override
    public boolean accept(Path path) {

        return !path.getName().startsWith("_") && !path.getName().startsWith(".") && !path.getName().endsWith(".tmp");
    }
}

在Pom中引入

    <dependencies>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>3.0.0-cdh6.3.1</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <repositories>
        <repository>
            <id>cloudera</id>
            <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>
    </repositories>

2.打包部署

生成的包文件HdfsFileFilter-1.0.0.jar,然后上传到服务器。
我的目录是/home/hadoop/extra-jars/HdfsFileFilter-1.0.0.jar

3. 使用方法

在执行程序中引入包:

spark-shell --master yarn \
--queue root.users.hadoop \
--driver-memory 8G --executor-memory 8G \
--num-executors 50 --executor-cores 2  \
--jars /home/hadoop/extra-jars/HdfsFileFilter-1.0.0.jar \
--conf spark.driver.maxResultSize=20G \
--conf spark.port.maxRetries=16 \
--conf spark.executor.memoryOverhead=5120 \
--conf spark.dynamicAllocation.enabled=false \
--name testSparkShell

在程序中添加以下配置

spark.conf.set("mapred.input.pathFilter.class","org.apache.hadoop.hdfs.ExcludeTmpFile")
### 回答1: 如果在 Spark 中使用 `saveAsTextFile()` 方法将 RDD 保存到本地文件系统或 Hadoop 分布式文件系统 (HDFS) 时,如果文件已经存在,则会抛出 `FileAlreadyExistsException` 异常。 为了解决这个问题,您可以使用 `overwrite` 参数来强制 Spark 覆盖现有文件。例如: ``` rdd.saveAsTextFile("/path/to/output", overwrite=True) ``` 您也可以使用 `deleteOnExit` 参数,这样在退出时就会删除给定的路径: ``` rdd.saveAsTextFile("/path/to/output", deleteOnExit=True) ``` 但是,请注意,使用 `deleteOnExit` 参数可能会导致性能问题,因为 Spark 在退出时必须扫描所有输出文件并删除它们。因此,建议您使用 `overwrite` 参数。 ### 回答2: 当使用Spark覆写原文件夹时,可能会遇到 FileAlreadyExistsException 文件已存在的报错。 FileAlreadyExistsException 是一个异常类,表示文件已经存在。它通常在尝试创建或覆盖已经存在的文件时抛出。 要解决这个问题,可以采取以下几种方法: 1. 根据需求使用不同的保存模式: - 如果要覆盖原文件夹,可以使用 `mode("overwrite")` 或 `mode(SaveMode.Overwrite)` 来强制覆盖已存在的文件。 - 如果要将新数据追加到原文件夹中,可以使用 `mode("append")` 或 `mode(SaveMode.Append)` 来将数据追加到已存在的文件中。 - 如果只想在原文件夹中创建新文件,并保留原有文件,可以使用 `mode("ignore")` 或 `mode(SaveMode.Ignore)` 来跳过已存在的文件。 2. 先删除原文件夹再保存新文件: - 在覆写前,可以使用文件系统 API(如 Hadoop HDFS 的 `FileSystem`)或操作系统命令(如 `rm`)来删除原文件夹及其中的文件,然后再保存新的文件。 3. 修改保存路径: - 将新文件保存到一个新的路径,避免覆盖原文件夹中的文件。 无论采取哪种方法,都需要注意数据的保存方式和目标路径的正确性,以避免出现不可预知的问题。另外,在覆写文件夹时请谨慎操作,确保不会误删或误覆盖重要数据。 ### 回答3: 当在Spark中尝试覆写原文件文件时,可能会遇到FileAlreadyExistsException的错误。这个错误是由于原文件夹中的文件已经存在,而覆写操作需要删除原文件夹并创建新的文件夹来完成。下面是解决这个问题的几种方法: 1. 修改写入模式(Write Mode):在写入文件时,可以通过指定不同的写入模式来解决问题。比如,可以将写入模式设置为"overwrite"来覆盖原文件夹中的文件。例如: df.write.mode("overwrite").csv("path/to/directory") 2. 删除原文件夹:在覆写操作之前,手动删除原文件夹中的文件。可以使用文件系统操作(如使用bash命令`rm -r`)或者使用Spark的API来删除文件夹。例如: import org.apache.hadoop.fs.Path import org.apache.hadoop.fs.FileSystem val path = new Path("path/to/directory") val fs = FileSystem.get(sparkSession.sparkContext.hadoopConfiguration) fs.delete(path, true) 3. 更改覆写路径:如果原文件夹无法删除,可以考虑将新的文件写入到另一个路径,而不是原文件夹中。这样可以避免出现FileAlreadyExistsException错误。例如: df.write.csv("path/to/newdirectory") 请注意,在使用这些方法之前,确保已备份原文件夹中的文件,因为这些操作会对数据产生修改或删除。此外,还需要确认在Spark环境中是否有足够的权限来执行这些操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

硅谷工具人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值