Java Hadoop MapReduce对大型json数据的查询

Java Hadoop MapReduce对大型json数据的查询,java,json,hadoop,Java,Json,Hadoop,这里是Hadoop n00b 我已经在一台服务器上安装了Hadoop 2.6.0,在那里我存储了12个json文件,我想在这些文件上执行MapReduce操作。这些文件很大,每个文件的大小从2到5 GB不等 JSON文件的结构是JSON对象的数组。下面两个对象的片段: [{"campus":"Gløshaugen","building":"Varmeteknisk og Kjelhuset","floor":"4. etasje","timestamp":1412121618,"dayOfWee

这里是Hadoop n00b

我已经在一台服务器上安装了Hadoop 2.6.0,在那里我存储了12个json文件,我想在这些文件上执行MapReduce操作。这些文件很大,每个文件的大小从2到5 GB不等

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}]
我想根据字段buildingtimestamp执行MapReduce操作。至少在一开始,直到我掌握了窍门。例如,mapReduce构建等于参数且时间戳大于X小于Y的数据。reduce过程后我需要的相关字段是纬度和经度

我知道有不同的工具(Hive、HBase、PIG、Spark等)可以与Hadoop一起使用,可以更轻松地解决这个问题,但我的老板希望对独立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 {


    }
}
公共类Reducer扩展org.apache.hadoop.mapreduce.Reducer{
私有文本结果=新文本();
受保护的void reduce(文本键、Iterable值、org.apache.hadoop.mapreduce.Reducer.Context上下文)引发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"));
}
public void映射(文本键、文本值、上下文)引发IOException、InterruptedException{
私人楼宇;
私有静态int-tsFrom;
私有静态int-tsTo;
试一试{
JSONArray ja=新的JSONArray(key.toString());
为某人做准备;
对于(int n=0;ntsFrom){
sb=新的StringBuilder();
某人(纬度);
某人加上(“/”);
某人(经度);
write(新文本(sb.toString()),值);
}
}
}捕获(JSONException e){
e、 printStackTrace();
}
}
@凌驾
公共void配置(JobConf JobConf){
System.out.println(“配置”);
BUILDING=jobConf.get(“BUILDING”);
tsFrom=Integer.parseInt(jobConf.get(“tsFrom”);
tsTo=Integer.parseInt(jobConf.get(“tsTo”);
}

这适用于小型数据集。因为我处理的是大型json文件,所以我得到了Java堆空间异常。因为我不熟悉Hadoop,所以我很难理解MapR如何读取数据而不脱离MemoryError。

如果您只是想在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);
映射器类需要实现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);
}
if(BUILDING.equals(BUILDING)&×tampTSFROM){
sb=新的StringBuilder();
某人(纬度);
某人加上(“/”);
某人(经度);
编写(新文本(sb.toString()),1);
}

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

hmm,这一点很好。我所需要的就是时间,我再试试。我应该使用像Jackson这样的流API,因为它的大小,还是Hadoop以某种方式为我做到了这一点;i、 e.最初并非完全可用的数据,并且是“逐行”或“一小串一小串”的数据。您的案例是大量数据,需要进行批处理,hadoop非常适合于此。您能否提供一些代码,说明应该如何构建Map类?请注意,在1台服务器上安装mapreduce时,您将永远看不到良好的性能。关键是让多台机器向外扩展而不是向上扩展。更新了我的答案以包括必要的代码更改