Hadoop MapReduce查询大型json数据

时间:2016-03-14 14:10:11

标签: java json hadoop

Hadoop n00b在这里。

我已经在服务器上安装了Hadoop 2.6.0,我已经存储了12个我想要执行MapReduce操作的json文件。这些文件很大,每个文件大小为2-5千兆字节。

JSON文件的结构是一个JSON对象数组。下面两个对象的片段:

[{"campus":"Gløshaugen","building":"Varmeteknisk og Kjelhuset","floor":"4. etasje","timestamp":1412121618,"dayOfWeek":3,"hourOfDay":2,"latitude":63.419161638078066,"salt_timestamp":1412121602,"longitude":10.404867443910122,"id":"961","accuracy":56.083199914753536},{"campus":"Gløshaugen","building":"IT-Vest","floor":"2. etasje","timestamp":1412121612,"dayOfWeek":3,"hourOfDay":2,"latitude":63.41709424828986,"salt_timestamp":1412121602,"longitude":10.402167488838765,"id":"982","accuracy":7.315199988880896}]

我想根据字段构建时间戳执行MapReduce操作。至少在开始之前,我才能掌握这一点。例如。 mapReduce数据,其中building等于参数,timestamp大于X且小于Y. reduce过程后我需要的相关字段是纬度和经度。

我知道你可以使用不同的工具(Hive,HBase,PIG,Spark等)来解决这个问题,但是我的老板想要评估独立Hadoop的MapReduce性能。

到目前为止,我已经创建了触发map和reduce类的主类,实现了我认为是map类中的一个开头,但是我坚持使用reduce类。以下是我到目前为止的情况。

public class Hadoop {

    public static void main(String[] args) throws Exception {

        try {
            Configuration conf = new Configuration();
            Job job = new Job(conf, "maze");
            job.setJarByClass(Hadoop.class);
            job.setMapperClass(Map.class);
            job.setReducerClass(Reducer.class);
            job.setOutputKeyClass(Text.class);
            job.setOutputValueClass(Text.class);

            job.setMapOutputKeyClass(Text.class);
            job.setMapOutputValueClass(Text.class);

            job.setInputFormatClass(KeyValueTextInputFormat.class);
            job.setOutputFormatClass(TextOutputFormat.class);
            Path inPath = new Path("hdfs://xxx.xxx.106.23:50070/data.json");

            FileInputFormat.addInputPath(job, inPath);

            boolean result = job.waitForCompletion(true);
            System.exit(result ? 0 : 1);
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

映射器:

public class Map extends org.apache.hadoop.mapreduce.Mapper{
    private Text word = new Text();

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

        try {
            JSONObject jo = new JSONObject(value.toString());
            String latitude = jo.getString("latitude");
            String longitude = jo.getString("longitude");
            long timestamp = jo.getLong("timestamp");
            String building = jo.getString("building");
            StringBuilder sb = new StringBuilder();

            sb.append(latitude);
            sb.append("/");
            sb.append(longitude);
            sb.append("/");
            sb.append(timestamp);
            sb.append("/");
            sb.append(building);
            sb.append("/");
            context.write(new Text(sb.toString()),value);

        }catch (JSONException e){
            e.printStackTrace();
        }
    }
}

减速机:

public class Reducer extends org.apache.hadoop.mapreduce.Reducer{
    private Text result = new Text();

    protected void reduce(Text key, Iterable<Text> values, org.apache.hadoop.mapreduce.Reducer.Context context) throws IOException, InterruptedException {


    }
}

更新

public void map(Text key, Text value, Context context) throws IOException, InterruptedException {
    private static String BUILDING;
    private static int tsFrom;
    private static int tsTo;
    try {
        JSONArray ja = new JSONArray(key.toString());
        StringBuilder sb;
        for(int n = 0; n < ja.length(); n++)
        {
            JSONObject jo = ja.getJSONObject(n);
            String latitude = jo.getString("latitude");
            String longitude = jo.getString("longitude");
            int timestamp = jo.getInt("timestamp");
            String building = jo.getString("building");



            if (BUILDING.equals(building) && timestamp < tsTo && timestamp > tsFrom) {
                sb = new StringBuilder();
                sb.append(latitude);
                sb.append("/");
                sb.append(longitude);
                context.write(new Text(sb.toString()), value);
            }
        }
    }catch (JSONException e){
        e.printStackTrace();
    }
}

@Override
public void configure(JobConf jobConf) {
    System.out.println("configure");
    BUILDING = jobConf.get("BUILDING");
    tsFrom = Integer.parseInt(jobConf.get("TSFROM"));
    tsTo = Integer.parseInt(jobConf.get("TSTO"));
}

这适用于小型数据集。由于我正在使用LARGE json文件,因此我获得了Java堆空间异常。由于我不熟悉Hadoop,因此我无法理解MapR如何在不获取outOfMemoryError的情况下读取数据。

1 个答案:

答案 0 :(得分:2)

如果您只想在building = something和timestamp = somethingelse的约束下获得LONG / LAT列表。

这是一个简单的过滤操作;为此你不需要减速器。在映射器中,您应检查当前JSON是否满足条件,然后将其写入上下文。如果它不能满足条件,你不希望它在输出中。

输出应该是LONG / LAT(没有建筑物/时间戳,除非你也想要它们)

如果没有减速器,则映射器的输出是作业的输出,在您的情况下就足够了。

至于代码:

您的驱动程序应使用作业配置将建筑物ID和时间戳范围传递给映射器。你放在那里的任何东西都可供你的所有地图制作者使用。

Configuration conf = new Configuration();
conf.set("Building", "123");
conf.set("TSFROM", "12300000000");
conf.set("TSTO", "12400000000");
Job job = new Job(conf);

你的mapper类需要实现JobConfigurable.configure;在那里,您将从配置对象读入本地静态变量

private static String BUILDING;
private static Long tsFrom;
private static Long tsTo;
public void configure(JobConf job) {
    BUILDING = job.get("Building");
    tsFrom = Long.parseLong(job.get("TSFROM"));
    tsTo = Long.parseLong(job.get("TSTO"));
}

现在,您的地图功能需要检查:

if (BUILDING.equals(building) && timestamp < TSTO && timestamp > TSFROM) {
   sb = new StringBuilder();
   sb.append(latitude);
   sb.append("/");
   sb.append(longitude);
   context.write(new Text(sb.toString()),1);
}

这意味着属于其他建筑物或时间戳之外的任何行都不会出现在结果中。