Top Banner
PostGIS on Rails Matt Nemenman [email protected] @quarterdome 1 Friday, April 19,
37

PostGIS on Rails

Dec 05, 2014

Download

Technology

Matt Nemenman

How to use PostgreSQL PostGIS extension in Ruby on Rails environment.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: PostGIS on Rails

PostGIS on Rails

Matt [email protected]

@quarterdome

1Friday, April 19,

Page 2: PostGIS on Rails

About me

Programmer

Love maps

Building map based rental search engine @ Apartment List

2Friday, April 19,

Page 3: PostGIS on Rails

Location Aware Apps

Where am I?

What is around me?

3Friday, April 19,

Page 4: PostGIS on Rails

Where am I?

Latitude and Longitude

HTML5 geolocation or GPS

Address

Geocoding

Reverse geocoding

4Friday, April 19,

Page 5: PostGIS on Rails

Where am I?

What if you need to know ...

Neighborhood

School district

National park

Earthquake safety zone

5Friday, April 19,

Page 6: PostGIS on Rails

What is around me?

Yelp and Google Places API

Restaurants, bars, etc.

Points of interest

6Friday, April 19,

Page 7: PostGIS on Rails

What is around me?

What if you want to know ...

What are three neighborhoods closest to me?

Average rent for 1 bedroom in Lower Pacific Heights

Crime rate on my city block

Who is around me?

7Friday, April 19,

Page 8: PostGIS on Rails

When 3rd party APIs fall short ...

Get your own data set

Build your own solution

8Friday, April 19,

Page 9: PostGIS on Rails

Spatial Systems

MongoDB

Solr

MySQL

Oracle / DB2

PostGIS

9Friday, April 19,

Page 10: PostGIS on Rails

PostGIS

Geospatial extension to Postgres

New datatypes

Functions to work with those datatypes

Spatial indices using GiST

create extension postgis;

10Friday, April 19,

Page 11: PostGIS on Rails

A Simple Example

11Friday, April 19,

Page 12: PostGIS on Rails

A simple example

Yosemite Park Ranger

Tracking bears equipped with GPS transmitters

Want to show all the bears on Google Maps

12Friday, April 19,

Page 13: PostGIS on Rails

Bears (database migration)

create_table :bears do |t| t.column :lat, :float t.column :lon, :floatend

add_index :bears, :latadd_index :bears, :lonadd_index :bears, [:lat, :lon]

13Friday, April 19,

Page 14: PostGIS on Rails

Bears (model)class Bear < ActiveRecord::Base

def self.bbox(sw_lon, sw_lat, ne_lon, ne_lat) self .where( :lon => sw_lon..ne_lon ) .where( :lat => sw_lat..ne_lat )end

end

14Friday, April 19,

Page 15: PostGIS on Rails

A PostGIS example (migration)

create_table :bears do |t| t.column :coordinates, :geometry, :srid => 4326end

add_index :bears, :coordinates, :spatial => true

15Friday, April 19,

Page 16: PostGIS on Rails

A PostGIS example (model)

def self.box(sw_lon, sw_lat, ne_lon, ne_lat)

factory = Rails.application.spatial_factory

sw = factory.point(sw_lon, sw_lat) nw = factory.point(sw_lon, ne_lat) ne = factory.point(ne_lon, ne_lat) se = factory.point(ne_lon, sw_lat)

ring = factory.linear_ring([sw, nw, ne, se]) bbox = factory.polygon(ring)

self .where('ST_Intersects(coordinates, :bbox)', :bbox => bbox)end

16Friday, April 19,

Page 17: PostGIS on Rails

A PostGIS example

1_000_000.times do Bear.create!( ...)

end

17Friday, April 19,

Page 18: PostGIS on Rails

1,000,000 bears

PostGIS is 1.5x to 50x faster

18Friday, April 19,

Page 19: PostGIS on Rails

Active Record PostGIS Adapter

Migration support

Automatic conversion of PostGIS datatypes to Ruby (RGeo) objects and back

gem 'pg'gem 'rgeo'gem 'activerecord-postgis-adapter'

19Friday, April 19,

Page 20: PostGIS on Rails

Rails Migrations

