将 MaxMind 的 GeoLite2 导入 MySQL
Importing MaxMind's GeoLite2 to MySQL
MaxMind 的 GeoLite2 是一个很棒的数据库,如果您想将 IP 地址映射到国家。
,它会非常有用
为了有效地做到这一点,我想将它导入到 MySQL 数据库中,方案如下:
我记得很久以前为 CSV 数据库编写了一个导入脚本,但是今天您可以下载的 CSV 格式很难理解,至少对我来说是这样:
network,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
1.0.0.0/24,2077456,2077456,,0,0
1.0.1.0/24,1814991,1814991,,0,0
1.0.2.0/23,1814991,1814991,,0,0
1.0.4.0/22,2077456,2077456,,0,0
1.0.8.0/21,1814991,1814991,,0,0
1.0.16.0/20,1861060,1861060,,0,0
1.0.32.0/19,1814991,1814991,,0,0
1.0.64.0/18,1861060,1861060,,0,0
1.0.128.0/17,1605651,1605651,,0,0
我真的停留在基础知识上。 将数据库从 CSV 表示形式导入 MySQL 的最有效和最简单的方法是什么?
network,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
1.0.0.0/24,2077456,2077456,,0,0
1.0.1.0/24,1814991,1814991,,0,0
1.0.2.0/23,1814991,1814991,,0,0
1.0.4.0/22,2077456,2077456,,0,0
create table thing1
( network varchar(20) not null,
geoname_id varchar(20) not null,
registered_country_geoname_id varchar(20) not null,
represented_country_geoname_id varchar(20) not null,
is_anonymous_proxy varchar(20) not null,
is_satellite_provider varchar(20) not null
);
LOAD DATA INFILE 'c:\dev\ipaddr.txt'
INTO TABLE thing1
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(@v1,@v2,@v3,@v4,@v5,@v6)
set network=ifnull(@v1,''),
geoname_id=ifnull(@v2,''),
registered_country_geoname_id=ifnull(@v3,''),
represented_country_geoname_id=ifnull(@v4,''),
is_anonymous_proxy=ifnull(@v5,''),
is_satellite_provider=ifnull(@v6,'');
以上对我来说很好。
以下编辑开始
对于以下内容,尝试根据 stijn-de-witt 在评论中提出的观点改进此答案。
但是请注意,评论中引用的博客在进入整数的更新语句中存在错误。所以暂时直到我解决这个问题,我发现了一个 varchar 修改,如下所示。
Edit1(更多内容,请参阅下面的评论):
Alter the table to get a "from ip to ip range"
alter table thing1 add column from_ip varchar(20), add column to_ip varchar(20);
-- note that those two are nullable at the moment. You can always change that later
为刚刚添加的 varchar 更新 table
update thing1
set from_ip= INET_NTOA(INET_ATON( SUBSTRING_INDEX(network, '/', 1))
& 0xffffffff ^ ((0x1 << ( 32 - SUBSTRING_INDEX(network, '/', -1)) ) -1 )),
to_ip= INET_NTOA(INET_ATON( SUBSTRING_INDEX(network, '/', 1))
| ((0x100000000 >> SUBSTRING_INDEX(network, '/', -1) ) -1 ))
select * from thing1;
(以上更新声明,感谢 Bernd Buffen )
以上更新语句的结果:
mysql> select network,from_ip,to_ip from thing1;
+------------+---------+-----------+
| network | from_ip | to_ip |
+------------+---------+-----------+
| 1.0.1.0/24 | 1.0.1.0 | 1.0.1.255 |
| 1.0.2.0/23 | 1.0.2.0 | 1.0.3.255 |
| 1.0.4.0/22 | 1.0.4.0 | 1.0.7.255 |
+------------+---------+-----------+
从这里查看 MySQL 手册页 Miscellaneous Functions INET_ATON(expr)
。
Edit2(再次感谢stijn-de-witt):
alter table thing1 add column uint_from_ip int unsigned, add column uint_to_ip int unsigned;
UPDATE thing1 SET uint_from_ip = inet_aton(SUBSTRING(network, 1, LOCATE('/', network) - 1)),
uint_to_ip = (inet_aton(SUBSTRING(network, 1, LOCATE('/', network) - 1)) + (pow(2, (32-CONVERT(SUBSTRING(network, LOCATE('/', network) + 1), UNSIGNED INT)))-1));
结果:
select network,from_ip,to_ip,uint_from_ip,uint_to_ip from thing1;
+------------+---------+-----------+--------------+------------+
| network | from_ip | to_ip | uint_from_ip | uint_to_ip |
+------------+---------+-----------+--------------+------------+
| 1.0.1.0/24 | 1.0.1.0 | 1.0.1.255 | 16777472 | 16777727 |
| 1.0.2.0/23 | 1.0.2.0 | 1.0.3.255 | 16777728 | 16778239 |
| 1.0.4.0/22 | 1.0.4.0 | 1.0.7.255 | 16778240 | 16779263 |
+------------+---------+-----------+--------------+------------+
(在提到一些修复后,以上归功于此 S0BEIT blog)
我建议使用 MaxMind's GeoIP2 CSV Converter to put it in the format you want. There is an -include-integer-range
option that will provide from and to integer columns that I think you are looking for. Binaries are available for Windows, Linux (amd64), and OS X。
用一个简单的 SQL 脚本似乎真的不可能做到这一点,所以我用 C# 编写了一个。由于导入如此大的 MySQL 数据库并不是那么简单,我直接将 INSERT INTO
实现到脚本本身。
它需要一个 table 结构,就像问题中草图上的结构一样。
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace GeoIPConvert
{
public static class Program
{
public static void Main(string[] args)
{
// https://dev.maxmind.com/geoip/geoip2/geolite2/
List<Country> countries = File.ReadAllLines("Countries.csv")
.Select(line => line.Split(','))
.Where(line => line[4] != "" && line[5] != "")
.Select((line, index) => new Country
{
ID = Convert.ToInt32(line[0]),
DatabaseID = index + 1,
Flag = line[4].ToLower(),
Name = line[5].Replace("\"", "")
})
.ToList();
List<IPRange> ipRanges = File.ReadAllLines("GeoIP.csv")
.Select(line => line.Split(','))
.Where(line => line[2] != "")
.Select(line => new IPRange
{
Country = countries.First(country => country.ID == Convert.ToInt32(line[2])),
From = ConvertCidrToRange(line[0]).Item1,
To = ConvertCidrToRange(line[0]).Item2,
})
.ToList();
//string sql =
// "INSERT INTO geoip_countries(Flag, Name) VALUES\r\n" +
// string.Join(",\r\n", countries.Select(country => "(\"" + country.Flag + "\", \"" + country.Name + "\")").ToArray()) + "\r\n" +
// "INSERT INTO geoip_ipranges(CountryID, `From`, `To`) VALUES\r\n" +
// string.Join(",\r\n", ipRanges.Select(iprange => "(\"" + iprange.Country.DatabaseID + "\", \"" + iprange.From + "\", \"" + iprange.To + "\")").ToArray());
//File.WriteAllText("Import.sql", sql);
using (MySqlConnection sql = new MySqlConnection("Server=localhost;Database=test_db;Uid=root;"))
{
sql.Open();
foreach (Country country in countries)
{
new MySqlCommand("INSERT INTO geoip_countries(Flag, Name) VALUES(\"" + country.Flag + "\", \"" + country.Name + "\")", sql).ExecuteNonQuery();
}
foreach (IPRange ipRange in ipRanges)
{
new MySqlCommand("INSERT INTO geoip_ipranges(CountryID, `From`, `To`) VALUES(\"" + ipRange.Country.DatabaseID + "\", \"" + ipRange.From + "\", \"" + ipRange.To + "\")", sql).ExecuteNonQuery();
Console.WriteLine(ipRange.To);
}
sql.Close();
}
}
private static Tuple<uint, uint> ConvertCidrToRange(string cidr)
{
string[] parts = cidr.Split('.', '/');
uint ipnum = Convert.ToUInt32(parts[0]) << 24 | Convert.ToUInt32(parts[1]) << 16 | Convert.ToUInt32(parts[2]) << 8 | Convert.ToUInt32(parts[3]);
uint mask = uint.MaxValue << (32 - Convert.ToInt32(parts[4]));
return Tuple.Create(ipnum & mask, ipnum | (mask ^ uint.MaxValue));
}
}
public class Country
{
public int ID { get; set; }
public int DatabaseID { get; set; }
public string Flag { get; set; }
public string Name { get; set; }
}
public class IPRange
{
public Country Country { get; set; }
public uint From { get; set; }
public uint To { get; set; }
}
}
您可以使用我的工具将 MaxMind GeoLite2 country/city CSV 从 GitHub https://github.com/mbto/maxmind-geoip2-csv2sql-converter
转换为 MySQL/PostgreSQL/Microsoft SQL Server 2019
您可以阅读 examples,或按照以下步骤操作:
- 在 https://support.maxmind.com/account-faq/license-keys/how-do-i-generate-a-license-key/
获取 MaxMind API 的免费许可证密钥(如果您没有)
- 在 adoptopenjdk.net or github.com/raphw/raphw.github.io or oracle.com/java
安装 Java 11(如果未安装)
- 从 releases 下载工具(.zip 或 .tar)
- 解压到你的目录
- Copy/Paste .ini 模板
bin/GeoLite2-Country-CSV.mysql.default.ini
使用您的个人资料名称,示例 bin/GeoLite2-Country-CSV.mysql.Your Project Name.ini
或使用默认值。
- 用记事本打开 .ini 模板并更改
[windows_loader]
或 [unix_loader]
部分(设置 MySQL host:port、用户和密码)。
- 对于 unix:执行
chmod +x maxmind-geoip2-csv2sql-converter
- 运行 转换:
maxmind-geoip2-csv2sql-converter.bat -c "GeoLite2-Country-CSV.mysql.Your Project Name.ini" -k Your_License_Key -i 4,6
- 转换后,脚本
bin/converted/loader.bat
和 bin/converted/loader.sh
将可用。
- 对于 unix:执行
chmod +x loader.sh
- 执行
loader.bat
或 loader.sh
以导入架构。
完成
MaxMind 的 GeoLite2 是一个很棒的数据库,如果您想将 IP 地址映射到国家。
,它会非常有用为了有效地做到这一点,我想将它导入到 MySQL 数据库中,方案如下:
我记得很久以前为 CSV 数据库编写了一个导入脚本,但是今天您可以下载的 CSV 格式很难理解,至少对我来说是这样:
network,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider 1.0.0.0/24,2077456,2077456,,0,0 1.0.1.0/24,1814991,1814991,,0,0 1.0.2.0/23,1814991,1814991,,0,0 1.0.4.0/22,2077456,2077456,,0,0 1.0.8.0/21,1814991,1814991,,0,0 1.0.16.0/20,1861060,1861060,,0,0 1.0.32.0/19,1814991,1814991,,0,0 1.0.64.0/18,1861060,1861060,,0,0 1.0.128.0/17,1605651,1605651,,0,0
我真的停留在基础知识上。 将数据库从 CSV 表示形式导入 MySQL 的最有效和最简单的方法是什么?
network,geoname_id,registered_country_geoname_id,represented_country_geoname_id,is_anonymous_proxy,is_satellite_provider
1.0.0.0/24,2077456,2077456,,0,0
1.0.1.0/24,1814991,1814991,,0,0
1.0.2.0/23,1814991,1814991,,0,0
1.0.4.0/22,2077456,2077456,,0,0
create table thing1
( network varchar(20) not null,
geoname_id varchar(20) not null,
registered_country_geoname_id varchar(20) not null,
represented_country_geoname_id varchar(20) not null,
is_anonymous_proxy varchar(20) not null,
is_satellite_provider varchar(20) not null
);
LOAD DATA INFILE 'c:\dev\ipaddr.txt'
INTO TABLE thing1
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(@v1,@v2,@v3,@v4,@v5,@v6)
set network=ifnull(@v1,''),
geoname_id=ifnull(@v2,''),
registered_country_geoname_id=ifnull(@v3,''),
represented_country_geoname_id=ifnull(@v4,''),
is_anonymous_proxy=ifnull(@v5,''),
is_satellite_provider=ifnull(@v6,'');
以上对我来说很好。
以下编辑开始
对于以下内容,尝试根据 stijn-de-witt 在评论中提出的观点改进此答案。
但是请注意,评论中引用的博客在进入整数的更新语句中存在错误。所以暂时直到我解决这个问题,我发现了一个 varchar 修改,如下所示。
Edit1(更多内容,请参阅下面的评论):
Alter the table to get a "from ip to ip range"
alter table thing1 add column from_ip varchar(20), add column to_ip varchar(20);
-- note that those two are nullable at the moment. You can always change that later
为刚刚添加的 varchar 更新 table
update thing1
set from_ip= INET_NTOA(INET_ATON( SUBSTRING_INDEX(network, '/', 1))
& 0xffffffff ^ ((0x1 << ( 32 - SUBSTRING_INDEX(network, '/', -1)) ) -1 )),
to_ip= INET_NTOA(INET_ATON( SUBSTRING_INDEX(network, '/', 1))
| ((0x100000000 >> SUBSTRING_INDEX(network, '/', -1) ) -1 ))
select * from thing1;
(以上更新声明,感谢 Bernd Buffen
以上更新语句的结果:
mysql> select network,from_ip,to_ip from thing1;
+------------+---------+-----------+
| network | from_ip | to_ip |
+------------+---------+-----------+
| 1.0.1.0/24 | 1.0.1.0 | 1.0.1.255 |
| 1.0.2.0/23 | 1.0.2.0 | 1.0.3.255 |
| 1.0.4.0/22 | 1.0.4.0 | 1.0.7.255 |
+------------+---------+-----------+
从这里查看 MySQL 手册页 Miscellaneous Functions INET_ATON(expr)
。
Edit2(再次感谢stijn-de-witt):
alter table thing1 add column uint_from_ip int unsigned, add column uint_to_ip int unsigned;
UPDATE thing1 SET uint_from_ip = inet_aton(SUBSTRING(network, 1, LOCATE('/', network) - 1)),
uint_to_ip = (inet_aton(SUBSTRING(network, 1, LOCATE('/', network) - 1)) + (pow(2, (32-CONVERT(SUBSTRING(network, LOCATE('/', network) + 1), UNSIGNED INT)))-1));
结果:
select network,from_ip,to_ip,uint_from_ip,uint_to_ip from thing1;
+------------+---------+-----------+--------------+------------+
| network | from_ip | to_ip | uint_from_ip | uint_to_ip |
+------------+---------+-----------+--------------+------------+
| 1.0.1.0/24 | 1.0.1.0 | 1.0.1.255 | 16777472 | 16777727 |
| 1.0.2.0/23 | 1.0.2.0 | 1.0.3.255 | 16777728 | 16778239 |
| 1.0.4.0/22 | 1.0.4.0 | 1.0.7.255 | 16778240 | 16779263 |
+------------+---------+-----------+--------------+------------+
(在提到一些修复后,以上归功于此 S0BEIT blog)
我建议使用 MaxMind's GeoIP2 CSV Converter to put it in the format you want. There is an -include-integer-range
option that will provide from and to integer columns that I think you are looking for. Binaries are available for Windows, Linux (amd64), and OS X。
用一个简单的 SQL 脚本似乎真的不可能做到这一点,所以我用 C# 编写了一个。由于导入如此大的 MySQL 数据库并不是那么简单,我直接将 INSERT INTO
实现到脚本本身。
它需要一个 table 结构,就像问题中草图上的结构一样。
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace GeoIPConvert
{
public static class Program
{
public static void Main(string[] args)
{
// https://dev.maxmind.com/geoip/geoip2/geolite2/
List<Country> countries = File.ReadAllLines("Countries.csv")
.Select(line => line.Split(','))
.Where(line => line[4] != "" && line[5] != "")
.Select((line, index) => new Country
{
ID = Convert.ToInt32(line[0]),
DatabaseID = index + 1,
Flag = line[4].ToLower(),
Name = line[5].Replace("\"", "")
})
.ToList();
List<IPRange> ipRanges = File.ReadAllLines("GeoIP.csv")
.Select(line => line.Split(','))
.Where(line => line[2] != "")
.Select(line => new IPRange
{
Country = countries.First(country => country.ID == Convert.ToInt32(line[2])),
From = ConvertCidrToRange(line[0]).Item1,
To = ConvertCidrToRange(line[0]).Item2,
})
.ToList();
//string sql =
// "INSERT INTO geoip_countries(Flag, Name) VALUES\r\n" +
// string.Join(",\r\n", countries.Select(country => "(\"" + country.Flag + "\", \"" + country.Name + "\")").ToArray()) + "\r\n" +
// "INSERT INTO geoip_ipranges(CountryID, `From`, `To`) VALUES\r\n" +
// string.Join(",\r\n", ipRanges.Select(iprange => "(\"" + iprange.Country.DatabaseID + "\", \"" + iprange.From + "\", \"" + iprange.To + "\")").ToArray());
//File.WriteAllText("Import.sql", sql);
using (MySqlConnection sql = new MySqlConnection("Server=localhost;Database=test_db;Uid=root;"))
{
sql.Open();
foreach (Country country in countries)
{
new MySqlCommand("INSERT INTO geoip_countries(Flag, Name) VALUES(\"" + country.Flag + "\", \"" + country.Name + "\")", sql).ExecuteNonQuery();
}
foreach (IPRange ipRange in ipRanges)
{
new MySqlCommand("INSERT INTO geoip_ipranges(CountryID, `From`, `To`) VALUES(\"" + ipRange.Country.DatabaseID + "\", \"" + ipRange.From + "\", \"" + ipRange.To + "\")", sql).ExecuteNonQuery();
Console.WriteLine(ipRange.To);
}
sql.Close();
}
}
private static Tuple<uint, uint> ConvertCidrToRange(string cidr)
{
string[] parts = cidr.Split('.', '/');
uint ipnum = Convert.ToUInt32(parts[0]) << 24 | Convert.ToUInt32(parts[1]) << 16 | Convert.ToUInt32(parts[2]) << 8 | Convert.ToUInt32(parts[3]);
uint mask = uint.MaxValue << (32 - Convert.ToInt32(parts[4]));
return Tuple.Create(ipnum & mask, ipnum | (mask ^ uint.MaxValue));
}
}
public class Country
{
public int ID { get; set; }
public int DatabaseID { get; set; }
public string Flag { get; set; }
public string Name { get; set; }
}
public class IPRange
{
public Country Country { get; set; }
public uint From { get; set; }
public uint To { get; set; }
}
}
您可以使用我的工具将 MaxMind GeoLite2 country/city CSV 从 GitHub https://github.com/mbto/maxmind-geoip2-csv2sql-converter
转换为 MySQL/PostgreSQL/Microsoft SQL Server 2019您可以阅读 examples,或按照以下步骤操作:
- 在 https://support.maxmind.com/account-faq/license-keys/how-do-i-generate-a-license-key/ 获取 MaxMind API 的免费许可证密钥(如果您没有)
- 在 adoptopenjdk.net or github.com/raphw/raphw.github.io or oracle.com/java 安装 Java 11(如果未安装)
- 从 releases 下载工具(.zip 或 .tar)
- 解压到你的目录
- Copy/Paste .ini 模板
bin/GeoLite2-Country-CSV.mysql.default.ini
使用您的个人资料名称,示例bin/GeoLite2-Country-CSV.mysql.Your Project Name.ini
或使用默认值。 - 用记事本打开 .ini 模板并更改
[windows_loader]
或[unix_loader]
部分(设置 MySQL host:port、用户和密码)。 - 对于 unix:执行
chmod +x maxmind-geoip2-csv2sql-converter
- 运行 转换:
maxmind-geoip2-csv2sql-converter.bat -c "GeoLite2-Country-CSV.mysql.Your Project Name.ini" -k Your_License_Key -i 4,6
- 转换后,脚本
bin/converted/loader.bat
和bin/converted/loader.sh
将可用。 - 对于 unix:执行
chmod +x loader.sh
- 执行
loader.bat
或loader.sh
以导入架构。
完成