Skip to content

Latest commit

 

History

History

spatial-data

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

Spatial Data - Student Labs

Overview

In these labs, we will explore the following spatial features supported by CockroachDB:

  • How to put together separate spatial data sets to ask and answer potentially interesting questions.
  • How to use various built-in functions for operating on spatial data.
  • How to create indexes on spatial data.
  • Performing joins on spatial data, and how to use EXPLAIN to make sure we are using indexes effectively.

We use the following datasets:

  • NY State bird sighting data from the years 2000-2019, taken from the North American Breeding Bird Survey (NABBS), see here.

  • Road data from the US National Atlas - Major Roads of the United States data set, here.

  • Bookstores information scraped from the American Booksellers Association website's member directory, here.

Labs Prerequisites

  1. Build the single region dev cluster:

  2. You also need:

Lab 0 - Create database and load data

Connect to the database

# use cockroach sql, defaults to localhost:26257
cockroach sql --insecure

# or use the --url param for any another host:
cockroach sql --url "postgresql://localhost:26257/defaultdb?sslmode=disable"

# or use psql
psql -h localhost -p 26257 -U root defaultdb
IMPORT TABLE birds (
    id INT8 NOT NULL,
    name VARCHAR NOT NULL,
    bird_family VARCHAR NOT NULL,
    genus VARCHAR NOT NULL,
    species VARCHAR NOT NULL,
    bird_order VARCHAR NOT NULL,
    CONSTRAINT "primary" PRIMARY KEY (id ASC),
    INDEX birds_name_idx (name ASC),
    FAMILY "primary" (id, name, bird_family, genus, species, bird_order)
) CSV DATA (
    'https://github.com/cockroachlabs/workshop_labs/raw/master/spatial-data/data/birds.csv.gz'
) WITH skip = '1';

IMPORT TABLE routes (
    id INT8 NOT NULL,
    name VARCHAR NOT NULL,
    country VARCHAR NOT NULL,
    state VARCHAR NOT NULL,
    geom GEOMETRY NOT NULL,
    CONSTRAINT "primary" PRIMARY KEY (id ASC),
    FAMILY "primary" (id, name, country, state, geom)
) CSV DATA (
    'https://github.com/cockroachlabs/workshop_labs/raw/master/spatial-data/data/routes.csv.gz'
) WITH skip = '1';

IMPORT TABLE observations (
    id UUID NOT NULL DEFAULT gen_random_uuid(),
    country VARCHAR NOT NULL,
    state VARCHAR NOT NULL,
    route_id INT8 NULL,
    year INT8 NOT NULL,
    bird_id INT8 NULL,
    count INT8 NOT NULL,
    CONSTRAINT "primary" PRIMARY KEY (id ASC),
    INDEX observations_bird_id_idx (bird_id ASC),
    FAMILY "primary" (id, country, state, route_id, year, bird_id, count)
) CSV DATA (
    'https://github.com/cockroachlabs/workshop_labs/raw/master/spatial-data/data/observations.csv.gz'
) WITH skip = '1';

IMPORT TABLE bookstores (
    id UUID NOT NULL DEFAULT gen_random_uuid(),
    name STRING NOT NULL,
    url STRING NULL,
    phone STRING NULL,
    address STRING NOT NULL,
    street STRING NOT NULL,
    city STRING NOT NULL,
    state STRING NOT NULL,
    zip STRING NOT NULL,
    description STRING NULL,
    geom GEOMETRY NULL,
    CONSTRAINT "primary" PRIMARY KEY (id ASC),
    FAMILY "primary" (id, name, url, phone, address, street, city, state, zip, description, geom)
) CSV DATA (
    'https://github.com/cockroachlabs/workshop_labs/raw/master/spatial-data/data/bookstores.csv.gz'
) WITH skip = '1', nullif = 'NULL';

IMPORT TABLE bookstore_routes (
    id UUID NOT NULL DEFAULT gen_random_uuid(),
    name VARCHAR NULL,
    start_store_id UUID NULL,
    end_store_id UUID NULL,
    geom GEOMETRY NOT NULL,
    CONSTRAINT "primary" PRIMARY KEY (id ASC),
    FAMILY "primary" (id, name, start_store_id, end_store_id, geom)
) CSV DATA (
    'https://github.com/cockroachlabs/workshop_labs/raw/master/spatial-data/data/bookstore_routes.csv.gz'
) WITH skip = '1';

IMPORT TABLE roads (
    gid INT8 NOT NULL DEFAULT unique_rowid(),
    prime_name VARCHAR(50) NULL,
    secondary VARCHAR(30) NULL,
    prefix_dir VARCHAR(10) NULL,
    pre_type VARCHAR(30) NULL,
    name VARCHAR(30) NULL,
    street_typ VARCHAR(10) NULL,
    suffix_dir VARCHAR(10) NULL,
    interstate VARCHAR(20) NULL,
    us_route VARCHAR(20) NULL,
    st_route VARCHAR(20) NULL,
    qualifier VARCHAR(5) NULL,
    trans_type VARCHAR(5) NULL,
    fcode VARCHAR(2) NULL,
    state_fips VARCHAR(2) NULL,
    state VARCHAR(2) NULL,
    miles DECIMAL NULL,
    kilometers DECIMAL NULL,
    geom GEOMETRY(MULTILINESTRING) NULL,
    CONSTRAINT "primary" PRIMARY KEY (gid ASC),
    INDEX roads_state_idx (state ASC),
    FAMILY "primary" (gid, prime_name, secondary, prefix_dir, pre_type, name, street_typ, suffix_dir, interstate, us_route, st_route, qualifier, trans_type, fcode, state_fips, state, miles, kilometers, geom )
) CSV DATA (
    'https://github.com/cockroachlabs/workshop_labs/raw/master/spatial-data/data/roads.csv.gz'
) WITH skip = '1';


SHOW TABLES;
  schema_name |    table_name    | type  | owner | estimated_row_count
--------------+------------------+-------+-------+----------------------
  public      | birds            | table | root  |                 756
  public      | bookstore_routes | table | root  |                  56
  public      | bookstores       | table | root  |                2913
  public      | observations     | table | root  |               85731
  public      | roads            | table | root  |              225838
  public      | routes           | table | root  |                 129
(6 rows)

Lab 1 - ST_Collect() and ST_AsGeoJSON()

In this lab the goal is to find the Common Loon sightings by the NABBS in the years 2000-2019 in NY state.

We will be using a few built-in spatial functions for this and the next lab.

First, we create a list of all of the sightings of the Common Loon.

Then, we use the ST_Collect() function, which collects geometries into a GeometryCollection object.

Finally, we take the GeometryCollection object and use the ST_AsGeoJSON() function to convert it to the GeoJSON format, which is much more extensible and user friendly, too.

WITH loon_sightings AS (
    SELECT
        (st_collect(routes.geom)) AS the_geom
    FROM
        birds
        JOIN observations ON birds.id = observations.bird_id
        JOIN routes ON observations.route_id = routes.id
    WHERE
        birds.name = 'Common Loon'
)
SELECT
    ST_AsGeoJSON(the_geom)