add_column :bears, :coordinates, :geometry, :srid => 4326

add_index :bears, :coordinates, :spatial => true

20Friday, April 19,

Page 21: PostGIS on Rails

Postgres Table

=> \d bears Table "public.bears" Column | Type -------------+----------------------------- id | integer coordinates | geometry(Geometry,4326) Indexes: "pins_pkey" PRIMARY KEY, btree (id) "index_pins_on_coordinates" gist (coordinates)

21Friday, April 19,

Page 22: PostGIS on Rails

PostGIS Data

=> select id, coordinates from bears limit 4; id | coordinates ----+---------------------------------------------------- 1 | 0101000020E61000002A8A632C341F664021805D8DDBEB4BC0 2 | 0101000020E61000004DF900A54A5866C0A2BAB6AC827D50C0 3 | 0101000020E61000002450EA628F5259C01C789C77C2883040 4 | 0101000020E610000038760C7B85443C4013206005DC2C48C0(4 rows)

22Friday, April 19,

Page 23: PostGIS on Rails

RGeo

##> bear=Bear.first => #<Bear id: 1, coordinates: #<RGeo::Geos::CAPIPointImpl:0x3fd52ab501b4 "POINT (176.9751188224921 -55.84263770165877)">>

##> bear.coordinates.x => 176.9751188224921

##> bear.coordinates.y => -55.84263770165877

23Friday, April 19,

Page 24: PostGIS on Rails

More examples# \d parks Column | Type ------------------------+----------------------------- id | integer name | character varying(255) boundary | geometry(Geometry,4326)

Indexes: "parks_pkey" PRIMARY KEY, btree (id) "index_parks_on_name" btree (name) "index_parks_on_boundary" gist (polygon)

# select id, name, boundary from parks limit 2; id | name | boundary --------+-------------+------------------------ 1 | Yosemite |0103000020E6100000010000... 2 | Yellowstone |0103000020E6100000010000...

24Friday, April 19,

Page 25: PostGIS on Rails

How many bears are in Yosemite now?

##> park = Park.find_by_name(‘Yosemite’)

##> bears = Bear.where(‘ST_Intersects(coordinates, :bounds)’, :bounds => park.boundary)

##> bear_count = bears.count

25Friday, April 19,

Page 26: PostGIS on Rails

How Many Bears in Yosemite and Yellowstone

(Ruby)?

##> yosemite = Park.find_by_name(‘Yosemite’)

##> yellowstone = Park.find_by_name(‘Yellowstone’)

##> bounds = yosemite.boundary + yellowstone.boundary

##> bears = Bear.where(‘ST_Intersects(coordinates, :bounds)’, :bounds => bounds)

##> bear_count = bears.count

26Friday, April 19,

Page 27: PostGIS on Rails

How Many Bears in Yosemite and Yellowstone

(SQL)?

select count(*) from bears inner join parks on ST_Intersects(bears.coordinates, parks.boundary) where parks.name in (‘Yosemite’, ‘Yellowstone’);

27Friday, April 19,

Page 28: PostGIS on Rails

Three parks closest to me?

Distance operator (KNN) is a feature of Postgres 9.1 and above

select id, name, boundary <-> ST_Point(37.775, -122.44) as distancefrom parksorder by distancelimit 3;

28Friday, April 19,

Page 29: PostGIS on Rails

What else is possible?

29Friday, April 19,

Page 30: PostGIS on Rails

Geometry Simplification

ST_Simplify

ST_ConvexHull

ST_ConcaveHull

30Friday, April 19,

Page 31: PostGIS on Rails

Spatial Relationships

ST_Centroid

ST_Contained

ST_Area

ST_Perimeter

ST_DWithin

31Friday, April 19,

Page 32: PostGIS on Rails

Format Conversions

ST_AsGeoJSON

ST_AsText

32Friday, April 19,

Page 35: PostGIS on Rails

Data Sources (commercial)

Maponics

http://www.maponics.com/

Urban Mapping

http://www.urbanmapping.com/

Onboard Informatics

http://www.onboardinformatics.com/

35Friday, April 19,

Page 37: PostGIS on Rails

Q & A

We are hiring @apartmentlist!37Friday, April 19,