J'essaie de lancer une NaiveBayesClassifer
simple en utilisant hadoop, ce qui provoque cette erreur
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)
Code:
Configuration configuration = new Configuration();
NaiveBayesModel model = NaiveBayesModel.materialize(new Path(modelPath), configuration);// error in this line..
modelPath
pointe vers le fichier NaiveBayes.bin
et l'objet de configuration est en cours d'impression - Configuration: core-default.xml, core-site.xml
Je pense que c'est à cause des pots, des idées?
C'est un cas typique du plugin maven-Assembly
qui casse des choses.
Différents JAR (hadoop-commons
pour LocalFileSystem
, hadoop-hdfs
pour DistributedFileSystem
) contiennent chacun un fichier différent appelé org.Apache.hadoop.fs.FileSystem
dans leur répertoire META-INFO/services
. Ce fichier répertorie les noms de classe canoniques des implémentations du système de fichiers qu’ils souhaitent déclarer (l’appelle une interface de fournisseur de services implémentée via Java.util.ServiceLoader
, voir org.Apache.hadoop.FileSystem
ligne 2622 ).
Lorsque nous utilisons maven-Assembly-plugin
, tous nos fichiers JAR sont fusionnés en un seul et tous les META-INFO/services/org.Apache.hadoop.fs.FileSystem
se écrasent. Un seul de ces fichiers reste (le dernier ajouté). Dans ce cas, la liste FileSystem
de hadoop-commons
remplace la liste de hadoop-hdfs
, de sorte que DistributedFileSystem
n'a plus été déclaré.
Après avoir chargé la configuration Hadoop, mais juste avant de faire quoi que ce soit lié à FileSystem
-, nous appelons ceci:
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
a porté à mon attention qu'il existe un moyen basé sur la configuration pour que le maven-Assembly
utilise une version fusionnée de toutes les déclarations de services FileSystem
. Ajoutez le plugin suivant à votre fichier pom.xml
:
<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>
Pour ceux qui utilisent le plugin shade, suivant les conseils de david_p, vous pouvez fusionner les services dans le fichier jar ombré en ajoutant le serviceResourceTransformer à la configuration du plugin:
<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>
Cela va fusionner tous les services org.Apache.hadoop.fs.FileSystem dans un fichier
Pour mémoire, cela se produit encore dans hadoop 2.4.0. Tellement frustrant...
J'ai pu suivre les instructions de ce lien: http://grokbase.com/t/cloudera/scm-users/1288xszz7r/no-filesystem-for-scheme-hdfs
J'ai ajouté ce qui suit à mon core-site.xml et cela a fonctionné:
<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>
merci 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);
ou
<property>
<name>fs.hdfs.impl</name>
<value>org.Apache.hadoop.hdfs.DistributedFileSystem</value>
</property>
Cela m'a pris du temps pour le comprendre avec Spark 2.0.2, mais voici mon petit mot:
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)
Et les parties pertinentes de mon build.sbt
:
scalaVersion := "2.11.8"
libraryDependencies += "org.Apache.spark" %% "spark-core" % "2.0.2"
J'espère que cela peut aider!
Pour maven, il suffit d'ajouter la dépendance de maven pour hadoop-hdfs (voir le lien ci-dessous) qui résoudra le problème.
http://mvnrepository.com/artifact/org.Apache.hadoop/hadoop-hdfs/2.7.1
J'utilise sbt Assembly pour emballer mon projet. Je rencontre aussi ce problème. Ma solution est ici. Étape 1: ajoutez la stratégie de fusion META-INF dans votre build.sbt
case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
case PathList("META-INF", ps @ _*) => MergeStrategy.first
Étape 2: ajoutez la bibliothèque hadoop-hdfs à build.sbt
"org.Apache.hadoop" % "hadoop-hdfs" % "2.4.0"
Step3: sbt propre; sbt assemblée
J'espère que les informations ci-dessus peuvent vous aider.
En supposant que vous utilisez la distribution mvn et cloudera de hadoop. J'utilise cdh4.6 et l'ajout de ces dépendances a fonctionné pour moi. Je pense que vous devriez vérifier les versions des dépendances hadoop et 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>
n'oubliez pas d'ajouter le référentiel mcln cloudera.
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
Une autre cause possible (bien que la question des OP ne souffre pas de cela) est si vous créez une instance de configuration qui ne charge pas les valeurs par défaut:
Configuration config = new Configuration(false);
Si vous ne chargez pas les paramètres par défaut, vous n'obtiendrez pas les paramètres par défaut pour des applications telles que les implémentations FileSystem
, qui entraînent des erreurs identiques, lorsque vous essayez d'accéder à HDFS. Le passage au constructeur sans paramètre de transmission de true
pour charger les valeurs par défaut peut résoudre le problème.
De plus, si vous ajoutez des emplacements de configuration personnalisés (par exemple sur le système de fichiers) à l'objet Configuration
, faites attention à la surcharge de addResource()
que vous utilisez. Par exemple, si vous utilisez addResource(String)
, Hadoop suppose que la chaîne est une ressource de chemin de classe. Si vous devez spécifier un fichier local, procédez comme suit:
File configFile = new File("example/config.xml");
config.addResource(new Path("file://" + configFile.getAbsolutePath()));
Je suppose que vous construisez un échantillon en utilisant maven.
Veuillez vérifier le contenu du fichier JAR que vous essayez d'exécuter. Surtout le répertoire META-INFO/services
, le fichier org.Apache.hadoop.fs.FileSystem
. Il devrait y avoir une liste des classes d'implémentation de filsystem. La ligne de contrôle org.Apache.hadoop.hdfs.DistributedFileSystem
est présente dans la liste pour HDFS et org.Apache.hadoop.fs.LocalFileSystem
pour le schéma de fichiers local.
Si tel est le cas, vous devez remplacer la ressource référencée lors de la construction.
Une autre possibilité est que vous n'avez simplement pas hadoop-hdfs.jar
dans votre chemin d'accès aux classes, mais cette probabilité est faible. Généralement, si vous avez la dépendance correcte avec hadoop-client
, ce n'est pas une option.
Il m'a fallu un jour pour trouver une solution à partir de réponses données, en raison de ma nouvelle jeunesse. C’est ce que j’ai trouvé, si quelqu'un a besoin d'aide dès le début:
import org.Apache.spark.SparkContext
import org.Apache.spark.SparkConf
object MyObject {
def main(args: Array[String]): Unit = {
val mySparkConf = new SparkConf().setAppName("SparkApp").setMaster("local[*]").set("spark.executor.memory","5g");
val sc = new SparkContext(mySparkConf)
val conf = sc.hadoopConfiguration
conf.set("fs.hdfs.impl", classOf[org.Apache.hadoop.hdfs.DistributedFileSystem].getName)
conf.set("fs.file.impl", classOf[org.Apache.hadoop.fs.LocalFileSystem].getName)
J'utilise Spark 2.1
Et j'ai cette partie dans mon build.sbt
assemblyMergeStrategy in Assembly := {
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x => MergeStrategy.first
}
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://nameNode:9000");
FileSystem fs = FileSystem.get(conf);
set fs.defaultFS fonctionne pour moi! Hadoop-2.8.1
Si vous utilisez sbt :
//hadoop
lazy val HADOOP_VERSION = "2.8.0"
lazy val dependenceList = Seq(
//hadoop
//The order is important: "hadoop-hdfs" and then "hadoop-common"
"org.Apache.hadoop" % "hadoop-hdfs" % HADOOP_VERSION
,"org.Apache.hadoop" % "hadoop-common" % HADOOP_VERSION
)
Pour SBT, utilisez ci-dessous mergeStrategy dans build.sbt
mergeStrategy in Assembly <<= (mergeStrategy in Assembly) { (old) => {
case PathList("META-INF", "services", "org.Apache.hadoop.fs.FileSystem") => MergeStrategy.filterDistinctLines
case s => old(s)
}
}