HAVERSINE distance in BigQuery?

后端 未结 2 673
暗喜
暗喜 2020-12-06 12:47

I\'m looking for a way to get HAVERSINE() in BigQuery. For example, how to get the closest weather stations to an arbitrary point?

相关标签:
2条回答
  • 2020-12-06 13:12

    2019 update: BigQuery now has a native ST_DISTANCE() function, which is more accurate than Haversine.

    For example:

    #standardSQL
    CREATE TEMP FUNCTION RADIANS(x FLOAT64) AS (
      ACOS(-1) * x / 180
    );
    CREATE TEMP FUNCTION RADIANS_TO_KM(x FLOAT64) AS (
      111.045 * 180 * x / ACOS(-1)
    );
    CREATE TEMP FUNCTION HAVERSINE(lat1 FLOAT64, long1 FLOAT64,
                                   lat2 FLOAT64, long2 FLOAT64) AS (
      RADIANS_TO_KM(
        ACOS(COS(RADIANS(lat1)) * COS(RADIANS(lat2)) *
             COS(RADIANS(long1) - RADIANS(long2)) +
             SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))))
    );
    
    SELECT
      lat,
      lon,
      name,
      HAVERSINE(40.73943, -73.99585, lat, lon) *1000 AS haversine_distance
      , ST_DISTANCE(
          ST_GEOGPOINT(-73.99585, 40.73943)
          , ST_GEOGPOINT(lon,lat)) bqgis_distance
    FROM `bigquery-public-data.noaa_gsod.stations`
    WHERE lat IS NOT NULL AND lon IS NOT NULL
    ORDER BY 1 DESC
    LIMIT 4;
    


    Using standard SQL you can define a SQL function to encapsulate the logic. For example,

    #standardSQL
    CREATE TEMP FUNCTION RADIANS(x FLOAT64) AS (
      ACOS(-1) * x / 180
    );
    CREATE TEMP FUNCTION RADIANS_TO_KM(x FLOAT64) AS (
      111.045 * 180 * x / ACOS(-1)
    );
    CREATE TEMP FUNCTION HAVERSINE(lat1 FLOAT64, long1 FLOAT64,
                                   lat2 FLOAT64, long2 FLOAT64) AS (
      RADIANS_TO_KM(
        ACOS(COS(RADIANS(lat1)) * COS(RADIANS(lat2)) *
             COS(RADIANS(long1) - RADIANS(long2)) +
             SIN(RADIANS(lat1)) * SIN(RADIANS(lat2))))
    );
    
    SELECT
      lat,
      lon,
      name,
      HAVERSINE(40.73943, -73.99585, lat, lon) AS distance_in_km
    FROM `bigquery-public-data.noaa_gsod.stations`
    WHERE lat IS NOT NULL AND lon IS NOT NULL
    ORDER BY distance_in_km
    LIMIT 4;
    
    0 讨论(0)
  • 2020-12-06 13:17

    2018 update: BigQuery now supports native geo functions.

    ST_DISTANCE: Returns the shortest distance in meters between two non-empty GEOGRAPHYs.

    Distance between NY and Seattle:

    #standardSQL
    WITH geopoints AS (
      SELECT ST_GEOGPOINT(lon,lat) p, name, state
      FROM `bigquery-public-data.noaa_gsod.stations`  
    )
    
    SELECT ST_DISTANCE(
      (SELECT p FROM geopoints WHERE name='PORT AUTH DOWNTN MANHATTAN WA'),
      (SELECT p FROM geopoints WHERE name='SEATTLE')
    )
    
    3866381.55
    
    • https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions

    Legacy SQL solution (standard pending):

    SELECT lat, lon, name,
      (111.045 * DEGREES(ACOS(COS(RADIANS(40.73943)) * COS(RADIANS(lat)) * COS(RADIANS(-73.99585) - RADIANS(lon)) + SIN(RADIANS(40.73943)) * SIN(RADIANS(lat))))) AS distance
    FROM [bigquery-public-data:noaa_gsod.stations]
    HAVING distance>0
    ORDER BY distance
    LIMIT 4
    

    (based on http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/)

    0 讨论(0)
提交回复
热议问题