FROM
    loon_sightings;
                                                                                                                                                                                                            st_asgeojson
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  {"type":"MultiPoint","coordinates":[[-75.078218,43.662991],[-75.078218,43.662991],[-75.078218,43.662991],[-75.078218,43.662991],[-75.078218,43.662991],[-75.078218,43.662991],[-75.078218,43.662991],[-74.389678,43.652701],[-74.389678,43.652701],[-74.389678,43.652701],[-74.389678,43.652701],[-74.389678,43.652701],[-74.389678,43.652701],[-74.389678,43.652701],[-74.389678,43.652701],[-74.389678,43.652701],[-74.9492509,43.6625207],[-74.473788,43.726581],[-74.473788,43.726581],[-74.473788,43.726581],[-74.234828,43.971271],[-74.234828,43.971271],[-74.234828,43.971271],[-74.234828,43.971271],[-74.234828,43.971271],[-74.234828,43.971271],[-74.3975289,43.5654587],[-74.3975289,43.5654587],[-74.7918689,43.7217467],[-74.7918689,43.7217467],[-74.7918689,43.7217467],[-74.7918689,43.7217467],[-74.7918689,43.7217467],[-74.7918689,43.7217467],[-74.7918689,43.7217467],[-74.7918689,43.7217467],[-74.0622389,43.6884937],[-74.0622389,43.6884937],[-73.7371009,43.6098217],[-75.0557089,44.4354227],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.9230359,44.1319167],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.1807169,44.4319917],[-74.7210849,44.5376687],[-74.7210849,44.5376687],[-74.7210849,44.5376687],[-73.4887779,44.4433387],[-73.4887779,44.4433387],[-75.7014799,44.1487467],[-75.7014799,44.1487467],[-75.7014799,44.1487467],[-75.7014799,44.1487467],[-75.7014799,44.1487467],[-74.9852279,42.0781957],[-74.9852279,42.0781957],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.966888,43.679941],[-74.492148,44.522881],[-74.492148,44.522881],[-74.492148,44.522881],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587],[-74.6305979,44.1294587]]}

Copy the output of the query and paste it into http://geojson.io to see what it looks like.

loon-sightings

Lab 2 - ST_Area(), ST_ConvexHull() and ST_Transform()

In this lab, the goal is to find the area of the Loon's sightings range.

As before, we create a list of all of the sightings of the Common Loon into a GeometryCollection object.

Then, we calculate the convex hull of object using ST_ConvexHull(), read more about it in the docs.

We need to note that because the routes data uses SRID 4326, the resulting area is measured in degrees and we need to cast it into a GEOGRAPHY object before using ST_Area() to calculate the area, which we convert to square km.

WITH loon_sightings AS (
    SELECT
        (st_collect(routes.geom)) AS the_geom
    FROM
        birds
        JOIN observations ON birds.id = observations.bird_id
        JOIN routes ON observations.route_id = routes.id
    WHERE
        birds.name = 'Common Loon'
)
SELECT
    st_area(st_convexhull(the_geom)::GEOGRAPHY) / 1000 ^ 2 AS area_km_squared
    -- alternatively, using ST_Transform
    -- st_area(ST_Transform(st_convexhull(the_geom), 26986)) / 1000 ^ 2 AS area_km_squared
FROM
    loon_sightings;
   area_km_squared
----------------------
  27003.820075269043
(1 row)

Lab 3 - ST_Contain()

In this lab, the goal is to find bookstores that lie within the Loon's habitat range.

Similar to the previous labs, let's build a CTE that returns the convex hull of Common Loon habitat. We then join the result with the bookstores table to check whether a bookstore's location is contained by the loon habitat by making use of the ST_Contains() function.

WITH loon_sightings AS (
    SELECT
        ST_ConvexHull(ST_Collect(routes.geom)) AS loon_hull
    FROM
        birds
        JOIN observations ON birds.id = observations.bird_id
        JOIN routes ON observations.route_id = routes.id
    WHERE
        birds.name = 'Common Loon'
)
SELECT
    name, street, city, state
FROM
    loon_sightings
    JOIN bookstores ON ST_Contains(loon_hull, geom)
ORDER BY
    geom;
                        name                       |        street         |      city      | state
---------------------------------------------------+-----------------------+----------------+--------
  Blacktree Books                                  | 5006 state Highway 23 | Oneonta        | NY
  The Green Toad Bookstore                         | 198 Main St           | Oneonta        | NY
  The Treehouse Reading and Arts Center            | 587 Main St Ste 304   | New York Mills | NY
  Gansevoort House Books at Gems Along the Mohawk  | 800 Mohawk St         | Herkimer       | NY
  Gansevoort House Books at The Shoppes at 25 West | 25 W Mill Street      | Little Falls   | NY
  Mysteries On Main Street                         | 144 W Main St         | Johnstown      | NY
  The Bookstore Plus Music & Art               | 2491 Main St          | Lake Placid    | NY
  The Book Nook (Saranac Lake, NY)                 | 7 Broadway            | Saranac Lake   | NY
(8 rows)

Let's put the locations on a map using ST_AsGeoJSON().

WITH loon_sightings AS (
    SELECT
        ST_ConvexHull(ST_Collect(routes.geom)) AS loon_hull
    FROM
        birds
        JOIN observations ON birds.id = observations.bird_id
        JOIN routes ON observations.route_id = routes.id
    WHERE
        birds.name = 'Common Loon'
)
SELECT
    jsonb_pretty(ST_AsGeoJSON(ST_Collect(geom)) :: JSONB) AS bookstore_loc
FROM
    loon_sightings
    JOIN bookstores ON ST_Contains(loon_hull, geom);
       bookstore_loc
----------------------------
  {
      "coordinates": [
          [
              -74.992647,
              43.01861
          ],
          [
              -74.374175,
              43.006495
          ],
          [
              -74.860436,
              43.040708
          ],
          [
              -75.062138,
              42.454003
          ],
          [
              -74.131673,
              44.326892
          ],
          [
              -75.036815,
              42.448793
          ],
          [
              -73.980251,
              44.279377
          ],
          [
              -75.296575,
              43.098322
          ]
      ],
      "type": "MultiPoint"
  }
(1 row)

bookstore-loc

Lab 4 - ST_Distance()

THe goal is to get a list of the most often sighted birds within 10 miles of The Book Nook in Saranac Lake, NY.

Build a CTE that returns the geom of the bookstore we want to visit, The Book Nook.

Use ST_Distance(), which returns the distance in meters between geography_a and geography_b, to list the names and observation totals (sums) of birds whose habitats are within 10 miles of the location of the bookstore.

WITH the_book_nook AS (
    SELECT geom FROM bookstores WHERE name = 'The Book Nook (Saranac Lake, NY)'
)
SELECT
    birds.name,
    SUM(observations.COUNT) AS sightings
FROM
    birds
    JOIN observations ON birds.id = observations.bird_id
    JOIN routes ON observations.route_id = routes.id,
    the_book_nook
WHERE
    ST_Distance(
        the_book_nook.geom :: GEOGRAPHY,
        routes.geom :: GEOGRAPHY
    ) < (1609 * 10)
GROUP BY
    birds.name
ORDER BY
    sightings DESC
LIMIT
    10;
                   name                  | sightings
-----------------------------------------+------------
  Red-eyed Vireo                         |      2557
  White-throated Sparrow                 |       928
  Hermit Thrush                          |       924
  American Robin                         |       691
  Ovenbird                               |       650
  American Crow                          |       528
  (Myrtle Warbler) Yellow-rumped Warbler |       506
  Chipping Sparrow                       |       465
  Black-capped Chickadee                 |       390
  Yellow-bellied Sapsucker               |       359
(10 rows)

Note how, if you pull the query plan using EXPLAIN (VERBOSE), the optimizer uses the ST_DWithinexclusive accelarated function instead of ST_Distance().

                        tree                        |        field        |                          description                           |                       columns                        | ordering
