IP地址分布分析(国内)·叄

IP地址分布分析(国内)·叄

五月 13, 2020 阅读量

IP地址分布分析(国内)·叄

最近碰上IP地址数据量百万级的,原来的两套方案根本不能用,于是乎就有了叄。工作可用→工作用

ip所在地来源

因为数据量比较大,还是本地化比较好。最后选用了国内大神写的ip2region,准确率99.9%的离线IP地址定位库,0.0x毫秒级查询,数据库文件大小只有1.5M,提供了java,php,c,python,nodejs,golang,c#等查询绑定和Binary,B树,内存三种查询算法。数据库最后更新时间为6个月前,感觉问题不大,存在部分IP和现在有偏差。
数据格式为_城市Id|国家|区域|省份|城市|ISP_,只有中国的数据精确到了城市,其他国家有部分数据只能定位到国家,后面的选项全部是0。查不到数据时,也会为0。

过程

因为数据量巨大,已经超过Excel的处理范围(最大行1048576)。提供过来的数据,分成了5块,接近500W的原始数据。Excel对大数据(主要是行数,之前几个G的数据没发现问题,只是字段多,数据量96W)的处理显得很无力,比如筛选出来的结果不对(前面空白数据的锅吗?)。

这时候只能用数据库来筛选数据,发现默认配置下SqlServer比MySql快多了。
首先先用Excle的去重功能去掉重复数据,然后分别导入到一张数据库表里,再通过数据库去重插入新表,最后筛选出200W的不重复IP。

然后执行ip2region,根据导出的IP获取region信息,导出到文本文件。200W数据在内存查询算法下耗时8秒。

最后把生成的结果再导回数据库,分组查询。

省为0的,可以用高德地图的ip定位API来进行二次判定。

代码

下载ip2region的代码拷到自己的工程,我用的是Java,把binding/java下的代码拷到了自己之前写的工程(新建工程就行)。还需要拷贝数据库文件data/ip2region.db。我的代码结构如下

新建Java入口文件,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.lionsoul.ip2region.test.TestUtil;

public class IpDistributionCreaterByip2region {

public static void main(String args[]) {
// String[] ips = { "116.116.91.150", // 正常内蒙古
// "127.0.0.1", // 本地
// "172.58.22.176", // 美国
// "223.104.212.147", // geoip上海
// "223.104.148.122", // geoip江苏
// "47.75.7.133" }; // 正常香港
// ipDistributionCreater(ips);

// 数据量大时从文件读取
List<String> ipList = new ArrayList<String>();
try {
BufferedReader br = new BufferedReader(new FileReader("D:\\useripdis.txt"));
String lineStr = "";
while ((lineStr = br.readLine()) != null) {
ipList.add(lineStr);
}
br.close();
//System.out.println("读取" + ipList.size() + "条IP");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String[] ips = {};
ipDistributionCreater(ipList.toArray(ips));

}

public static void ipDistributionCreater(String ips[]) {
try {
long startTime = System.currentTimeMillis();
DbConfig config = new DbConfig();
DbSearcher searcher = new DbSearcher(config, TestUtil.class.getResource("../data/ip2region.db").getPath()); // 貌似需要完整路径

// btreeSearch binarySearch memorySearch
Method method = searcher.getClass().getMethod("memorySearch", String.class); //内存查询算法

FileOutputStream fos = new FileOutputStream(new File("D:\\ipResult.txt"));

DataBlock dataBlock = null;
for (int i = 0; i < ips.length; i++) {
if (Util.isIpAddress(ips[i])) {
dataBlock = (DataBlock) method.invoke(searcher, ips[i]);
String[] regionAry = dataBlock.getRegion().split("\\|");
String result = ips[i] + "\t" + regionAry[0] + "\t" + regionAry[2] + "\t" + regionAry[3] + "\r\n";
//System.out.print(i + ":" + result);
fos.write(result.getBytes());
}
}

fos.close();
System.out.println("Finish");
long endTime = System.currentTimeMillis();
System.out.println((endTime-startTime)/1000 + "s");

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

IP地址分布分析(国内)
IP地址分布分析(国内)·续