Hadoop, java MapReduce: запуск из произвольного web/EE контейнера
В интернете есть довольно большое количество примеров о том, как запустить MapReduce из стенделон приложения на джаве.Но начинающему работать с индийским слоником может быть сложно понять, как запустить джобу из какого-нибудь java контейнера.Например, в этом туториале, любезно предоставленном ikrumping, содержится такой пример кода: Job job = new Job (config, «grep»); /* * Для запуска программы из jar-файла необходимо указать любой * класс из вашего приложения. */ job.setJarByClass (Grep.class); Такой код будет работать, если вы запускаете стенделон приложение:
Если же вы запускаете код из JBOSS AS, WebSphere AS, Glassfish AS и тд, то этот код работать не будет.Почему? Да потому, что контейнер распаковывает ваш JAR файл в разные свои кеши и запускает классы уже оттуда.
Кому интересно, почему метод setJarByClass не работает в случае контейнера — приглашаю под спойлер Для начала предлагаю взглянуть на имплементацию метода setJarByClass. public void setJarByClass (Class cls) { String jar = findContainingJar (cls); if (jar!= null) setJar (jar); }
private static String findContainingJar (Class my_class) { ClassLoader loader = my_class.getClassLoader (); String class_file = my_class.getName ().replaceAll (»\\.»,»/») + ».class»; try { Enumeration itr = loader.getResources (class_file); while (itr.hasMoreElements ()) { URL url = (URL)itr.nextElement (); if («jar».equals (url.getProtocol ())) { String toReturn = url.getPath (); if (toReturn.startsWith («file:»)) { toReturn = toReturn.substring («file:».length ()); }
toReturn = toReturn.replaceAll (»\\+»,»%2B»); toReturn = URLDecoder.decode (toReturn, «UTF-8»); return toReturn.replaceAll (»!.*$»,»); } } } catch (IOException e) { throw new RuntimeException (e); } return null; } Как видите, метод findContainingJar ожидает, что тип протокола у URL будет «jar».А в случае каждого каждого контейнера протокол будет свой.Как результат: метод setJarByClass работает в основном только для стенделон приложений.
Как же запустить мапредьюс джобу универсальным способом, не зависящим от конкретного контейнера приложений? Для этого нужно выполнить следующее: создать отдельный JAR, содержащий все классы, используемые из джобы зааплодить его в файловую систему HDFS худупа, где вы собираетесь запускать MapReduce добавить JAR архив в classpath запускаемой джобы В вышеприведенном примере нужно заменить:
job.setJarByClass (Grep.class); на DistributedCache.addFileToClassPath (»/user/UserName/test.jar», config); Где первый параметр метода addFileToClassPath содержит путь к JAR файлу внутри распределенной файловой системы HDFS.А второй — конфигурацию хадупа (org.apache.hadoop.conf.Configuration).
Раньше было еще 2 способа подсунуть свою джарку хадупу, но они уже устарели: blog.cloudera.com/blog/2011/01/how-to-include-third-party-libraries-in-your-map-reduce-job