----------------------------------------------------+---------------------+----------------------------------------------------------------+------------------------------------------------------+-----------
                                                    | distribution        | full                                                           |                                                      |
                                                    | vectorized          | true                                                           |                                                      |
  limit                                             |                     |                                                                | (name, sightings)                                    |
   │                                                | estimated row count | 10                                                             |                                                      |
   │                                                | count               | 10                                                             |                                                      |
   └── sort                                         |                     |                                                                | (name, sum)                                          | -sum
        │                                           | estimated row count | 756                                                            |                                                      |
        │                                           | order               | -sum                                                           |                                                      |
        └── group                                   |                     |                                                                | (name, sum)                                          |
             │                                      | estimated row count | 756                                                            |                                                      |
             │                                      | aggregate 0         | sum(count)                                                     |                                                      |
             │                                      | group by            | name                                                           |                                                      |
             └── project                            |                     |                                                                | (name, count)                                        |
                  └── hash join (inner)             |                     |                                                                | (route_id, bird_id, count, id, geom, geom, id, name) |
                       │                            | estimated row count | 28746                                                          |                                                      |
                       │                            | equality            | (bird_id) = (id)                                               |                                                      |
                       │                            | right cols are key  |                                                                |                                                      |
                       ├── hash join (inner)        |                     |                                                                | (route_id, bird_id, count, id, geom, geom)           |
                       │    │                       | estimated row count | 34021                                                          |                                                      |
                       │    │                       | equality            | (route_id) = (id)                                              |                                                      |
                       │    ├── scan                |                     |                                                                | (route_id, bird_id, count)                           |
                       │    │                       | estimated row count | 85731                                                          |                                                      |
                       │    │                       | table               | observations@primary                                           |                                                      |
                       │    │                       | spans               | FULL SCAN                                                      |                                                      |
                       │    └── cross join (inner)  |                     |                                                                | (id, geom, geom)                                     |
                       │         │                  | estimated row count | 43                                                             |                                                      |
                       │         │                  | pred                | st_dwithinexclusive(geom::GEOGRAPHY, geom::GEOGRAPHY, 16090.0) |                                                      |
                       │         ├── scan           |                     |                                                                | (id, geom)                                           |
                       │         │                  | estimated row count | 129                                                            |                                                      |
                       │         │                  | table               | routes@primary                                                 |                                                      |
                       │         │                  | spans               | FULL SCAN                                                      |                                                      |
                       │         └── render         |                     |                                                                | (geom)                                               |
                       │              │             | estimated row count | 1                                                              |                                                      |
                       │              │             | render 0            | geom                                                           |                                                      |
                       │              └── filter    |                     |                                                                | (name, geom)                                         |
                       │                   │        | estimated row count | 1                                                              |                                                      |
                       │                   │        | filter              | name = 'The Book Nook (Saranac Lake, NY)'                      |                                                      |
                       │                   └── scan |                     |                                                                | (name, geom)                                         |
                       │                            | estimated row count | 2913                                                           |                                                      |
                       │                            | table               | bookstores@primary                                             |                                                      |
                       │                            | spans               | FULL SCAN                                                      |                                                      |
                       └── scan                     |                     |                                                                | (id, name)                                           |
                                                    | estimated row count | 756                                                            |                                                      |
                                                    | table               | birds@birds_name_idx                                           |                                                      |
                                                    | spans               | FULL SCAN                                                      |                                                      |
(45 rows)

Lab 5 - ST_Length()

In this lab, we want to find the length of the route from Mysteries on Main Street in Johnstown, NY, to The Book Nook in Saranac Lake, NY.

Function STLength() takes a geography object and returns the length of the given geography in meters.

SELECT
    st_length(geom :: GEOGRAPHY) / 1000 AS km
FROM
    bookstore_routes
WHERE
    end_store_id = (
        SELECT id FROM bookstores WHERE name = 'Mysteries On Main Street'
    )
    AND start_store_id = (
        SELECT id FROM bookstores WHERE name = 'The Book Nook (Saranac Lake, NY)'
    );
          km
----------------------
  213.48808505371238
(1 row)

We can pull the route too. Paste the GeoJSON output into http://geojson.io to view the route on the map.

SELECT
    ST_AsGeoJSON(geom)
FROM
    bookstore_routes
