[英]How to store ipv4 and ipv6 addresses in postgresql using GORM
[英]Finding Geo Locations for ipv4 and ipv6 using BigQuery and MaxMind GeoIP
我正在尝试使用用户的 IP 将用户与其地理位置相匹配。
IPs 是 ipv4、ipv6 和一些带有无效条目的行的混合。
我正在使用 GeoLite2-City-Blocks-IPv4(知道我将不得不为 ipv6 使用不同的文件,如果有人知道哪个是正确的,非常感谢)和 GeoLite2-City-Locations-en。 所以基本上,一个文件有 IP 块和它们的位置代码,另一个文件有这些代码的实际位置。
我使用 Felipe Hoffa https://towardsdatascience.com/geolocation-with-bigquery-de-identify-76-million-ip-addresses-in-20-seconds-e9e652480bd2这篇文章中的说明将我的 IP 与块文件。
问题是我在尝试使用 .NET.SAFE_IP_FROM_STRING(ip_address) &.NET.IP.NET_MASK(4,mask) 函数时遇到错误。 错误是:
BYTES 的按位二元运算符要求输入的长度相等。 左侧有 16 个字节,右侧有 4 个字节。
因此,在使用正则表达式将 IP 传递给 function 之前,我尝试确保 IP 有效。 这适用于 ipv4。 我现在也找到了匹配 ipv6 的正则表达式,从我的检查来看,它似乎是准确的。 但是我仍然得到错误。 我不知道为什么以及如何修复我的查询以获得正确的结果。
请参阅下面的整个查询:
(
SELECT
*,
NET.SAFE_IP_FROM_STRING(ip_address) & NET.IP_NET_MASK(4,
mask) network_bin
FROM (
SELECT
* EXCEPT (is_valid)
FROM (
SELECT
*,
CASE
WHEN (REGEXP_CONTAINS(ip_address, r'\A[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7}\z') OR (NOT REGEXP_CONTAINS(ip_address, r'\A(.*?[a-f0-9](:|\z)){8}') AND REGEXP_CONTAINS(ip_address, r'\A([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,6})?::([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,6})?\z')) OR REGEXP_CONTAINS(ip_address, r'\A[a-f0-9]{1,4}(:[a-f0-9]{1,4}){5}:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z') OR (NOT REGEXP_CONTAINS(ip_address, r'\A(.*?[a-f0-9]:){6}') AND REGEXP_CONTAINS(ip_address, r'\A([a-f0-9]{1,4}(:[a-f0-9]{1,4}){0,4})?::([a-f0-9]{1,4}:){0,5}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}\z')) ) THEN TRUE
WHEN REGEXP_CONTAINS(ip_address, r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$") THEN TRUE
ELSE
FALSE
END
AS is_valid
FROM (
SELECT
user,
ip_address,
date
FROM
`project.dataset.table`)
WHERE
is_valid IS TRUE),
UNNEST(GENERATE_ARRAY(9,32)) mask)
问题在这里得到了回答: https://stackoverflow.com/a/65403033/12675934
总之:问题是 NET.SAFE_IP_FROM_STRING 返回 4 个字节的 IPv4 和 16 个字节的 IPv6。 所以 & NET.IP_NET_MASK(4, mask) 对于 IPv4 是可以的,但是对于 IPv6 你需要使用 & NET.IP_NET_MASK(16, mask)。
与这个问题有相同的答案How to improve performance of GeoIP query in BigQuery?
WITH test_data AS (
SELECT '2a02:2f0c:570c:fe00:1db7:21c4:21fa:f89' AS ip UNION ALL
SELECT '79.114.150.111' AS ip
)
-- replace the input_data with your data
, ipv4 AS (
SELECT DISTINCT ip, NET.SAFE_IP_FROM_STRING(ip) AS ip_bytes
FROM test_data
WHERE BYTE_LENGTH(NET.SAFE_IP_FROM_STRING(ip)) = 4
), ipv4d AS (
SELECT ip, city_name, country_name, latitude, longitude
FROM (
SELECT ip, ip_bytes & NET.IP_NET_MASK(4, mask) network_bin, mask
FROM ipv4, UNNEST(GENERATE_ARRAY(8,32)) mask
)
JOIN `demo_bq_dataset.geoip_city_v4`
USING (network_bin, mask)
), ipv6 AS (
SELECT DISTINCT ip, NET.SAFE_IP_FROM_STRING(ip) AS ip_bytes
FROM test_data
WHERE BYTE_LENGTH(NET.SAFE_IP_FROM_STRING(ip)) = 16
), ipv6d AS (
SELECT ip, city_name, country_name, latitude, longitude
FROM (
SELECT ip, ip_bytes & NET.IP_NET_MASK(16, mask) network_bin, mask
FROM ipv6, UNNEST(GENERATE_ARRAY(19,64)) mask
)
JOIN `demo_bq_dataset.geoip_city_v6`
USING (network_bin, mask)
)
SELECT * FROM ipv4d
UNION ALL
SELECT * FROM ipv6d
为了获得 geoip_city_v4 和 geoip_city_v6,您需要从https://maxmind.com/下载 geoip 数据库
您可以按照本教程更新和准备数据集https://hodo.dev/posts/post37-gcp-bigquery-geoip/ 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.