访客和最近商店之间的测地距离
geodesic distance between visitors and closest store
我有一个很大的 .csv 数据集,其中包含 10e7 个点,坐标(纬度、经度)表示访问者的位置。我有另一个包含 10e3 点的数据集,坐标表示商店的位置。
我想使用某种测地线公式将最近的商店关联到每个访问者。
我想要真正快速高效的东西,我可以在 python(例如 pandas)或 Google BigQuery 上 运行。
有人可以给我线索吗?
这是一个快速解决方案,可以在 DBpedia (v2014) 中为 21,221 个城市找到最近的 NOAA 气象站。
#standardSQL
CREATE TEMPORARY FUNCTION distance(lat1 FLOAT64, lon1 FLOAT64, lat2 FLOAT64, lon2 FLOAT64)
RETURNS FLOAT64
LANGUAGE js AS """
var p = 0.017453292519943295; // Math.PI / 180
var c = Math.cos;
var a = 0.5 - c((lat2 - lat1) * p)/2 +
c(lat1 * p) * c(lat2 * p) *
(1 - c((lon2 - lon1) * p))/2;
return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
""";
SELECT *
FROM (
SELECT city, country_label, distance, name weather_station, country,
RANK() OVER(PARTITION BY city ORDER BY distance DESC) rank
FROM (
SELECT city, a.country_label, distance(a.lat,a.lon,b.lat,b.lon) distance, b.name, b.country
FROM (
SELECT rdf_schema_label city, country_label, country,
CAST(REGEXP_EXTRACT(point, r'(-?\d*\.\d*)') as FLOAT64) lat,
CAST(REGEXP_EXTRACT(point, r' (-?\d*\.\d*)') as FLOAT64) lon
FROM `fh-bigquery.dbpedia2014temp.City`
WHERE point!='NULL'
) a
JOIN (
SELECT name, country, usaf, wban, lat, lon
FROM `bigquery-public-data.noaa_gsod.stations`
WHERE lat != 0.0 AND lon !=0.0
) b
ON CAST(a.lat as INT64)=CAST(b.lat as INT64)
AND CAST(a.lon as INT64)=CAST(b.lon as INT64)
)
)
WHERE rank=1
注意事项:
- 它使用来自
的距离公式
- 通过仅搜索与城市相同 INT(lat),INT(lon) 的站点来限制 JOIN 进行优化。可以改进这一点,但我会把它留给另一个问题。
添加到 Felipe 答案:
您可以使用 SQL UDF 与 JS UDF
JS UDF 有一些 Limits 而 SQL UDF 没有
因此,您可以与 Felipe 的其余代码一起使用的等效 SQL UDF 是
CREATE TEMPORARY FUNCTION distance(lat1 FLOAT64, lon1 FLOAT64, lat2 FLOAT64, lon2 FLOAT64)
RETURNS FLOAT64 AS ((
WITH constants AS (
SELECT 0.017453292519943295 AS p
)
SELECT 12742 * ASIN(SQRT(
0.5 - COS((lat2 - lat1) * p)/2 +
COS(lat1 * p) * COS(lat2 * p) *
(1 - COS((lon2 - lon1) * p))/2))
FROM constants
));
我尽量保留各自 JS UDF 的布局,这样你就可以看到它是如何创建的
我有一个很大的 .csv 数据集,其中包含 10e7 个点,坐标(纬度、经度)表示访问者的位置。我有另一个包含 10e3 点的数据集,坐标表示商店的位置。
我想使用某种测地线公式将最近的商店关联到每个访问者。
我想要真正快速高效的东西,我可以在 python(例如 pandas)或 Google BigQuery 上 运行。
有人可以给我线索吗?
这是一个快速解决方案,可以在 DBpedia (v2014) 中为 21,221 个城市找到最近的 NOAA 气象站。
#standardSQL
CREATE TEMPORARY FUNCTION distance(lat1 FLOAT64, lon1 FLOAT64, lat2 FLOAT64, lon2 FLOAT64)
RETURNS FLOAT64
LANGUAGE js AS """
var p = 0.017453292519943295; // Math.PI / 180
var c = Math.cos;
var a = 0.5 - c((lat2 - lat1) * p)/2 +
c(lat1 * p) * c(lat2 * p) *
(1 - c((lon2 - lon1) * p))/2;
return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
""";
SELECT *
FROM (
SELECT city, country_label, distance, name weather_station, country,
RANK() OVER(PARTITION BY city ORDER BY distance DESC) rank
FROM (
SELECT city, a.country_label, distance(a.lat,a.lon,b.lat,b.lon) distance, b.name, b.country
FROM (
SELECT rdf_schema_label city, country_label, country,
CAST(REGEXP_EXTRACT(point, r'(-?\d*\.\d*)') as FLOAT64) lat,
CAST(REGEXP_EXTRACT(point, r' (-?\d*\.\d*)') as FLOAT64) lon
FROM `fh-bigquery.dbpedia2014temp.City`
WHERE point!='NULL'
) a
JOIN (
SELECT name, country, usaf, wban, lat, lon
FROM `bigquery-public-data.noaa_gsod.stations`
WHERE lat != 0.0 AND lon !=0.0
) b
ON CAST(a.lat as INT64)=CAST(b.lat as INT64)
AND CAST(a.lon as INT64)=CAST(b.lon as INT64)
)
)
WHERE rank=1
注意事项:
- 它使用来自 的距离公式
- 通过仅搜索与城市相同 INT(lat),INT(lon) 的站点来限制 JOIN 进行优化。可以改进这一点,但我会把它留给另一个问题。
添加到 Felipe 答案:
您可以使用 SQL UDF 与 JS UDF
JS UDF 有一些 Limits 而 SQL UDF 没有
因此,您可以与 Felipe 的其余代码一起使用的等效 SQL UDF 是
CREATE TEMPORARY FUNCTION distance(lat1 FLOAT64, lon1 FLOAT64, lat2 FLOAT64, lon2 FLOAT64)
RETURNS FLOAT64 AS ((
WITH constants AS (
SELECT 0.017453292519943295 AS p
)
SELECT 12742 * ASIN(SQRT(
0.5 - COS((lat2 - lat1) * p)/2 +
COS(lat1 * p) * COS(lat2 * p) *
(1 - COS((lon2 - lon1) * p))/2))
FROM constants
));
我尽量保留各自 JS UDF 的布局,这样你就可以看到它是如何创建的