Hadoop: 方案无文件系统:file。

109

我正在尝试使用hadoop运行一个简单的NaiveBayesClassifier,但出现了以下错误:

Exception in thread "main" java.io.IOException: No FileSystem for scheme: file
    at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:1375)
    at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:66)
    at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:1390)
    at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:196)
    at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:95)
    at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:180)
    at org.apache.hadoop.fs.Path.getFileSystem(Path.java:175)
    at org.apache.mahout.classifier.naivebayes.NaiveBayesModel.materialize(NaiveBayesModel.java:100)

代码:

    Configuration configuration = new Configuration();
    NaiveBayesModel model = NaiveBayesModel.materialize(new Path(modelPath), configuration);// error in this line..

modelPath指向NaiveBayes.bin文件,配置对象打印出-Configuration: core-default.xml, core-site.xml

我认为这是由于jars引起的,有什么想法吗?


需要更多信息... - Tariq
2
我自己不确定,但是在谷歌上快速搜索表明,有一些问题围绕着JAR文件没有像你建议的那样被引用。也许以下链接会得出答案。 https://groups.google.com/a/cloudera.org/forum/#!topic/scm-users/lyho8ptAzE0 http://grokbase.com/t/cloudera/cdh-user/134r64jm5t/no-filesystem-for-scheme-hdfs - Emile
1
嗯...你能告诉我关于你的环境的情况吗?同时,请给我展示完整的异常信息。 - Tariq
modelPath的值是多少?你尝试过 file:///path/to/dir 吗? - Chris White
正如@emile建议的那样,请确保您通过hadoop而不是java运行您的jar文件。即使用"hadoop jar"来运行分布式jar文件,而不是尝试执行独立的"java -jar"。 - matthieu lieber
显示剩余3条评论
20个回答

193

这是典型的maven-assembly插件引起问题的案例。

为什么会发生这种情况

