Geospatial joins

Learn about geospatial joins between tables

Kusto Query Language (KQL) provides tools for geospatial joins.

The following tools and capabilities are useful:

Examples

The following example illustrates join on locations using S2.

let locations1 = datatable(name: string, longitude: real, latitude: real)
[
    "a", -0.12433080766874127, 51.51115841361647,
    "b", -0.12432651341458723, 51.511160848670585,
    "c", -0.12432466939637266, 51.51115959669167,
    "d", 1,                    1,
];
let locations2 = datatable(id: string, longitude: real, latitude: real)
[
    "1", -0.12432668105284961, 51.51115938802832
];
let s2_join_level = 22; // More about join levels: https://learn.microsoft.com/en-us/kusto/query/geo-point-to-s2cell-function?view=azure-data-explorer
locations1
| extend hash = geo_point_to_s2cell(longitude, latitude, s2_join_level)
| join kind = inner (locations2 | extend hash = geo_point_to_s2cell(longitude, latitude, s2_join_level)) on hash
| project name, id  

Output

nameid
a1
b1
c1

The following example illustrates join on locations using H3 while accounting for a case where two nearby locations may be neighbors.

let locations1 = datatable(name: string, longitude: real, latitude: real)
[
    "a", -0.12433080766874127, 51.51115841361647,
    "b", -0.12432651341458723, 51.511160848670585,
    "c", -0.12432466939637266, 51.51115959669167,
    "d", 1,                    1,
];
let locations2 = datatable(id: string, longitude: real, latitude: real)
[
    "1", -0.12432668105284961, 51.51115938802832
];
let to_hash = (lng: real, lat: real)
{
    let h3_hash_level = 14; // More about join levels: https://learn.microsoft.com/en-us/kusto/query/geo-point-to-h3cell-function?view=azure-data-explorer
    let h3_hash = geo_point_to_h3cell(lng, lat, h3_hash_level);
    array_concat(pack_array(h3_hash), geo_h3cell_neighbors(h3_hash))
};
locations1
| extend hash = to_hash(longitude, latitude)
| mv-expand hash to typeof(string)
| join kind = inner (
    locations2
    | extend hash = to_hash(longitude, latitude)
    | mv-expand hash to typeof(string))
    on hash
| distinct name, id, longitude, latitude

Output

nameidlongitudelatitude
a1-0.12433080766874151.5111584136165
b1-0.12433080766874151.5111584136165
c1-0.12432466939637351.5111595966917

The following example illustrates join of locations from locations1 table with locations from locations2 table if the points from locations1 are within 300 meters of points from locations2 table.

let locations1 = datatable(name: string, longitude: real, latitude: real)
[
    "O2 Entrance", 0.005889454501716321, 51.50238626916584,
    "O2 Entrance", 0.0009625704125020596,51.50385432770013,
    "Greenwich Park", 0.0009395106042404677, 51.47700456557013,
];
let locations2 = datatable(id: string, longitude: real, latitude: real)
[
    "O2 Arena", 0.003159306017352037, 51.502929224128394
]
| extend buffer = geo_point_buffer(0.003159306017352037, 51.502929224128394, 300, 0.1); // Create a radius of 300 meters from O2 center location
locations1
| evaluate geo_polygon_lookup(locations2, buffer, longitude, latitude)
| project name, id, longitude, latitude

Output

nameidlongitudelatitude
O2 EntranceO2 Arena0.0009625704125020651.5038543277001
O2 EntranceO2 Arena0.0058894545017163251.5023862691658

|O2 Entrance|O2 Arena|0.00588945450171632|51.5023862691658|