WHERE
    end_store_id = (
        SELECT id FROM bookstores WHERE name = 'Mysteries On Main Street'
    )
    AND start_store_id = (
        SELECT id FROM bookstores WHERE name = 'The Book Nook (Saranac Lake, NY)'
    );
{"type":"MultiLineString","coordinates":[[[-74.152265,44.317412001],[-74.150683244,44.320361245],[-74.149541,44.322491001]],[[-74.357329,44.244378001],[-74.356093,44.243859001],[-74.354178,44.242898001],[-74.348143,44.239648001],[-74.343626,44.237058001],[-74.342321,44.236058001],[-74.341749001,44.235410001],[-74.33975,44.232579001],[-74.339208,44.231977001],[-74.338667001,44.231599001],[-74.337461,44.231248001],[-74.326169,44.228478001],[-74.324681,44.228200001],[-74.322827,44.228066001],[-74.319936001,44.228040001],[-74.318920999,44.228200001],[-74.316251,44.228909001],[-74.315228,44.229337001],[-74.313824,44.230576001],[-74.310864,44.234299001],[-74.308766,44.236287001],[-74.30769,44.237137001],[-74.306668,44.237778001],[-74.305104,44.238369001],[-74.300305,44.239258001],[-74.298489,44.239849001],[-74.296765,44.240559001],[-74.293965,44.241978001],[-74.285755,44.246469001],[-74.284199,44.246998001],[-74.283496,44.247158001],[-74.278659999,44.246807001],[-74.277065,44.246487001],[-74.27103,44.244926001],[-74.269977,44.244766001],[-74.268862,44.244926001],[-74.267528001,44.245315001],[-74.264667,44.246425001],[-74.263103,44.246887001],[-74.262439,44.246956001],[-74.261516,44.246887001],[-74.258806999,44.246215001],[-74.258105,44.246128001],[-74.256106,44.246376001],[-74.249583,44.248748001],[-74.242563999,44.250486001],[-74.240374,44.251056001],[-74.237955,44.251956001],[-74.236117,44.252757001],[-74.234713,44.253264001],[-74.233477,44.253375001],[-74.232264001,44.253214001],[-74.230066,44.252714001],[-74.228067,44.252554001],[-74.224855,44.252695001],[-74.222374999,44.253027001],[-74.220468,44.253485001],[-74.219284999,44.253916001],[-74.218202,44.254465001],[-74.217285999,44.255606001],[-74.216554001,44.256914001],[-74.216272,44.258444001],[-74.216172,44.260206001],[-74.215837,44.261663001],[-74.215417,44.262537001],[-74.215105,44.262884001],[-74.210526,44.266176001],[-74.209443,44.267164001],[-74.205635,44.272016001],[-74.204712,44.272855001],[-74.203781,44.273633001],[-74.20137,44.275014001],[-74.199875,44.276155001],[-74.189735,44.286454001],[-74.1883,44.287625001],[-74.187415,44.288033001],[-74.186333,44.288353001],[-74.184364869,44.288747417],[-74.184364734,44.288747444],[-74.180854001,44.289451001],[-74.178374,44.290524001],[-74.177191,44.291213001],[-74.176085,44.292084001],[-74.175354,44.292725001],[-74.174521,44.293915001],[-74.173979,44.295353001],[-74.173468,44.297363001],[-74.172934001,44.298374001],[-74.166349,44.306545001],[-74.165144,44.308003001],[-74.160711,44.311824001],[-74.159916999,44.312461001],[-74.157789,44.313514001],[-74.154476999,44.315021001],[-74.153623,44.315642001],[-74.152265,44.317412001]],[[-74.464373,44.224200001],[-74.462122,44.224250001],[-74.461046,44.224318001],[-74.455468999,44.22478],[-74.442636406,44.225904612],[-74.437326,44.226370001],[-74.436273,44.226599001],[-74.416718001,44.232618001],[-74.398811,44.238371001],[-74.396683,44.238729001],[-74.390892,44.239401001],[-74.386916999,44.240198001],[-74.376418001,44.242708001],[-74.37461,44.243078001],[-74.369964,44.243669001],[-74.358573,44.244409001],[-74.357329,44.244378001]],[[-74.538494,44.124160001],[-74.537784999,44.125049001],[-74.534733,44.128341001],[-74.533054,44.129662001],[-74.531116,44.130992001],[-74.528957,44.132541001],[-74.527345325,44.134460927],[-74.527338703,44.134468817],[-74.527332393,44.134476334],[-74.525867,44.136222001],[-74.525164999,44.137359001],[-74.524524,44.138992001],[-74.524012999,44.140750001],[-74.522853,44.151859001],[-74.522876,44.154721001],[-74.523166,44.156341001],[-74.523501999,44.157512001],[-74.523822,44.158702001],[-74.523914,44.160320001],[-74.523753999,44.161079001],[-74.523371,44.161991001],[-74.521656,44.164352001],[-74.518795,44.167732001],[-74.517734,44.168800001],[-74.515415,44.170791001],[-74.512392,44.173229001],[-74.511211,44.174079001],[-74.507396,44.176181001],[-74.500621,44.180629001],[-74.492266,44.190040001],[-74.487185,44.193339001],[-74.485827,44.194141001],[-74.480456,44.196220001],[-74.478991,44.196551001],[-74.474985,44.197211001],[-74.472384001,44.197902001],[-74.471864933,44.198667258],[-74.471781,44.198791001],[-74.471609775,44.199419986],[-74.47160767,44.199427717],[-74.471357398,44.200347074],[-74.471238999,44.200782001],[-74.470742999,44.204081001],[-74.470324,44.205100001],[-74.470011,44.205630001],[-74.468932391,44.207118271],[-74.468927664,44.207124794],[-74.467852,44.208609001],[-74.464525,44.213050001],[-74.462816,44.215560001],[-74.462626,44.216022001],[-74.462687,44.217509001],[-74.46288977,44.21846686],[-74.46306,44.219271001],[-74.463861,44.220321001],[-74.464914999,44.221049001],[-74.465776999,44.221599001],[-74.466311,44.222030001],[-74.466249999,44.222491001],[-74.465655,44.223059001],[-74.464373,44.224200001]],[[-74.529117,44.099819001],[-74.531985,44.102500001],[-74.532741,44.103572001],[-74.533183,44.104492001],[-74.533435,44.106109001],[-74.533527,44.108600001],[-74.534061,44.111190001],[-74.534503,44.112152001],[-74.535045,44.113109001],[-74.536502999,44.115379001],[-74.537357,44.116381001],[-74.537456,44.116455001]],[[-74.472935039,44.000000001],[-74.479534023,44.002542684],[-74.479984937,44.002716429],[-74.480005378,44.002724305],[-74.480329,44.002849001],[-74.48677,44.005149001],[-74.49295,44.007480001],[-74.496628,44.009689001],[-74.498024,44.010719001],[-74.499611,44.012371001],[-74.501511,44.014541001],[-74.503151,44.016508001],[-74.508523,44.023811001],[-74.511529,44.027950001],[-74.514778999,44.032821001],[-74.515222,44.034469001],[-74.515473999,44.036991001],[-74.516015,44.039112001],[-74.517175,44.041202001],[-74.517816,44.042251001],[-74.519449,44.044540001],[-74.520181,44.045272001],[-74.521486,44.046760001],[-74.52189,44.047332001],[-74.522234,44.048221],[-74.522074,44.052341001],[-74.521654,44.055591001],[-74.520983,44.059932001],[-74.520051,44.065921001],[-74.519023544,44.072237853],[-74.519022043,44.072247084],[-74.518511,44.075389001],[-74.518381,44.076869001],[-74.518374,44.078979001],[-74.518503,44.079730001],[-74.518976,44.081382001],[-74.519572001,44.082641001],[-74.52122,44.085311001],[-74.525523,44.093051001],[-74.52682,44.095809001],[-74.528056,44.098220001],[-74.5291102,44.099808753],[-74.529115821,44.099817225],[-74.529117,44.099819001]],[[-74.419277,43.968522001],[-74.420169,43.969804001],[-74.420413,43.970281001],[-74.420604,43.971353001],[-74.420643889,43.971779185],[-74.420644773,43.971788634],[-74.42081,43.973554001],[-74.421245,43.974141001],[-74.421848,43.974301001],[-74.426426993,43.974695925],[-74.42644422,43.974697411],[-74.427425,43.974782001],[-74.42815,43.975010001],[-74.428618155,43.975309199],[-74.428626193,43.975314337],[-74.429577,43.975922001],[-74.43047,43.976590001],[-74.431927,43.977391001],[-74.435977,43.978982001],[-74.437787,43.979302001],[-74.439526,43.979302001],[-74.443196,43.979050001],[-74.444340001,43.979092001],[-74.445003999,43.979191001],[-74.446484,43.979640001],[-74.449117,43.980812001],[-74.451276,43.981953001],[-74.453779,43.983780001],[-74.456640001,43.986951001],[-74.460989,43.992531001],[-74.461897,43.993790001],[-74.4634,43.995430001],[-74.464407001,43.996460001],[-74.465362,43.997082001],[-74.472935039,44.000000001]],[[-74.430422635,43.855487245],[-74.430823844,43.859778886],[-74.432091,43.864603001],[-74.430741,43.872534001],[-74.430741,43.873312001],[-74.431092,43.874205001],[-74.431824999,43.875052001],[-74.432267,43.875433001],[-74.433274,43.876513001],[-74.433854,43.877634001],[-74.433946,43.878454001],[-74.433725001,43.879091001],[-74.432962,43.880034001],[-74.431573,43.881113001],[-74.427842,43.882784001],[-74.424844,43.884363001],[-74.424027,43.884882001],[-74.418244,43.889235],[-74.417732,43.889895001],[-74.417481,43.890444001],[-74.417428,43.891023001],[-74.417481,43.891981001],[-74.417992999,43.893305001],[-74.418686999,43.894175001],[-74.419221,43.894613001],[-74.420586,43.895502001],[-74.422838,43.896364001],[-74.424661,43.896803001],[-74.428651,43.896982001],[-74.434976,43.898191001],[-74.435762,43.898394001],[-74.436464,43.898992001],[-74.436815,43.899541001],[-74.437037001,43.900682001],[-74.437006,43.902284001],[-74.436844816,43.902957433],[-74.436815,43.903082001],[-74.436568249,43.903468348],[-74.436564,43.903475001],[-74.435687001,43.905462001],[-74.435648,43.906812001],[-74.435877,43.907381001],[-74.436884,43.908254001],[-74.437456,43.908434001],[-74.439768,43.909033001],[-74.440714,43.909444001],[-74.442675,43.910814001],[-74.443247,43.911241001],[-74.443949,43.912252001],[-74.444194,43.912843001],[-74.444163,43.913831001],[-74.443477,43.917234001],[-74.443286,43.917814001],[-74.442683,43.918993001],[-74.442408,43.919753002],[-74.441707,43.924302001],[-74.442027,43.925031001],[-74.44321,43.926824001],[-74.444118,43.927891001],[-74.444727999,43.928422001],[-74.455486001,43.936163001],[-74.457503769,43.936996535],[-74.457628577,43.938124354],[-74.456197485,43.939437358],[-74.452444415,43.94344539],[-74.450565344,43.945532689],[-74.449504442,43.946317113],[-74.446375524,43.948497454],[-74.446308501,43.948545699],[-74.4417465,43.951936699],[-74.441713582,43.95196156],[-74.441577106,43.952073562],[-74.44144825,43.95219425],[-74.441440603,43.952201926],[-74.440944602,43.952701927],[-74.440831562,43.952823108],[-74.440719559,43.952959582],[-74.440616724,43.953103091],[-74.440523492,43.953253017],[-74.440440267,43.95340872],[-74.440417621,43.953455787],[-74.440279357,43.953750403],[-74.439810963,43.954070359],[-74.438161986,43.954733199],[-74.435710574,43.955480195],[-74.435629767,43.955506216],[-74.435464532,43.955568406],[-74.435303719,43.955641268],[-74.435303325,43.955641463],[-74.434326325,43.956123464],[-74.434253446,43.956160804],[-74.429912445,43.958468803],[-74.429830017,43.958514493],[-74.429792382,43.958536629],[-74.428869382,43.95908963],[-74.428757089,43.959160725],[-74.428613582,43.959263561],[-74.428602976,43.959271742],[-74.425443975,43.961720742],[-74.425061746,43.963823434],[-74.423999,43.966344001],[-74.419277,43.968522001]],[[-74.430422635,43.855487245],[-74.422981,43.853304001],[-74.422035,43.852503001],[-74.421463,43.851863001],[-74.42086,43.850794001],[-74.420173,43.849055001],[-74.417701001,43.847792001],[-74.416725,43.847434001],[-74.411512999,43.845713001],[-74.410461,43.845374001],[-74.405379,43.845622001],[-74.404302999,43.845653001],[-74.402564,43.845443001],[-74.391691,43.843593001],[-74.389043999,43.842933001],[-74.386389,43.842044001],[-74.383202099,43.84067843],[-74.383194658,43.840675242],[-74.383008908,43.840595648],[-74.380788,43.839644001],[-74.378271,43.838885001],[-74.370183,43.837283001],[-74.369199,43.836986001],[-74.367238,43.835895001],[-74.366452,43.835223001],[-74.362378,43.829894001],[-74.361927,43.829215001],[-74.360920001,43.826236001],[-74.360073,43.825275001],[-74.359158,43.824615001],[-74.356823,43.823444001],[-74.351642,43.821704001],[-74.350788,43.821453001],[-74.345065,43.820084001],[-74.339946,43.819373001],[-74.338977001,43.819164001],[-74.33768,43.818595001],[-74.336580999,43.817832001],[-74.334681,43.816055001],[-74.333987,43.815483001],[-74.33301,43.815112001],[-74.332346,43.815025001],[-74.328997,43.815135001],[-74.328265,43.815044001],[-74.32606,43.814525001],[-74.324885,43.814014001],[-74.323565,43.813075001],[-74.317789,43.807224001],[-74.316904,43.805984001],[-74.315865999,43.804916001],[-74.314164,43.803356001],[-74.312616,43.802234001],[-74.309617,43.800743001],[-74.304787,43.798774001],[-74.303597,43.798156002],[-74.302544,43.797374001],[-74.302017,43.796764001],[-74.301766,43.795703001],[-74.301293,43.789993001],[-74.301239,43.788345001],[-74.30156,43.787366001],[-74.301964,43.786903001],[-74.303009,43.785984001],[-74.303856,43.785053001],[-74.303766,43.784523001],[-74.303169,43.783584001],[-74.30237657,43.782755241],[-74.302368102,43.782746385],[-74.301773,43.782124001],[-74.300392,43.781143001],[-74.299507001,43.780723001],[-74.298248001,43.780403001],[-74.296165,43.780174001],[-74.294173999,43.780174001],[-74.293197,43.780403001],[-74.289786,43.781475001],[-74.283652001,43.782913001],[-74.281074,43.783226001],[-74.276053,43.783065001],[-74.266203,43.782344001],[-74.265295,43.782203001]],[[-74.363938,43.502013001],[-74.366326,43.504158001],[-74.367432,43.504927001],[-74.368592001,43.505598001],[-74.3695,43.506236001],[-74.369966,43.506716001],[-74.371263,43.508746001],[-74.371728,43.510188002],[-74.371759,43.510878001],[-74.371072,43.513346001],[-74.371126,43.514128001],[-74.371263001,43.514609001],[-74.371606001,43.515086001],[-74.372988,43.516226001],[-74.37459,43.516986001],[-74.377199,43.518266001],[-74.385432,43.522406001],[-74.386088,43.523017001],[-74.386408999,43.523497001],[-74.386691,43.524646001],[-74.386532553,43.526017531],[-74.38653144,43.526027172],[-74.386442444,43.526797514],[-74.386409,43.527087001],[-74.385913,43.528948001],[-74.385119,43.531458001],[-74.383929,43.534228001],[-74.383212,43.535826001],[-74.383021,43.537089001],[-74.382983,43.538138001],[-74.383334,43.538897001],[-74.384273,43.540125001],[-74.385593,43.541586001],[-74.390468001,43.545298001],[-74.391071,43.546008002],[-74.391918,43.547678001],[-74.395001,43.555265001],[-74.395131,43.556048001],[-74.395283,43.557879001],[-74.395321,43.561217001],[-74.395543,43.562746001],[-74.395909,43.563776],[-74.396512,43.564509001],[-74.397519,43.565466001],[-74.398803582,43.566517366],[-74.398814559,43.56652635],[-74.399221,43.566859001],[-74.399824,43.567705001],[-74.399944999,43.568259001],[-74.399945,43.569647001],[-74.399221,43.572188001],[-74.39919,43.573626001],[-74.399662,43.574797001],[-74.40064,43.575918001],[-74.404486,43.579416001],[-74.405202999,43.580538001],[-74.405584,43.581227001],[-74.405916539,43.5819675],[-74.405920409,43.581976118],[-74.406069135,43.582307303],[-74.407255,43.584948001],[-74.407721,43.586386001],[-74.408263,43.588358001],[-74.408606,43.591215001],[-74.408484,43.592638001],[-74.408454,43.594439001],[-74.408896,43.595877001],[-74.409934,43.596907001],[-74.410712,43.597319001],[-74.414336,43.598826001],[-74.418052,43.600195001],[-74.418937,43.600676001],[-74.419784,43.601568001],[-74.420166,43.602099001],[-74.420356,43.602716001],[-74.420326,43.603445001],[-74.419976,43.604178001],[-74.417839,43.607267001],[-74.416397,43.610147001],[-74.414604,43.614607001],[-74.414423322,43.616825244],[-74.412448675,43.618905862],[-74.40718547,43.621568425],[-74.402912985,43.623921388],[-74.397525939,43.62776043],[-74.395234896,43.628936913],[-74.392262735,43.632218675],[-74.39075766,43.634708852],[-74.389909772,43.637358042],[-74.388159464,43.640096794],[-74.387494889,43.644231168],[-74.387252,43.646085001],[-74.387122,43.646905001],[-74.387222,43.647615001],[-74.387664,43.648465001],[-74.388618,43.649698001],[-74.388953999,43.650544001],[-74.389282339,43.651568593],[-74.389285046,43.651577041],[-74.389527445,43.652333453],[-74.389847852,43.655810221],[-74.388573718,43.658372116],[-74.385712295,43.660061454],[-74.378887271,43.663353982],[-74.375864153,43.663837969],[-74.373971827,43.663959237],[-74.371619282,43.665055508],[-74.369785751,43.66516015],[-74.365134387,43.665658299],[-74.363288,43.666715001],[-74.362213,43.667745001],[-74.360854,43.669385001],[-74.360518,43.669934001],[-74.360167,43.670827001],[-74.356002,43.676476001],[-74.349882999,43.683015001],[-74.344527,43.687794001],[-74.343077,43.689374001],[-74.342131,43.691105001],[-74.340582,43.694836001],[-74.339514,43.696484],[-74.335066,43.700436001],[-74.334242,43.701874001],[-74.333174,43.704007001],[-74.331496,43.707844001],[-74.330802,43.709084001],[-74.330076,43.709927001],[-74.329352001,43.710366001],[-74.328215,43.710705001],[-74.324652001,43.710957001],[-74.320875,43.711563001],[-74.319922,43.711865001],[-74.319266,43.712277001],[-74.313734,43.718174001],[-74.313069,43.719135001],[-74.312566999,43.720524001],[-74.311713,43.722103001],[-74.309912,43.724556001],[-74.302595001,43.732204001],[-74.299216,43.735523001],[-74.297856999,43.736393001],[-74.294798006,43.740837095],[-74.294792616,43.740844925],[-74.292921,43.743564001],[-74.290266,43.747505001],[-74.289922999,43.747887001],[-74.287932,43.748733001],[-74.287207,43.749325001],[-74.286703,43.750084001],[-74.285567,43.752563001],[-74.285345,43.753802001],[-74.284903,43.754875001],[-74.283926,43.756206001],[-74.282431,43.757225001],[-74.278173999,43.761955001],[-74.276846,43.763714001],[-74.27561,43.764866001],[-74.274252,43.765823001],[-74.270308,43.768245001],[-74.265844,43.770633001],[-74.264074,43.773136001],[-74.263722,43.773906001],[-74.263662,43.775093001],[-74.263884,43.776195001],[-74.264570001,43.777404001],[-74.264853,43.778395001],[-74.265265,43.781635001],[-74.265295,43.782203001]],[[-74.538405,43.399411001],[-74.534987,43.400719001],[-74.533636,43.401360001],[-74.531745,43.402501001],[-74.530805999,43.403229001],[-74.529921,43.404080001],[-74.527311,43.407731001],[-74.526495,43.409058001],[-74.524985001,43.412920001],[-74.524451,43.413998001],[-74.523793,43.414979001],[-74.523108,43.415730001],[-74.522154001,43.416398001],[-74.521093999,43.417008001],[-74.518043001,43.418500001],[-74.513304,43.420670001],[-74.508344,43.422768001],[-74.507361,43.423131001],[-74.499571001,43.426739001],[-74.497915,43.427628001],[-74.495504,43.429299001],[-74.488104,43.434572002],[-74.486913001,43.435559001],[-74.483991,43.437459001],[-74.480543,43.439400001],[-74.476689,43.440937001],[-74.474523,43.441449001],[-74.473745,43.441516001],[-74.472646,43.441288001],[-74.47054,43.440808001],[-74.468564,43.440540001],[-74.467183,43.440702001],[-74.465771,43.441201001],[-74.457173,43.447567001],[-74.453511,43.450928001],[-74.452411999,43.452049001],[-74.451405,43.452919001],[-74.445484001,43.457390001],[-74.440525,43.460407001],[-74.43845,43.461510001],[-74.435283,43.462418001],[-74.432674,43.463798001],[-74.430072,43.466109001],[-74.428562001,43.466999001],[-74.423259001,43.469658001],[-74.421505,43.470231001],[-74.420529,43.470428001],[-74.414973,43.471008001],[-74.412081,43.470958001],[-74.411082001,43.470890001],[-74.408251,43.470256001],[-74.407214,43.470119001],[-74.406328,43.470231001],[-74.405237,43.470639001],[-74.404421,43.471187001],[-74.403751968,43.471760018],[-74.40374812,43.471763313],[-74.402247,43.473049001],[-74.398798,43.475128001],[-74.397257,43.475996001],[-74.395281,43.476959001],[-74.394808,43.477138001],[-74.39409,43.477649001],[-74.392458,43.479358001],[-74.392168001,43.479747001],[-74.389879,43.481849001],[-74.388879,43.482417001],[-74.388063,43.482768001],[-74.384286001,43.483890001],[-74.38231,43.484687001],[-74.379548,43.485988001],[-74.378007,43.487247001],[-74.37459,43.490497001],[-74.371728001,43.493628001],[-74.368516,43.497519001],[-74.368081,43.498088001],[-74.366921,43.499526001],[-74.363938,43.502013001]],[[-74.517516,43.229490001],[-74.517511546,43.229491206],[-74.51715,43.229589001],[-74.516121,43.230180001],[-74.515517999,43.231168001],[-74.515166985,43.234115798],[-74.516126976,43.235651784],[-74.516352909,43.23601328],[-74.516358236,43.236021803],[-74.516627882,43.236453236],[-74.517407028,43.237621954],[-74.517309635,43.23869328],[-74.516725275,43.241225503],[-74.516335703,43.242783794],[-74.516451181,43.24314947],[-74.516596508,43.243609679],[-74.516599124,43.243617961],[-74.517504421,43.246484736],[-74.517504421,43.249114353],[-74.517789825,43.250826773],[-74.517791285,43.250835533],[-74.517991388,43.25203615],[-74.517699208,43.253497048],[-74.517991387,43.25447098],[-74.519257499,43.255152732],[-74.522958442,43.255931877],[-74.528899427,43.255931877],[-74.534353447,43.255055339],[-74.534409397,43.255065212],[-74.534613985,43.255101316],[-74.534616201,43.255101707],[-74.536009132,43.255347518],[-74.539125714,43.256224057],[-74.540781399,43.258464101],[-74.541755331,43.259340641],[-74.543216229,43.260119786],[-74.544190161,43.261483291],[-74.544287555,43.263236368],[-74.545346767,43.265596244],[-74.547662904,43.26791238],[-74.54885406,43.269831465],[-74.549383463,43.271419675],[-74.550640795,43.272809358],[-74.551104022,43.274265215],[-74.552295179,43.275654897],[-74.553486335,43.276846053],[-74.553817212,43.277706333],[-74.55342016,43.278831314],[-74.552824581,43.280088646],[-74.553023108,43.281015101],[-74.553684861,43.282338608],[-74.553817212,43.283926816],[-74.553883387,43.286242954],[-74.553618685,43.287764988],[-74.553287809,43.289353196],[-74.553221634,43.291272281],[-74.553817213,43.293654593],[-74.556202148,43.296330374],[-74.55620838,43.296337366],[-74.556530402,43.296698659],[-74.557439202,43.297789221],[-74.557853909,43.298286869],[-74.561625903,43.299875077],[-74.563942041,43.300603006],[-74.565265548,43.301198584],[-74.567250809,43.303316195],[-74.566593,43.306008001],[-74.565959,43.306329001],[-74.565021001,43.306668001],[-74.564342,43.306809001],[-74.562518,43.306870001],[-74.561672,43.307118001],[-74.560832,43.307580001],[-74.56026,43.308179001],[-74.559603999,43.309251001],[-74.559513,43.310868001],[-74.557223999,43.314487001],[-74.556812,43.314969001],[-74.556179,43.315419001],[-74.551799,43.317689001],[-74.550791999,43.318028001],[-74.550205,43.318139001],[-74.54932,43.318120001],[-74.548602,43.317998001],[-74.546553305,43.317435031],[-74.546540117,43.317431407],[-74.546535,43.317430001],[-74.545314,43.317448001],[-74.543769359,43.317982042],[-74.54346,43.318089001],[-74.541895334,43.319480577],[-74.541874268,43.319499312],[-74.541227786,43.320074278],[-74.537982,43.322961001],[-74.536966999,43.324059001],[-74.534404,43.326890001],[-74.534053,43.327348001],[-74.534023,43.328469001],[-74.534145,43.329949001],[-74.53445,43.331300001],[-74.534633,43.335969001],[-74.534572,43.336610001],[-74.533748,43.339700001],[-74.532902,43.341908001],[-74.532711,43.342562001],[-74.532711,43.344109001],[-74.533154001,43.347749001],[-74.533329,43.348180001],[-74.534245,43.348569001],[-74.535931,43.348920001],[-74.539784,43.352101001],[-74.540059001,43.352578001],[-74.5425,43.359578001],[-74.542431,43.360329001],[-74.544652,43.365231001],[-74.545285,43.366009001],[-74.546719999,43.368889001],[-74.546911,43.369328],[-74.546941,43.370099001],[-74.546910434,43.37081979],[-74.546910043,43.370828991],[-74.546743,43.374768001],[-74.54523859,43.380839868],[-74.545236318,43.380849039],[-74.544607,43.383389001],[-74.544165,43.384350001],[-74.543592,43.385129001],[-74.543226,43.386269001],[-74.543211,43.387047001],[-74.543211,43.393700001],[-74.543363,43.395100001],[-74.543692001,43.395955001]],[[-74.523337,43.190378001],[-74.523589,43.190599001],[-74.524406,43.191679001],[-74.524398,43.193460001],[-74.526046,43.199522001],[-74.526756,43.201952001],[-74.526946,43.202500001],[-74.527358,43.203001001],[-74.528816,43.204241001],[-74.529228,43.204851001],[-74.530654,43.209131001],[-74.530807,43.211530001],[-74.531021,43.219041001],[-74.53099,43.219652001],[-74.530456,43.220411001],[-74.530075,43.220682001],[-74.529297,43.220998001],[-74.527389,43.221368001],[-74.526168,43.222299],[-74.52523,43.223351001],[-74.524131,43.225301],[-74.523285,43.226121001],[-74.520644999,43.228219001],[-74.519776,43.228719001],[-74.518394,43.229248001],[-74.517552345,43.229479983],[-74.517516,43.229490001]],[[-74.489522,43.144732001],[-74.487653,43.146842001],[-74.486974,43.147891001],[-74.486386,43.149222001],[-74.486196,43.149931001],[-74.486257,43.151370001],[-74.486982,43.157683001],[-74.487302,43.158499001],[-74.487553068,43.15885108],[-74.487558704,43.158858983],[-74.487645,43.158980001],[-74.488584,43.159922001],[-74.488995999,43.160261001],[-74.492902,43.163321001],[-74.493688,43.163782001],[-74.494749,43.164259001],[-74.498129,43.165240001],[-74.499593,43.166041002],[-74.506094,43.169752001],[-74.50688,43.170550001],[-74.507994,43.172289001],[-74.508909,43.172949001],[-74.509619,43.173319001],[-74.511809,43.174372001],[-74.512953,43.174563001],[-74.514395,43.174440001],[-74.516836999,43.174101001],[-74.517744999,43.174101001],[-74.522367999,43.174429001],[-74.525397,43.174822001],[-74.526427,43.175142001],[-74.527365999,43.175741001],[-74.527617001,43.176222001],[-74.527709,43.177180001],[-74.526206,43.180349001],[-74.524421,43.182619001],[-74.523757,43.183832001],[-74.523505,43.184771001],[-74.523482798,43.184871668],[-74.523481108,43.184879335],[-74.523350626,43.185470982],[-74.522689,43.188471001],[-74.522567,43.189432001],[-74.522849,43.189939001],[-74.523337,43.190378001]],[[-74.481137,43.137126001],[-74.477955,43.136122001],[-74.474796,43.133918001],[-74.473491999,43.132907001],[-74.469212,43.127990001],[-74.467541,43.125544001],[-74.462276001,43.121722001],[-74.461239002,43.120872001],[-74.451899999,43.111972001],[-74.44482,43.104675001],[-74.442248,43.100520001],[-74.441287,43.099738001],[-74.438442511,43.098239949],[-74.43842793,43.098232271],[-74.433276,43.095519001],[-74.427227,43.092842001],[-74.424792,43.092453001],[-74.423205,43.091941001],[-74.422495,43.091514001],[-74.421168,43.090263001],[-74.420733,43.089435001],[-74.420069,43.087520001],[-74.419657,43.084262001],[-74.418360001,43.081066001],[-74.416842,43.078594001],[-74.416178,43.077903001],[-74.409875999,43.074226001],[-74.402719,43.070606001],[-74.401857,43.070297001],[-74.396333,43.069805001],[-74.389688,43.068142001],[-74.388277001,43.067131001],[-74.383843,43.061993001],[-74.382844,43.060459001],[-74.381737,43.057114001],[-74.380936,43.055908001],[-74.37941,43.054917001],[-74.374505,43.053871001],[-74.373430143,43.05371745],[-74.372559,43.053593001],[-74.367921,43.052548001],[-74.366035999,43.051289001]],[[-74.366035999,43.051289001],[-74.365227,43.050747001],[-74.3619,43.050244001],[-74.360909,43.050106001],[-74.359956,43.050152001],[-74.354088001,43.051007001],[-74.352554,43.051045001],[-74.351057999,43.050888001],[-74.348739,43.050381001],[-74.346245,43.050488001]],[[-74.352012,43.027703001],[-74.350357,43.028802001],[-74.34217,43.035565001],[-74.335830001,43.039841001]],[[-74.360901,43.013665001],[-74.358557,43.013592001],[-74.357467,43.013772001],[-74.356567,43.014214001],[-74.353729,43.016545001],[-74.351463001,43.017712001]],[[-74.385208,43.015484001],[-74.384799414,43.015297285],[-74.374367565,43.010530139],[-74.374315078,43.009100739],[-74.374314756,43.009091976],[-74.374214,43.006348001]]]}

