【问题标题】:Processing JSON using java Mapreduce使用 java Mapreduce 处理 JSON
【发布时间】:2015-07-09 17:28:47
【问题描述】:

我是 hadoop mapreduce 的新手

我输入了文本文件,其中数据存储如下。这里只有几个元组(data.txt)

{"author":"Sharīf Qāsim","book":"al- Rabīʻ al-manshūd"}
{"author":"Nāṣir Nimrī","book":"Adīb ʻAbbāsī"}
{"author":"Muẓaffar ʻAbd al-Majīd Kammūnah","book":"Asmāʼ Allāh al-ḥusná al-wāridah fī muḥkam kitābih"}
{"author":"Ḥasan Muṣṭafá Aḥmad","book":"al- Jabhah al-sharqīyah wa-maʻārikuhā fī ḥarb Ramaḍān"}
{"author":"Rafīqah Salīm Ḥammūd","book":"Taʻlīm fī al-Baḥrayn"}

这是我应该在 (CombineBooks.java) 中编写代码的 java 文件

package org.hwone;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.util.GenericOptionsParser;

//TODO import necessary components

/*
*  Modify this file to combine books from the same other into
*  single JSON object. 
*  i.e. {"author": "Tobias Wells", "books": [{"book":"A die in the country"},{"book": "Dinky died"}]}
*  Beaware that, this may work on anynumber of nodes! 
*
*/

public class CombineBooks {

  //TODO define variables and implement necessary components

  public static void main(String[] args) throws Exception {
    Configuration conf = new Configuration();
    String[] otherArgs = new GenericOptionsParser(conf, args)
                .getRemainingArgs();
    if (otherArgs.length != 2) {
      System.err.println("Usage: CombineBooks <in> <out>");
      System.exit(2);
    }

    //TODO implement CombineBooks

    Job job = new Job(conf, "CombineBooks");

    //TODO implement CombineBooks

    System.exit(job.waitForCompletion(true) ? 0 : 1);
  }
}

我的任务是在“CombineBooks.java”中创建一个 Hadoop 程序 在“question-2”目录中返回。程序应该做 以下内容:给定输入的作者书元组,map-reduce 程序应该产生一个 JSON 对象,其中包含所有 JSON数组中来自同一作者的书籍,即

{"author": "Tobias Wells", "books":[{"book":"A die in the country"},{"book": "Dinky died"}]} 

知道怎么做吗?

【问题讨论】:

  • 使用 Apache Drill 和 SQL 怎么样?

标签: json hadoop mapreduce


【解决方案1】:

首先,您尝试使用的 JSON 对象不可用。要解决这个问题:

  1. 到这里并以 zip 格式下载:https://github.com/douglascrockford/JSON-java
  2. 解压到子目录 org/json/* 中的源文件夹

接下来,您的代码的第一行创建了一个包“org.json”,这是不正确的,您应该创建一个单独的包,例如“my.books”。

第三,这里用combiner是没用的。

这是我最终得到的代码,它可以工作并解决您的问题:

package my.books;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.json.*;

import javax.security.auth.callback.TextInputCallback;

public class CombineBooks {

    public static class Map extends Mapper<LongWritable, Text, Text, Text>{

        public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{

            String author;
            String book;
            String line = value.toString();
            String[] tuple = line.split("\\n");
            try{
                for(int i=0;i<tuple.length; i++){
                    JSONObject obj = new JSONObject(tuple[i]);
                    author = obj.getString("author");
                    book = obj.getString("book");
                    context.write(new Text(author), new Text(book));
                }
            }catch(JSONException e){
                e.printStackTrace();
            }
        }
    }

    public static class Reduce extends Reducer<Text,Text,NullWritable,Text>{

        public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException{

            try{
                JSONObject obj = new JSONObject();
                JSONArray ja = new JSONArray();
                for(Text val : values){
                    JSONObject jo = new JSONObject().put("book", val.toString());
                    ja.put(jo);
                }
                obj.put("books", ja);
                obj.put("author", key.toString());
                context.write(NullWritable.get(), new Text(obj.toString()));
            }catch(JSONException e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        if (args.length != 2) {
            System.err.println("Usage: CombineBooks <in> <out>");
            System.exit(2);
        }

        Job job = new Job(conf, "CombineBooks");
        job.setJarByClass(CombineBooks.class);
        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);
        job.setOutputKeyClass(NullWritable.class);
        job.setOutputValueClass(Text.class);
        job.setInputFormatClass(TextInputFormat.class);
        job.setOutputFormatClass(TextOutputFormat.class);

        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}

这是我的项目的文件夹结构:

src
src/my
src/my/books
src/my/books/CombineBooks.java
src/org
src/org/json
src/org/json/zip
src/org/json/zip/BitReader.java
...
src/org/json/zip/None.java
src/org/json/JSONStringer.java
src/org/json/JSONML.java
...
src/org/json/JSONException.java

这是输入

[localhost:CombineBooks]$ hdfs dfs -cat /example.txt
{"author":"author1", "book":"book1"}
{"author":"author1", "book":"book2"}
{"author":"author1", "book":"book3"}
{"author":"author2", "book":"book4"}
{"author":"author2", "book":"book5"}
{"author":"author3", "book":"book6"}

要运行的命令:

hadoop jar ./bookparse.jar my.books.CombineBooks /example.txt /test_output

这是输出:

[pivhdsne:CombineBooks]$ hdfs dfs -cat /test_output/part-r-00000
{"books":[{"book":"book3"},{"book":"book2"},{"book":"book1"}],"author":"author1"}
{"books":[{"book":"book5"},{"book":"book4"}],"author":"author2"}
{"books":[{"book":"book6"}],"author":"author3"}

您可以使用三个选项之一将org.json.* 类放入您的集群:

  1. org.json.* 类打包到您的jar 文件中(可以使用GUI IDE 轻松完成)。这是我在回答中使用的选项
  2. 将每个集群节点上包含 org.json.* 类的 jar 文件放入 CLASSPATH 目录之一(参见 yarn.application.classpath)
  3. 将包含org.json.* 的jar 文件放入HDFS (hdfs dfs -put &lt;org.json jar&gt; &lt;hdfs path&gt;) 并使用job.addFileToClassPath 调用此jar 文件,以便在集群上执行您的作业的所有任务都可用。在我的回答中,您应该将job.addFileToClassPath(new Path("&lt;jar_file_on_hdfs_location&gt;")); 添加到main

【讨论】:

  • +1 如果没有job.addFileToClassPath 声明,这个解决方案是不完整的。请添加。
  • 视情况而定。您可以将 org.json 内容构建为单独的 jar 文件,然后手动将其放置在每个集群节点上的 CLASSPATH 目录中(这是首选解决方案,因为 JSON 解析是一项常见任务)。或者您可以将org.jsonmy.books 放在一个罐子中,那么您就不必使用job.addFileToClassPath。或者您可以将其构建为单独的 jar 文件并使用 job.addFileToClassPath 在执行时将其发送到集群节点。您必须根据任务的上下文选择一个选项,对于生产我更喜欢 1,对于开发和调试 - 2 或 3
  • 在答案中添加相同的行将使查找此帖子的任何人受益。如果没有这些知识,他们将进入另一个异常,如果以前没有遇到过的话。这就是我的意图。
  • 添加到解决方案中
  • @0x0FFF .. 真的很棒,你能告诉我如何在 Ubuntu 终端中生成 JAR 文件吗,请帮助我,,这是我发布的问题stackoverflow.com/questions/35030016/…
【解决方案2】:

请参阅可拆分的多行 JSON: https://github.com/alexholmes/json-mapreduce

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多