首页 > 代码库 > 使用hadoop实现ip地理位置统计~ip归属地和运营商
使用hadoop实现ip地理位置统计~ip归属地和运营商
转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/40585565
更多相关hadoop内容访问:http://blog.csdn.net/xiaojimanman/article/category/2640707
对于博客 http://blog.csdn.net/xiaojimanman/article/details/40372189 中的计算结果 key-value (ip,出现次数),统计下各个地区运营商下的IP个数,通过这个计算结果,可以分析出用户的地理位置分布情况,为决策提供数据支持。
需求分析:
根据IP归属地,对IP进行分组求和,将结果输出到文件中。
数据格式:
此次的数据格式相对比较简单,就是博客 http://blog.csdn.net/xiaojimanman/article/details/40372189 的结果数据,一行数据格式为:
ip地址空格分隔符出现次数 例: 192.168.1.1 25
需求分析:
在实现mapreduce程序之前,需要考虑的一个问题就是IP地址和归属地之间的转换问题。我这里采用的是百度的阿拉丁接口,接口获取方法,在百度首页输入"IP",就会出现阿拉丁界面。如下图所示:
通过对该部分的网络请求分析,获取地址 http://opendata.baidu.com/api.php?query=122.49.34.58&co=&resource_id=6006&t=1414563340538&ie=utf8&oe=gbk&format=json&tn=baidu&_=1414563341538 可以获取IP的归属地,该接口返回的数据格式如下图所示:
可以通过HttpClient模拟浏览器访问该地址,分析返回结果,获取该IP地址对应的归属地。如果自己有IP库,这一步就会简单很多。
IP个归属地中间的对应关系解决了,就需要设计mapreduce的实现问题。
map的输入就是一行原始记录,首先需要对记录进行拆分,取得IP地址,在通过上面提到的接口,查询该IP的归属地;map的输出结果是key为IP归属地,value为出现次数,一行记录就是1 。输出结果如下图所示:
reduce就需要对同一个key下的记录求和即可,输出结果是key为IP归属地,value为出现次数,如下图所示:
这一篇博客在mapreduce方面和上两篇没有太大的区别,所以这里也不再详细的阐述了,这一篇主要的目的就是在mapreduce程序中使用第三方的接口。需求分析就到此为止,下面就看具体的代码实现。
代码实现:
ip归属地查询代码
/** * @Description: ip归属地查询 */ package com.lulei.crawl.ip; import java.io.IOException; import java.util.Date; import java.util.HashMap; import org.apache.commons.httpclient.HttpException; import com.lulei.crawl.CrawlBase; import com.lulei.util.DoRegex; /** * @author lulei * 这里继承了自己的封装类,在类CrawlBase中实现了网络数据的获取,并将网页源代码存储在pageSourceCode中 */ public class IPInfo extends CrawlBase{ private String ip; private String location; //第三方接口地址 private static String ipUrl = "http://opendata.baidu.com/api.php?query=%ip%&co=&resource_id=6006&t=%t1%&ie=utf8&oe=gbk&format=json&tn=baidu&_=%t2%"; private static long timeDifference = 1000L; private static HashMap<String, String> params; private static String locationRegex = "\"location\":\"(.*?)\""; //伪装浏览器 static { params = new HashMap<String, String>(); params.put("Referer", "http://www.baidu.com"); params.put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36"); } public IPInfo(String ip) throws HttpException, IOException { long t1 = new Date().getTime(); long t2 = t1 + timeDifference; this.ip = ip; //组装请求地址 String url = ipUrl.replaceAll("%ip%", ip) .replaceAll("%t1%", t1 + "") .replaceAll("%t2%", t2 + ""); //获取网页源代码,具体的实现,这里就不详细的介绍,自己可以写简单的HttpClient实现此功能 readPageByGet(url, "utf-8", params); //解析源代码,获取归属地 setLocation(); } /** * @author lulei * 解析源代码,获取归属地 */ private void setLocation() { this.location = DoRegex.getFirstString(getPageSourceCode(), locationRegex, 1); } public String getIp() { return ip; } public String getLocation() { return location; } /** * @param args * @throws IOException * @throws HttpException */ public static void main(String[] args) throws HttpException, IOException { // TODO Auto-generated method stub String ip = "122.49.34.58"; IPInfo ipinfo = new IPInfo(ip); System.out.println("ip:" +ip ); System.out.println("归属地:" + ipinfo.getLocation()); } }
对一行记录的分析类
/** *@Description: 一行记录分析 */ package com.mapreduce.log; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import com.lulei.crawl.ip.IPInfo; public class LogLine { private String ip; private String location; private boolean right = true; private IntWritable one = new IntWritable(1); public LogLine(String textLine) { //检验一行日志数据是否符合要求,如不符合,将其标识为不可用 if (textLine == null || "".equals(textLine)) { this.right = false; return; } String []strs = textLine.split(" "); if (strs.length < 2) { this.right = false; return; } //ip地址在第一个位置 this.ip = strs[0]; setLocation(); } private void setLocation() { try { IPInfo ipInfo = new IPInfo(this.ip); this.location = ipInfo.getLocation(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); //如果出现网络错误,将此IP的归属地设置成“未知” this.location = "未知"; } } /** * @return * @Author:lulei * @Description: map输出key */ public Text getMapKey() { return new Text(this.location); } /** * @return * @Author:lulei * @Description: map输出value */ public IntWritable getMapValue() { return this.one; } public boolean isRight() { return right; } }
mapreduce程序实现类
/** *@Description: IP归属地统计mapreduce实现 */ package com.mapreduce.log; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; 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.Tool; import org.apache.hadoop.util.ToolRunner; public class IPLocationMapReduce extends Configured implements Tool{ /** *@Description: IP归属地统计map *@Author:lulei *@Version:1.1.0 */ public static class Map extends Mapper<LongWritable, Text, Text, IntWritable> { @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { LogLine logLine = new LogLine(value.toString()); if (logLine.isRight()) { context.write(logLine.getMapKey(), logLine.getMapValue()); } } } /** *@Description: IP归属地统计reduce *@Author:lulei *@Version:1.1.0 */ public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable> { @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; //对values进行求和操作 for (IntWritable value : values) { sum += value.get(); } context.write(key, new IntWritable(sum)); } } @Override public int run(String[] arg0) throws Exception { Configuration conf = new Configuration(); @SuppressWarnings("deprecation") Job job = new Job(conf); job.setJobName("ipcount"); job.setInputFormatClass(TextInputFormat.class); //将输出设置为TextOutputFormat job.setOutputFormatClass(TextOutputFormat.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class); //Mapper Combiner Reducer job.setMapperClass(Map.class); job.setCombinerClass(Reduce.class); job.setReducerClass(Reduce.class); //输入 输出路径 FileInputFormat.addInputPath(job, new Path(arg0[0])); FileOutputFormat.setOutputPath(job, new Path(arg0[1])); job.waitForCompletion(true); return job.isSuccessful() ? 0 : 1; } public static void main(String[] args) { // TODO Auto-generated method stub //这里没有对输入的参数做验证 try { int res = ToolRunner.run(new Configuration(), new IPLocationMapReduce(), args); System.exit(res); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
上传运行:
打包、上传、运行这些步骤这里就不再详细介绍,具体可以参照博客 http://blog.csdn.net/xiaojimanman/article/details/40184581 最后一部分。
对于自己写的数据的输出结果如下图所示:
到此一个完整的mapreduce程序就完成了,关于hadoop的学习,自己还将继续~
使用hadoop实现ip地理位置统计~ip归属地和运营商