#string #hadoop #mapreduce
#строка #hadoop #mapreduce
Вопрос:
Я очень новичок в MapReduce и изучал реализацию метода setup. Новое строковое значение, заданное конфигурацией, печатается правильно, но когда я попытался его обработать, вступило в действие начальное значение строки. Я знаю, что строка неизменяема, но она должна предоставлять значение, на которое в данный момент указывает, другим методам.
public class EMapper extends Mapper<LongWritable, Text, Text, Text> {
String wordstring = "abcd"; //initialized wordstring with "abcd"
public void setup(Context context) {
Configuration config = new Configuration(context.getConfiguration());
wordstring = config.get("mapper.word"); // As string is immutable,
// wordstring should now point to
// value given by mapper.word
//Here mapper.word="ankit" by
//using -D in hadoop command
}
String def = wordstring;
String jkl = String.valueOf(wordstring); //tried to copy current value
//but
//string jkl prints the initial
/value.
public void map(LongWritable key, Text value, Context context)
throws InterruptedException, IOException {
context.write(new Text("wordstring=" wordstring " " "def="
def),
new Text("jkl=" jkl));
}
}
public class EDriver extends Configured implements Tool {
private static Logger logger = LoggerFactory.getLogger(EDriver.class);
public static void main(String[] args) throws Exception {
logger.info("Driver started");
int res = ToolRunner.run(new Configuration(), new EDriver(), args);
System.exit(res);
}
public int run(String[] args) throws Exception {
if (args.length != 2) {
System.err.printf("Usage: %s needsarguments",
getClass().getSimpleName());
return -1;
}
Configuration conf = getConf();
Job job = new Job(conf);
job.setJarByClass(EDriver.class);
job.setJobName("E Record Reader");
job.setMapperClass(EMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setReducerClass(EReducer.class);
job.setNumReduceTasks(0);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(NullWritable.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
job.setInputFormatClass(ExcelInputFormat.class);
return job.waitForCompletion(true) ? 0 : 1;
}
}
Я ожидал, что результат будет
wordstring=ankit def=ankit jkl=ankit
Фактический результат
wordstring=ankit def=abcd jkl=abcd
Ответ №1:
Это не имеет ничего общего с изменчивостью строк, а все, что связано с порядком выполнения кода.
Ваш setup
метод будет вызываться только после выполнения любых команд уровня класса. Порядок, в котором вы пишете код, ничего не меняет. Если бы вы переписали верхнюю часть своего кода в том порядке, в котором он фактически выполняется, у вас было бы:
public class EMapper extends Mapper<LongWritable, Text, Text, Text> {
String wordstring = "abcd";
String jkl = String.valueOf(wordstring);
public void setup(Context context) {
Configuration config = new Configuration(context.getConfiguration());
wordstring = config.get("mapper.word"); //By the time this is called, jkl has already been assigned to "abcd"
}
Так что неудивительно, что jkl
это все еще abcd
так. Вы должны установить jkl
в setup
методе, например:
public class EMapper extends Mapper<LongWritable, Text, Text, Text> {
String wordstring;
String jkl;
public void setup(Context context) {
Configuration config = new Configuration(context.getConfiguration());
wordstring = config.get("mapper.word");
jkl = wordstring;
//Here, jkl and wordstring are both different variables pointing to "ankit"
}
//Here, jkl and wordstring are null, as setup(Context context) has not yet run
public void map(LongWritable key, Text value, Context context)
throws InterruptedException, IOException {
//Here, jkl and wordstring are both different variables pointing to "ankit"
context.write(new Text("wordstring=" wordstring),
new Text("jkl=" jkl));
}
Конечно, вам это на самом деле не нужно jkl
, вы можете просто использовать напрямую wordstring
.
Комментарии:
1. Я где-то читал, проблема связана с различием в расположении объектов, т.Е. Пула констант строки и области кучи строк. . Я не могу использовать wordstring, заданную «mapper.word», потому что, я думаю, его объект находится в области кучи строк. Но применение метода intern() тоже не сработало
2. Вы действительно переоцениваете это. Это намного проще. Вы пробовали реализовать мой ответ?
3. Я реализовал это, но затем попытался применить некоторые строковые методы, такие как split, toCharArray и т. Д. На jkl (тот, который вы сказали написать внутри метода setup), И все они выдали исключение nullpointerexception
4. Вы делали их внутри методов
setup
ormap
? Где-нибудь еще, и вы увидите NPE. Могу ли я предложить вам поэкспериментировать с областью видимости переменных за пределами фреймворка MapReduce? Это даст вам представление об инициализации и определении области видимости переменных. Затем вы можете работать над своим заданием MapReduce.5. Неужели нет решения? Мне это нужно.
Ответ №2:
Проблема решена. На самом деле, я запускал Hadoop в распределенном режиме, где SETUP, MAPPER, REDUCER и CLEANUP выполняются на разных JVM. Таким образом, данные не могут быть переданы из SETUP в MAPPER напрямую. Первый объект wordstring был инициализирован в «abcd» в mapper. Я попытался изменить строку wordstring в SETUP (был создан другой объект wordstring), что на самом деле происходило в другой JVM. Итак, когда я попытался скопировать «wordstring» в jkl в
String jkl = String.valueOf(wordstring);
первое значение wordstring (созданное mapper и инициализированное как «abcd») копировалось в jkl.
Если я запущу Hadoop в автономном режиме, он будет использовать одну JVM, а значение, заданное wordstring с помощью SETUP, будет скопировано в jkl.
Таким образом, jkl получил копию wordstring, инициализированную «abcd», а не ту, которая задана SETUP.
Я использовал
Карта хэш-карты = новая хэш-карта ();
для передачи данных между SETUP в MAPPER, а затем jkl получил копию значения, заданного wordstring из SETUP.