route

Lab 6 - Spatial Performance Tuning

What are the top 10 roads nearest to a Loon sighting location in NY? A Spatial Join can help us answer this question.

  1. Build a CTE called loon_habitat that collects all of the Common Loon sightings into a single geometry.

  2. Build a CTE called nearby_roads that joins the results of loon_habitat with the roads table and pulls out the roads in NY state that are within a degree (about 60 nautical miles), then order the roads returned by their distance from a loon sighting.

  3. Finally, query the results of the nearby_roads subquery to get a list of 10 distinct road names.

The query below can also be written using an explicit ST_DWithin() function, which is an index-accelerated function. CockroachDB optimizes ST_Distance() to use ST_DWithin(), see the Query Plan for details.

As the data in the roads table has an SRID of 0, we need to use ST_SetSRID() to cast it to SRID 4326. This step is necessary because ST_Distance cannot operate on geometries with differing SRIDs.

Let's update the SRID of the roads.geom column to SRID 4326.

UPDATE
    roads
SET
    geom = ST_Transform(ST_SetSRID(geom, 4326), 4326)
WHERE
    gid IS NOT NULL RETURNING NOTHING;

Now run the query

WITH loon_habitat AS (
    SELECT
        ST_Collect(routes.geom) AS geom
    FROM
        birds
        JOIN observations ON birds.id = observations.bird_id
        JOIN routes ON observations.route_id = routes.id
    WHERE
        birds.name = 'Common Loon'
),
nearby_roads AS (
    SELECT
        roads.prime_name AS road_name
    FROM
        roads
        JOIN loon_habitat ON ST_Distance(
            loon_habitat.geom,roads.geom
        ) < 1
    ORDER BY
        ST_Distance(
            loon_habitat.geom,roads.geom
        ) ASC
    LIMIT
        20
)
SELECT
    DISTINCT road_name
