如何有效地将两列范围转换为扩展的 table?
How can I efficiently transform a two-column range into an expanded table?
我正在尝试在雪花中使用地理 IP 数据。这涉及几件事:
1) 具有 CIDR IP 范围和 geoname_ID 及其 lat/long 坐标
的来源 table
2) 我使用了 parse_ip 函数并将 range_start 和 range_end 值提取为 ipv4 0-42 亿范围内的简单整数列。有些范围由 1 个 IP 组成,有些可能多达 1670 万。
因此,中间 table 数据中的 310 万行看起来像这样:
RANGE_START RANGE_END GEONAME_ID LATITUDE LONGITUDE
214690946 214690946 4556793 39.84980011 -75.37470245
214690947 214690947 6252001 37.75099945 -97.82199860
214690948 214690951 6252001 37.75099945 -97.82199860
214690952 214690959 6252001 37.75099945 -97.82199860
214690960 214690975 6252001 37.75099945 -97.82199860
如您所见,一个地理名称 ID 可以关联多个范围。
问题是用这个 table 连接一个(解析为整数值)IP 需要非相等连接,这在雪花中非常慢(根据经验大约慢 1000 倍)。所以我想将上面的 table 扩展为范围内的每个 IP 一行,即范围为 214690960 到 214690975 的最后一行将变成 16 行,同时为每个新行保留 geoname 和 lat long .我能想到的唯一方法是对生成器 table 进行非等值连接,但这在 3xl 上花费了 30 分钟处理 1000 行,生成了大约 120 万行结果。我在此范围内有 310 万行要展平,所以这行不通。
任何想法,任何人?
到目前为止,这是我尝试过的:
create OR REPLACE table GENERATOR_TABLE (IP INT);
INSERT INTO GENERATOR_TABLE SELECT ROW_NUMBER() over (ORDER BY NULL) AS IP FROM TABLE(GENERATOR(ROWCOUNT => 4228250627)) ORDER BY IP;
create or replace table GEO_INTERMEDIARY as
(select network_parsed:ipv4_range_start::number as range_start, network_parsed:"ipv4_range_end"::number range_end, geoname_id, latitude, longitude from GEO_SOURCE order by range_start, range_end);
CREATE OR REPLACE TABLE EXPANDED_GEO AS
select * from (select * from GEO_INTERMEDIARY order by geoname_id limit 1000 offset 0) A
JOIN GENERATOR_TABLE B ON B.IP >= A.RANGE_START AND B.IP <= A.RANGE_END
ORDER BY IP;
对于这种模式,您确实可以尝试使用生成器,但我通常最终会使用 JavaScript UDTFs。
以下是您的数据的示例函数和用法:
create or replace table x(
RANGE_START int,
RANGE_END int,
GEONAME_ID int,
LATITUDE double,
LONGITUDE double
) as
select * from values
(214690946,214690946,4556793,39.84980011,-75.37470245),
(214690947,214690947,6252001,37.75099945,-97.82199860),
(214690948,214690951,6252001,37.75099945,-97.82199860);
create or replace function magic(
range_start double,
range_end double,
geoname_id double,
latitude double,
longitude double
)
returns table (
ip double,
geoname_id double,
latitude double,
longitude double
) language javascript as
$$
{
processRow: function(row, rowWriter, context) {
let start = row.RANGE_START
let end = row.RANGE_END
while (start <= end) {
rowWriter.writeRow({
IP: start,
GEONAME_ID: row.GEONAME_ID,
LATITUDE: row.LATITUDE,
LONGITUDE: row.LONGITUDE,
});
start++;
}
}
}
$$;
select m.* from x,
table(magic(range_start::double, range_end::double,
geoname_id::double, latitude, longitude)) m;
-----------+------------+-------------+--------------+
IP | GEONAME_ID | LATITUDE | LONGITUDE |
-----------+------------+-------------+--------------+
214690946 | 4556793 | 39.84980011 | -75.37470245 |
214690947 | 6252001 | 37.75099945 | -97.8219986 |
214690948 | 6252001 | 37.75099945 | -97.8219986 |
214690949 | 6252001 | 37.75099945 | -97.8219986 |
214690950 | 6252001 | 37.75099945 | -97.8219986 |
214690951 | 6252001 | 37.75099945 | -97.8219986 |
-----------+------------+-------------+--------------+
这里唯一的问题是 JS 只支持 double
类型,但是对于这个数据,没关系,你不会看到任何精度损失。
我在产生 10M IP 的 1M 范围内对其进行了测试,它在几秒钟内完成。
我正在尝试在雪花中使用地理 IP 数据。这涉及几件事:
1) 具有 CIDR IP 范围和 geoname_ID 及其 lat/long 坐标
的来源 table2) 我使用了 parse_ip 函数并将 range_start 和 range_end 值提取为 ipv4 0-42 亿范围内的简单整数列。有些范围由 1 个 IP 组成,有些可能多达 1670 万。
因此,中间 table 数据中的 310 万行看起来像这样:
RANGE_START RANGE_END GEONAME_ID LATITUDE LONGITUDE
214690946 214690946 4556793 39.84980011 -75.37470245
214690947 214690947 6252001 37.75099945 -97.82199860
214690948 214690951 6252001 37.75099945 -97.82199860
214690952 214690959 6252001 37.75099945 -97.82199860
214690960 214690975 6252001 37.75099945 -97.82199860
如您所见,一个地理名称 ID 可以关联多个范围。
问题是用这个 table 连接一个(解析为整数值)IP 需要非相等连接,这在雪花中非常慢(根据经验大约慢 1000 倍)。所以我想将上面的 table 扩展为范围内的每个 IP 一行,即范围为 214690960 到 214690975 的最后一行将变成 16 行,同时为每个新行保留 geoname 和 lat long .我能想到的唯一方法是对生成器 table 进行非等值连接,但这在 3xl 上花费了 30 分钟处理 1000 行,生成了大约 120 万行结果。我在此范围内有 310 万行要展平,所以这行不通。
任何想法,任何人? 到目前为止,这是我尝试过的:
create OR REPLACE table GENERATOR_TABLE (IP INT);
INSERT INTO GENERATOR_TABLE SELECT ROW_NUMBER() over (ORDER BY NULL) AS IP FROM TABLE(GENERATOR(ROWCOUNT => 4228250627)) ORDER BY IP;
create or replace table GEO_INTERMEDIARY as
(select network_parsed:ipv4_range_start::number as range_start, network_parsed:"ipv4_range_end"::number range_end, geoname_id, latitude, longitude from GEO_SOURCE order by range_start, range_end);
CREATE OR REPLACE TABLE EXPANDED_GEO AS
select * from (select * from GEO_INTERMEDIARY order by geoname_id limit 1000 offset 0) A
JOIN GENERATOR_TABLE B ON B.IP >= A.RANGE_START AND B.IP <= A.RANGE_END
ORDER BY IP;
对于这种模式,您确实可以尝试使用生成器,但我通常最终会使用 JavaScript UDTFs。
以下是您的数据的示例函数和用法:
create or replace table x(
RANGE_START int,
RANGE_END int,
GEONAME_ID int,
LATITUDE double,
LONGITUDE double
) as
select * from values
(214690946,214690946,4556793,39.84980011,-75.37470245),
(214690947,214690947,6252001,37.75099945,-97.82199860),
(214690948,214690951,6252001,37.75099945,-97.82199860);
create or replace function magic(
range_start double,
range_end double,
geoname_id double,
latitude double,
longitude double
)
returns table (
ip double,
geoname_id double,
latitude double,
longitude double
) language javascript as
$$
{
processRow: function(row, rowWriter, context) {
let start = row.RANGE_START
let end = row.RANGE_END
while (start <= end) {
rowWriter.writeRow({
IP: start,
GEONAME_ID: row.GEONAME_ID,
LATITUDE: row.LATITUDE,
LONGITUDE: row.LONGITUDE,
});
start++;
}
}
}
$$;
select m.* from x,
table(magic(range_start::double, range_end::double,
geoname_id::double, latitude, longitude)) m;
-----------+------------+-------------+--------------+
IP | GEONAME_ID | LATITUDE | LONGITUDE |
-----------+------------+-------------+--------------+
214690946 | 4556793 | 39.84980011 | -75.37470245 |
214690947 | 6252001 | 37.75099945 | -97.8219986 |
214690948 | 6252001 | 37.75099945 | -97.8219986 |
214690949 | 6252001 | 37.75099945 | -97.8219986 |
214690950 | 6252001 | 37.75099945 | -97.8219986 |
214690951 | 6252001 | 37.75099945 | -97.8219986 |
-----------+------------+-------------+--------------+
这里唯一的问题是 JS 只支持 double
类型,但是对于这个数据,没关系,你不会看到任何精度损失。
我在产生 10M IP 的 1M 范围内对其进行了测试,它在几秒钟内完成。