不同的JAR(LocalFileSystemhadoop-commonsDistributedFileSystemhadoop-hdfs)每个都包含一个名为org.apache.hadoop.fs.FileSystem的文件在它们的META-INFO/services目录中。该文件列出了他们想要声明的文件系统实现的规范类名称(这是通过java.util.ServiceLoader实现的服务提供者接口,参见org.apache.hadoop.FileSystem#loadFileSystems)。

当我们使用maven-assembly-plugin时,它将所有JAR合并为一个,所有的META-INFO/services/org.apache.hadoop.fs.FileSystem将彼此覆盖。只有一个这样的文件留下(最后添加的文件)。 在这种情况下,hadoop-commonsFileSystem列表覆盖了hadoop-hdfs的列表,因此DistributedFileSystem不再被声明。

我们是如何解决这个问题的

在加载Hadoop配置之后,但在执行任何与FileSystem相关的操作之前,我们调用以下代码:

    hadoopConfig.set("fs.hdfs.impl", 
        org.apache.hadoop.hdfs.DistributedFileSystem.class.getName()
    );
    hadoopConfig.set("fs.file.impl",
        org.apache.hadoop.fs.LocalFileSystem.class.getName()
    );

更新:正确的修复方法

我被 krookedking 注意到有一种基于配置的方法可以使maven-assembly使用所有FileSystem服务声明的合并版本,请查看他在下面的回答


13
以下是在Spark中执行相同操作所需的等效代码:val hadoopConfig: Configuration = spark.hadoopConfiguration hadoopConfig.set("fs.hdfs.impl", classOf[org.apache.hadoop.hdfs.DistributedFileSystem].getName) hadoopConfig.set("fs.file.impl", classOf[org.apache.hadoop.fs.LocalFileSystem].getName) - Philip O.
8
事实上,我只是将这个 Maven 依赖 http://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs/2.2.0 添加到 Maven 中,问题就解决了。 - B.Mr.W.
6
我尝试添加了hadoop-hdfs、hadoop-core、hadoop-common和hadoop-client,也尝试了添加以下内容: hadoopConfig.set("fs.hdfs.impl", org.apache.hadoop.hdfs.DistributedFileSystem.class.getName()); hadoopConfig.set("fs.file.impl", org.apache.hadoop.fs.LocalFileSystem.class.getName()); 但仍然无法正常运行。在Eclipse中运行时没有问题,但通过java -cp命令运行时会显示以上错误。 - Harish Pathak
1
Harish,你看到了什么?我这里也遇到了同样的问题,但是是在IntelliJ中。 - ThommyH
只是对这个精彩答案的补充:如果使用hadoop JARS但在非hadoop集群中运行作业,"""hadoopConfig.set("fs.hdfs.impl.....""""将不起作用。在这种情况下,我们将退回到管理汇编构建。例如,在sbt中,我们可以执行concat或filterDistinctLines的mergeStrategy。 - human
显示剩余3条评论

75

如果您正在使用shade插件,在遵循david_p的建议后,您可以通过将ServicesResourceTransformer添加到插件配置中来合并阴影jar中的服务:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.3</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
          </transformers>
        </configuration>
      </execution>
    </executions>
  </plugin>
这将把所有org.apache.hadoop.fs.FileSystem服务合并到一个文件中。

3
我最喜欢这个解决方案。与事后通过配置更改来修补问题不同,它直接从源头(构建)解决问题。 - Kevin Pauli
1
非常好的答案。解决了我类似的错误。我尝试过maven-assembly-plugin以及maven-jar-plugin/maven-dependency-plugin组合,但都没有成功。这个解决方案让我的Spark应用程序工作了。非常感谢! - somnathchakrabarti
非常好的答案!非常感谢! - andrea.lagala
优秀的答案。 - Niranjan Subramanian
非常感谢,非常有帮助! - mwol
显示剩余4条评论

11

用Spark 2.0.2花了我很长时间才弄明白,但是这是我找到的方法:

val sparkBuilder = SparkSession.builder
.appName("app_name")
.master("local")
// Various Params
.getOrCreate()

val hadoopConfig: Configuration = sparkBuilder.sparkContext.hadoopConfiguration

hadoopConfig.set("fs.hdfs.impl", classOf[org.apache.hadoop.hdfs.DistributedFileSystem].getName)

hadoopConfig.set("fs.file.impl", classOf[org.apache.hadoop.fs.LocalFileSystem].getName)

以下是我build.sbt的相关部分:

scalaVersion := "2.11.8"
libraryDependencies += "org.apache.spark" %% "spark-core" % "2.0.2"

我希望这能帮到你!


一直在苦苦思索,最终找到了解决方案。谢谢! - l Steveo l
只有在作为汇编jar运行时,我才会遇到错误。 - l Steveo l

9
记录一下,这个问题仍然在hadoop 2.4.0中存在。非常令人沮丧...
我能够按照这个链接中的说明进行操作:http://grokbase.com/t/cloudera/scm-users/1288xszz7r/no-filesystem-for-scheme-hdfs 我将以下内容添加到我的core-site.xml中,它起作用了:
<property>
   <name>fs.file.impl</name>
   <value>org.apache.hadoop.fs.LocalFileSystem</value>
   <description>The FileSystem for file: uris.</description>
</property>

<property>
   <name>fs.hdfs.impl</name>
   <value>org.apache.hadoop.hdfs.DistributedFileSystem</value>
   <description>The FileSystem for hdfs: uris.</description>
</property>

8

感谢David_p和Scala。

conf.set("fs.hdfs.impl", classOf[org.apache.hadoop.hdfs.DistributedFileSystem].getName);
conf.set("fs.file.impl", classOf[org.apache.hadoop.fs.LocalFileSystem].getName);

或者

<property>
 <name>fs.hdfs.impl</name>
 <value>org.apache.hadoop.hdfs.DistributedFileSystem</value>
</property>

1
只有在阅读这篇文章后,我才意识到这里的“conf”是指Hadoop配置:https://brucebcampbell.wordpress.com/2014/12/11/fix-hadoop-hdfs-error-java-io-ioexception-no-filesystem-for-scheme-hdfs-at-org-apache-hadoop-fs-filesystem-getfilesystemclassfilesystem-java2385/。 - Sal

7

5
假设你正在使用mvn和cloudera hadoop发行版。我正在使用cdh4.6,添加这些依赖项对我很有用。我认为你应该检查hadoop和mvn依赖项的版本。
<dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-core</artifactId>
        <version>2.0.0-mr1-cdh4.6.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>2.0.0-cdh4.6.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>2.0.0-cdh4.6.0</version>
    </dependency>

不要忘记添加Cloudera mvn仓库。
<repository>
        <id>cloudera</id>
        <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>

5

我使用sbt assembly来打包我的项目,也遇到了这个问题。我的解决方案在这里。 步骤1:在你的build.sbt中添加META-INF mergestrategy。

case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
case PathList("META-INF", ps @ _*) => MergeStrategy.first

步骤2:将Hadoop-hdfs库添加到build.sbt中。
"org.apache.hadoop" % "hadoop-hdfs" % "2.4.0"

第三步:sbt clean; sbt assembly
希望以上信息能够帮到您。

19
更好的解决方案可能是合并类似于以下代码:case PathList("META-INF", "services", "org.apache.hadoop.fs.FileSystem") => MergeStrategy.filterDistinctLines。这将保留所有已注册的文件系统。 - rav
感谢 @ravwojdyla ,提供了非常好的解决方案。你救了我大忙。对于那些在Apache Spark中寻找答案的迷失灵魂,将此添加到 build.sbt 中,当使用 sbt-assembly 时可以正常工作。 - Greedy Coder
@ravwojdyla 提供的解决方案是唯一一个对我有效的。 - Sergey Kovalev
4
@ravwojdyla提供的解决方案是理想的。我在build.sbt中进行了类似的设置,并使用了以下内容:assemblyMergeStrategy in assembly := { case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard case PathList("META-INF", "services", "org.apache.hadoop.fs.FileSystem") => MergeStrategy.concat case _ => MergeStrategy.first } - human
1
@human 在使用您的设置之前,一切都不起作用!赞! - ambushed

3

如果你正在使用Gradle Shadow插件,则需要添加以下配置:

shadowJar {
    mergeServiceFiles()
}

3

我遇到了同样的问题,找到了两种解决方案: (1)手动编辑jar文件:

使用WinRar(或类似工具)打开jar文件。进入Meta-info>services,通过添加以下内容来编辑"org.apache.hadoop.fs.FileSystem":

org.apache.hadoop.fs.LocalFileSystem

(2) 将我的依赖项按照以下顺序进行更改

<dependencies>
<dependency>
  <groupId>org.apache.hadoop</groupId>
  <artifactId>hadoop-hdfs</artifactId>
  <version>3.2.1</version>
</dependency>

<dependency>
  <groupId>org.apache.hadoop</groupId>
  <artifactId>hadoop-common</artifactId>
  <version>3.2.1</version>
</dependency>

<dependency>
  <groupId>org.apache.hadoop</groupId>
  <artifactId>hadoop-mapreduce-client-core</artifactId>
  <version>3.2.1</version>
</dependency>

<dependency>
  <groupId>org.apache.hadoop</groupId>
  <artifactId>hadoop-client</artifactId>
  <version>3.2.1</version>
</dependency>



</dependencies>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接