FROM
    nearby_roads
LIMIT
    10;
       road_name
-----------------------
  US Route 9
  State Route 30
  State Route 22 Spur
  State Route 22
  State Route 28
  State Route 86
  State Route 28N
  Interstate 87
  US Route 11
  State Route 421
(10 rows)

Time: 1.930s total (execution 1.930s / network 0.000s)

Great, we have our list of roads!

Lab 7 - Using Spatial Indexes

The previous query can be enhanced by use of Spatial Indexes. Let's create a spatial index on the road.geom column.

Create the index

CREATE INDEX ON roads USING GIST(geom);

Run the SQL query again, let's see how it performs

WITH loon_habitat AS (
    SELECT
        ST_Collect(routes.geom) AS geom
    FROM
        birds
        JOIN observations ON birds.id = observations.bird_id
        JOIN routes ON observations.route_id = routes.id
    WHERE
        birds.name = 'Common Loon'
),
nearby_roads AS (
    SELECT
        roads.prime_name AS road_name
    FROM
        roads
        JOIN loon_habitat ON st_distance(
            loon_habitat.geom,roads.geom
        ) < 1
    ORDER BY
        ST_Distance(
            loon_habitat.geom,roads.geom
        ) ASC
    LIMIT
        20
)
SELECT
    DISTINCT road_name
