私のMapReduceジョブは、Eclipseプロジェクトに依存関係として含まれている可能性のあるすべてのHadoopおよびHive jarを使用してEclipseでアセンブルすると、正常に実行されます。 (これらは、単一ノードのローカルHadoopインストールに付属するjarです)。
しかし、Mavenプロジェクト(以下を参照)を使用してアセンブルされた同じプログラムを実行しようとすると、次のようになります。
Exception in thread "main" Java.lang.IncompatibleClassChangeError: Found interface org.Apache.hadoop.mapreduce.JobContext, but class was expected
この例外は、プログラムが次のMavenプロジェクトを使用してアセンブルされた場合に発生します。
<project xmlns="http://maven.Apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bigdata.hadoop</groupId>
<artifactId>FieldCounts</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>FieldCounts</name>
<url>http://maven.Apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.Apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.Apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.Apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-jobclient</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.Apache.Hive.hcatalog</groupId>
<artifactId>hcatalog-core</artifactId>
<version>0.12.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-Assembly-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>attached</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.bigdata.hadoop.FieldCounts</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
*互換性のあるHadoopjarを見つける場所と方法を教えてください。 *
[update_1]Hadoop2.2.0.2.0.6.0-101を実行しています
私がここで見つけたように: https://github.com/kevinweil/elephant-bird/issues/247
Hadoop 1.0.3:JobContextはクラスです
Hadoop 2.0.0:JobContextはインターフェースです
私のpom.xmlには、バージョン2.2.0のjarが3つあります。
hadoop-hdfs 2.2.0
hadoop-common 2.2.0
hadoop-mapreduce-client-jobclient 2.2.0
hcatalog-core 0.12.0
唯一の例外はhcatalog-core
で、バージョンは0.12.0です。このjarの最新バージョンが見つかりませんでした。必要です。
これらの4つのjarファイルのどれがJava.lang.IncompatibleClassChangeError: Found interface org.Apache.hadoop.mapreduce.JobContext, but class was expected
を生成するかをどのように見つけることができますか?
これを解決する方法を教えてください。 (私が見る唯一の解決策は、ソースからすべてをコンパイルすることです!)
[/ update_1]
私のMarReduceジョブの全文:
package com.bigdata.hadoop;
import Java.io.IOException;
import Java.util.*;
import org.Apache.hadoop.conf.*;
import org.Apache.hadoop.io.*;
import org.Apache.hadoop.mapreduce.*;
import org.Apache.hadoop.util.*;
import org.Apache.hcatalog.mapreduce.*;
import org.Apache.hcatalog.data.*;
import org.Apache.hcatalog.data.schema.*;
import org.Apache.log4j.Logger;
public class FieldCounts extends Configured implements Tool {
public static class Map extends Mapper<WritableComparable, HCatRecord, TableFieldValueKey, IntWritable> {
static Logger logger = Logger.getLogger("com.foo.Bar");
static boolean firstMapRun = true;
static List<String> fieldNameList = new LinkedList<String>();
/**
* Return a list of field names not containing `id` field name
* @param schema
* @return
*/
static List<String> getFieldNames(HCatSchema schema) {
// Filter out `id` name just once
if (firstMapRun) {
firstMapRun = false;
List<String> fieldNames = schema.getFieldNames();
for (String fieldName : fieldNames) {
if (!fieldName.equals("id")) {
fieldNameList.add(fieldName);
}
}
} // if (firstMapRun)
return fieldNameList;
}
@Override
protected void map( WritableComparable key,
HCatRecord hcatRecord,
//org.Apache.hadoop.mapreduce.Mapper
//<WritableComparable, HCatRecord, Text, IntWritable>.Context context)
Context context)
throws IOException, InterruptedException {
HCatSchema schema = HCatBaseInputFormat.getTableSchema(context.getConfiguration());
//String schemaTypeStr = schema.getSchemaAsTypeString();
//logger.info("******** schemaTypeStr ********** : "+schemaTypeStr);
//List<String> fieldNames = schema.getFieldNames();
List<String> fieldNames = getFieldNames(schema);
for (String fieldName : fieldNames) {
Object value = hcatRecord.get(fieldName, schema);
String fieldValue = null;
if (null == value) {
fieldValue = "<NULL>";
} else {
fieldValue = value.toString();
}
//String fieldNameValue = fieldName+"."+fieldValue;
//context.write(new Text(fieldNameValue), new IntWritable(1));
TableFieldValueKey fieldKey = new TableFieldValueKey();
fieldKey.fieldName = fieldName;
fieldKey.fieldValue = fieldValue;
context.write(fieldKey, new IntWritable(1));
}
}
}
public static class Reduce extends Reducer<TableFieldValueKey, IntWritable,
WritableComparable, HCatRecord> {
protected void reduce( TableFieldValueKey key,
Java.lang.Iterable<IntWritable> values,
Context context)
//org.Apache.hadoop.mapreduce.Reducer<Text, IntWritable,
//WritableComparable, HCatRecord>.Context context)
throws IOException, InterruptedException {
Iterator<IntWritable> iter = values.iterator();
int sum = 0;
// Sum up occurrences of the given key
while (iter.hasNext()) {
IntWritable iw = iter.next();
sum = sum + iw.get();
}
HCatRecord record = new DefaultHCatRecord(3);
record.set(0, key.fieldName);
record.set(1, key.fieldValue);
record.set(2, sum);
context.write(null, record);
}
}
public int run(String[] args) throws Exception {
Configuration conf = getConf();
args = new GenericOptionsParser(conf, args).getRemainingArgs();
// To fix Hadoop "META-INFO" (http://stackoverflow.com/questions/17265002/hadoop-no-filesystem-for-scheme-file)
conf.set("fs.hdfs.impl",
org.Apache.hadoop.hdfs.DistributedFileSystem.class.getName());
conf.set("fs.file.impl",
org.Apache.hadoop.fs.LocalFileSystem.class.getName());
// Get the input and output table names as arguments
String inputTableName = args[0];
String outputTableName = args[1];
// Assume the default database
String dbName = null;
Job job = new Job(conf, "FieldCounts");
HCatInputFormat.setInput(job,
InputJobInfo.create(dbName, inputTableName, null));
job.setJarByClass(FieldCounts.class);
job.setMapperClass(Map.class);
job.setReducerClass(Reduce.class);
// An HCatalog record as input
job.setInputFormatClass(HCatInputFormat.class);
// Mapper emits TableFieldValueKey as key and an integer as value
job.setMapOutputKeyClass(TableFieldValueKey.class);
job.setMapOutputValueClass(IntWritable.class);
// Ignore the key for the reducer output; emitting an HCatalog record as
// value
job.setOutputKeyClass(WritableComparable.class);
job.setOutputValueClass(DefaultHCatRecord.class);
job.setOutputFormatClass(HCatOutputFormat.class);
HCatOutputFormat.setOutput(job,
OutputJobInfo.create(dbName, outputTableName, null));
HCatSchema s = HCatOutputFormat.getTableSchema(job);
System.err.println("INFO: output schema explicitly set for writing:"
+ s);
HCatOutputFormat.setSchema(job, s);
return (job.waitForCompletion(true) ? 0 : 1);
}
public static void main(String[] args) throws Exception {
String classpath = System.getProperty("Java.class.path");
//System.out.println("*** CLASSPATH: "+classpath);
int exitCode = ToolRunner.run(new FieldCounts(), args);
System.exit(exitCode);
}
}
そして、複雑なキーのクラス:
package com.bigdata.hadoop;
import Java.io.DataInput;
import Java.io.DataOutput;
import Java.io.IOException;
import org.Apache.hadoop.io.WritableComparable;
import com.google.common.collect.ComparisonChain;
public class TableFieldValueKey implements WritableComparable<TableFieldValueKey> {
public String fieldName;
public String fieldValue;
public TableFieldValueKey() {} //must have a default constructor
//
public void readFields(DataInput in) throws IOException {
fieldName = in.readUTF();
fieldValue = in.readUTF();
}
public void write(DataOutput out) throws IOException {
out.writeUTF(fieldName);
out.writeUTF(fieldValue);
}
public int compareTo(TableFieldValueKey o) {
return ComparisonChain.start().compare(fieldName, o.fieldName)
.compare(fieldValue, o.fieldValue).result();
}
}
Hadoopは、Hadoop 1.0
からHadoop 2.0
への巨大なコードリファクタリングを経てきました。副作用の1つは、Hadoop1.0に対してコンパイルされたコードがHadoop2.0と互換性がないことです。その逆も同様です。ただし、ソースコードはほとんど互換性があるため、ターゲットのHadoopディストリビューションを使用してコードを再コンパイルする必要があります。
例外「Found interface X, but class was expected
」は、Hadoop2.0でHadoop1.0用にコンパイルされたコードを実行している場合、またはその逆の場合に非常に一般的です。
クラスターで使用されている正しいHadoopバージョンを見つけて、pom.xmlファイルでそのHadoopバージョンを指定します。クラスターで使用されているのと同じバージョンのHadoopを使用してプロジェクトをビルドし、デプロイします。
Hadoop 2.0.0をサポートするには、「hcatalog-core」を再コンパイルする必要があります。現在、「hcatalog-core」はHadoop1.0のみをサポートしています
明らかに、HadoopバージョンとHiveバージョンの間にバージョンの非互換性があります。 HadoopバージョンまたはHiveバージョンをアップグレード(またはダウングレード)する必要があります。
これは、Hadoop1とHadoop2の非互換性によるものです。
私でさえこの問題に遭遇しました。 Hive-hcatalog-core-0.13.0.jarでHCatMultipleInputsを使用しようとしていました。 Hadoop2.5.1を使用しています。
次のコード変更は、問題の修正に役立ちました。
// JobContext ctx = new JobContext(conf、jobContext.getJobID()); JobContext ctx = new Job(conf);
このようなエントリを探します
<dependency>
<groupId>org.Apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
<version>1.2.1</version>
</dependency>
pom.xmlで。これらは、使用するHadoopバージョンを定義します。要件に応じて、それらを変更または削除します。