Whilst working on an Azure Data Lake project, a requirement hit the backlog that could be easily solved with a Geographical Information System (GIS) or even SQL Server – Spatial data type support was introduced into SQL Server 2008.
However, Azure Data Lake Analytics (ADLA) does not natively support spatial data analytics so we’ll have to extract the data into another service right? Wrong ? 🙂
Due to the extensibility of Azure Data Lake Analytics, we can enhance it to do practically anything. In fact, we can lean on existing components and enhance the service without having to develop the enhancement itself.
This blog is a quick run through demonstrating how to enhance ADLA such that it will support Spatial analytics and meet our project requirement.
For simplicity I’ve trivialised the problem. Here’s the requirement:
Indicate which Bus Stops are within 1.5 km of Southwark Tube Station.
To support this requirement, we have two datasets:
- A list of all the Bus Stops in London, including their Geo location (circa 20k records)
- The Geo location record of Southwark Tube Station (a single record !)
- In fact, the location of the tube station is pretty accurate and is geo located to the entrance pavement outside the tube station:
This would be an easy problem for a GIS to solve. You would specify the central point i.e. our Southwark Tube station marker and draw a circle, or buffer, with a radius 1.5 km around it and select all bus stops that fall within or intersect with that circle. This spatial analysis is easy for these systems as that’s essentially what they are built to do.
SQL Server 2008 introduced the Spatial Data Type, this allowed spatial style analysis to be performed on geo data using T-SQL in conjunction with the supplied Geometry and Geography data types. More info on those can be found here
So, how can we solve our problem in ADLA, without a GIS and without having to export the data to SQL Server??
You can register existing assemblies with ADLA. It so happens that the SQL Server Data Types and Spatial assemblies are nicely packaged up and can be used directly within ADLA itself – think about that, it’s pretty awesome !
Caveat: At the time of writing we have no idea of the licence implications. It will be up to you to ensure you are not in breach 🙂
Those assemblies can be downloaded from here. You only need to download and install the following file:
This installs two key assemblies, which you’ll need to grab and upload to your Data Lake Store:
- C:Program Files (x86)Microsoft SQL Server130SDKAssembliesMicrosoft.SqlServer.Types.dll
Once they have been uploaded to your Data Lake Store, you need to register those assemblies with ADLA.
DECLARE @ASSEMBLY_PATH string = "/5.UTILITY/USQL-Extend/SQL-Server/"; DECLARE @TYPES_ASM string = @ASSEMBLY_PATH+"Microsoft.SqlServer.Types.dll"; DECLARE @SPATIAL_ASM string = @ASSEMBLY_PATH+"SqlServerSpatial130.dll"; CREATE DATABASE IF NOT EXISTS SQLServerExtensions; USE DATABASE SQLServerExtensions; DROP ASSEMBLY IF EXISTS SqlSpatial; CREATE ASSEMBLY SqlSpatial FROM @TYPES_ASM WITH ADDITIONAL_FILES = ( @SPATIAL_ASM );
Following registration of the assemblies, we can see the registration loaded in the ADLA Catalog database we created:
We are now ready to use this U-SQL enhancement in our U-SQL Query – let’s go right ahead and solve our problem in one U-SQL Script.
// Reference the assemblies we require in our script. // System.Xml we get for free as a System Assembly so we didn't need to register that and our SQLServerExtensions.SqlSpatial assembly REFERENCE SYSTEM ASSEMBLY [System.Xml]; REFERENCE ASSEMBLY SQLServerExtensions.SqlSpatial; // Once the appropriate assemblies are registered, we can alias them using the USING keyword. USING Geometry = Microsoft.SqlServer.Types.SqlGeometry; USING Geography = Microsoft.SqlServer.Types.SqlGeography; USING SqlChars = System.Data.SqlTypes.SqlChars; // First create the centralised point. // In this case it's the pavement outside the entrance of Southwark Tube Station, London. // Format is Longitude, Latitude and then SRID. // NB: It's Longitude then Latitude, that's the opposite way to what you might expect.. DECLARE @southwarkTube Geography = Geography.Point(-0.104777,51.503829,4326); // Next we extract our entire London bus stop data set from the file. // There's about 20k of them. @busStopInput = EXTRACT [StopCode] string, [StopName] string, [Latitude] double?, [Longitude] double? FROM @"/1.RAW/OpenData/Transport/bus-stops-narrow-full-london.csv" USING Extractors.Csv(skipFirstNRows:1,silent:true); // This is effectively the transform step and where the magic happens // Very similar syntax to what you would do in T-SQL. // We are returning all the bus stops that fall within 1500m of Southwark Tube // Essentially we return all stops that intersect with a 1500m buffer around the central tube point @closeBusStops= SELECT * FROM @busStopInput WHERE @southwarkTube.STBuffer(1500).STIntersects(Geography.Point((double)@busStopInput.Longitude,(double)@busStopInput.Latitude,4326)).ToString()=="True"; // The results are written out to a csv file. OUTPUT @closeBusStops TO "/4.LABORATORY/Desks/Sach/spatial-closebusstops.csv" USING Outputters.Csv(outputHeader: true);
The query outputs a list of bus stops that are within the specified Spatial distance from Southwark Tube Station. If we have a look at all the bus stops (in red) and overlay all the ‘close’ bus stops (in green), we can see the results:
Azure Data Lake Analytics does not natively support spatial data analytics but by simply utilising the assemblies that ship with SQL Server, we can extend the capability of U-SQL to provide that functionality or practically any functionality we desire.