FROM
    nearby_roads
LIMIT
    10;
       road_name
-----------------------
  US Route 9
  State Route 30
  State Route 22 Spur
  State Route 22
  State Route 28
  State Route 86
  State Route 28N
  Interstate 87
  US Route 11
  State Route 421
(10 rows)

Time: 1.492s total (execution 1.492s / network 0.001s)

Great improvement! Check the query plan using EXPLAIN (VERBOSE) to confirm the optimizer is using the spatial index roads_geom_idx.

                                                 tree                                                 |         field         |                    description                    |                 columns                 | ordering
------------------------------------------------------------------------------------------------------+-----------------------+---------------------------------------------------+-----------------------------------------+------------
                                                                                                      | distribution          | full                                              |                                         |
                                                                                                      | vectorized            | false                                             |                                         |
  limit                                                                                               |                       |                                                   | (road_name)                             |
   │                                                                                                  | estimated row count   | 10                                                |                                         |
   │                                                                                                  | count                 | 10                                                |                                         |
   └── distinct                                                                                       |                       |                                                   | (road_name)                             |
        │                                                                                             | estimated row count   | 20                                                |                                         |
        │                                                                                             | distinct on           | road_name                                         |                                         |
        └── render                                                                                    |                       |                                                   | (road_name)                             |
             │                                                                                        | estimated row count   | 20                                                |                                         |
             │                                                                                        | render 0              | prime_name                                        |                                         |
             └── limit                                                                                |                       |                                                   | (column49, prime_name)                  |
                  │                                                                                   | estimated row count   | 20                                                |                                         |
                  │                                                                                   | count                 | 20                                                |                                         |
                  └── sort                                                                            |                       |                                                   | (column49, prime_name)                  | +column49
                       │                                                                              | estimated row count   | 2258                                              |                                         |
                       │                                                                              | order                 | +column49                                         |                                         |
                       └── render                                                                     |                       |                                                   | (column49, prime_name)                  |
                            │                                                                         | estimated row count   | 2258                                              |                                         |
                            │                                                                         | render 0              | st_distance(geom, geom)                           |                                         |
                            │                                                                         | render 1              | prime_name                                        |                                         |
                            └── project                                                               |                       |                                                   | (prime_name, geom, geom)                |
                                 │                                                                    | estimated row count   | 2258                                              |                                         |
                                 └── lookup join (inner)                                              |                       |                                                   | (gid, geom, prime_name, geom)           |
                                      │                                                               | table                 | roads@primary                                     |                                         |
                                      │                                                               | equality              | (gid) = (gid)                                     |                                         |
                                      │                                                               | equality cols are key |                                                   |                                         |
                                      │                                                               | pred                  | st_dwithinexclusive(geom, geom, 1.0)              |                                         |
                                      └── project                                                     |                       |                                                   | (gid, geom)                             |
                                           │                                                          | estimated row count   | 2258                                              |                                         |
                                           └── inverted join                                          |                       |                                                   | (geom, gid, geom_inverted_key)          |
                                                │                                                     | table                 | roads@roads_geom_idx                              |                                         |
                                                │                                                     | inverted expr         | st_dwithinexclusive(geom, geom_inverted_key, 1.0) |                                         |
                                                └── render                                            |                       |                                                   | (geom)                                  |
                                                     │                                                | estimated row count   | 1                                                 |                                         |
                                                     │                                                | render 0              | st_collect                                        |                                         |
                                                     └── group (scalar)                               |                       |                                                   | (st_collect)                            |
                                                          │                                           | estimated row count   | 1                                                 |                                         |
                                                          │                                           | aggregate 0           | st_collect(geom)                                  |                                         |
                                                          └── project                                 |                       |                                                   | (geom)                                  |
                                                               └── hash join (inner)                  |                       |                                                   | (id, name, route_id, bird_id, id, geom) |
                                                                    │                                 | estimated row count   | 406                                               |                                         |
                                                                    │                                 | equality              | (route_id) = (id)                                 |                                         |
                                                                    │                                 | right cols are key    |                                                   |                                         |
                                                                    ├── project                       |                       |                                                   | (id, name, route_id, bird_id)           |
                                                                    │    │                            | estimated row count   | 406                                               |                                         |
                                                                    │    └── lookup join (inner)      |                       |                                                   | (id, name, id, bird_id, route_id)       |
                                                                    │         │                       | table                 | observations@primary                              |                                         |
                                                                    │         │                       | equality              | (id) = (id)                                       |                                         |
                                                                    │         │                       | equality cols are key |                                                   |                                         |
                                                                    │         └── lookup join (inner) |                       |                                                   | (id, name, id, bird_id)                 |
                                                                    │              │                  | estimated row count   | 406                                               |                                         |
                                                                    │              │                  | table                 | observations@observations_bird_id_idx             |                                         |
                                                                    │              │                  | equality              | (id) = (bird_id)                                  |                                         |
                                                                    │              └── scan           |                       |                                                   | (id, name)                              |
                                                                    │                                 | estimated row count   | 1                                                 |                                         |
                                                                    │                                 | table                 | birds@birds_name_idx                              |                                         |
                                                                    │                                 | spans                 | /"Common Loon"-/"Common Loon"/PrefixEnd           |                                         |
                                                                    └── scan                          |                       |                                                   | (id, geom)                              |
                                                                                                      | estimated row count   | 129                                               |                                         |
                                                                                                      | table                 | routes@primary                                    |                                         |
                                                                                                      | spans                 | FULL SCAN                                         |                                         |
(62 rows)

Final thoughts

Congratulations, you reach the end of the labs! This workshop just scratches the surface of the many capabilities and possibilities offered by the PostGIS library. Check below links for more information, and subscribe to the CockroachDB newsletter to stay up-to-date with the latest development.

Reference

Official Docs

Blogs and Videos