2009.foss4g.org. Spatial Database Tips & Tricks Paul Ramsey pramsey@opengeo.org.

Post on 26-Mar-2015

238 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

Transcript

2009.foss4g.org

Spatial DatabaseTips & Tricks

Paul Ramseypramsey@opengeo.org

Housekeeping

• Copy workshop from DVD• Download from

http://xx.xx.xx.xx/xxx/spdb-003.zip• Install or not• Ignore me or not• Examples also at

http://xx.xx.xx.xx:8080/spatialdbtips

Impatient People

• They try to install without reading instructions

• When you see an error box during PostGIS install, click “Ignore”

• Remember to create “medford” (not “postgis”) database during PostGIS install

Impatient People

It’s not dead, it’s just resting…It’s not dead, it’s just resting…

Motivation

• Spatial databases are powerful• Godlike, really• You do not need “GIS software”• Your database is “GIS software”• You do not need “spatial

middleware”• See above

Standard Database

• Has data types– varchar– integer– real– date

Spatial Database

• Has spatial data types– point– linestring– polygon– multipoint– multilinestring– multipolygon

Standard Database

• Has one-dimensional indexes– b-tree– hash

Spatial Database

• Has spatial indexes– r-tree– quad-tree– grid

Find intersecting shapes…

Start with all boxes,

find intersecting boxes,

then find intersecting shapes.

Standard Database

• Has functions• Work against standard types

– lower()– round()– substring()– trim()– dayofweek ()

Spatial Database

• Has spatial functions• Work against spatial types

– ST_Area(geometry)– ST_Distance(geometry,geometry)– ST_Intersects(geometry,geometry)– ST_DWithin(geometry,geometry,radiu

s)– ST_Union(geometry,geometry)

Open Geospatial Consortium (OGC)

Simple Features for SQL (SFSQL)

Locator

Spatial

• No buffer operation

• No union operation

• No intersection operation

• No centroid point

• No area or length calculation

L O C A T O R

• Linear referencing system (LRS) support• Spatial analysis and mining functions

and procedures (SDO_SAM package)• Geocoding support (SDO_GCDR

package)• GeoRaster support• Topology data model• Network data model

S P A T I A L

• SFSQL compliant• New release, not as many features• No coordinate reference system

transforms• Windows only• Grid index

SELECT * FROM the_tableWHERE the_geom.STIntersects( geometry::STGeomFromText('POINT(0 0)',0) );

SELECT * FROM the_tableWHERE ST_Intersects( the_geom, ST_GeomFromText('POINT(0 0)',0) );

• PostgreSQL / PostGIS• SFSQL compliant• Open source (GPL)• Proprietary / open source clients• “geographic” coordinates require

care

• ST_Distance(‘POINT(0 0)’,’POINT(1 1)’)

• What units?• ST_Distance_Spheroid()• ST_Distance_Sphere()• Indexes are not sphere aware• Spherical distance functions defined

on points only

Installation

Installation

Installation

Installation

Data

Data

• Shape files– .shp, .shx, .dbf, .prj– shp2pgsql

• Other?– FME– ogr2ogr

Tomcat

• JNDI configuredo PostgreSQL JDBCo Connection to “medford” database

• JSLT installedo <c:> <sql:>

• GeoServer installedo Connections to “medford” tableso Styles for “medford” tables

Tomcat

Workshop

#0 - Base Map with WMS

+

=

+

=

http://localhost:8080/geoserver/

<body onload="init()"> <div id="map"></div></body>

var lon = -122.8450;var lat = 42.3438;var zoom = 18;var map;

function initMap() { map = new OpenLayers.Map( 'map' , {controls:[new OpenLayers.Control.MouseDefaults(), new OpenLayers.Control.LayerSwitcher(), new OpenLayers.Control.PanZoomBar()], numZoomLevels:20});

var gmap = new OpenLayers.Layer.Google( "Google Streets" // the default ); var gsat = new OpenLayers.Layer.Google( "Google Satellite", {type: G_SATELLITE_MAP} ); map.addLayers([gmap, gsat]); map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);}

// Initialize WMS layer from our local // GeoServervar bwms = new OpenLayers.Layer.WMS( "Medford Buildings", "http://localhost:8080/geoserver/wms?", { "transparent":"true", "layers":"medford:buildings", "format":"image/png" }, { "reproject":"true" } );

// Add WMS layer to our mapmap.addLayer(bwms);

#1

– Click to

Q

uery

#1 – Click to Query

// Tie the map click event to our query function map.events.register("click", map, queryDatabase );

function queryDatabase(e) {

// Read the map coordinates from the click event var lonlat = map.getLonLatFromViewPortPx(e.xy);

// Read the table we are going to query from page var table = document.getElementById("table").value;

// Construct the query URL var url = "01-click-query.jsp"; url += "?lon=" + lonlat.lon; url += "&lat=" + lonlat.lat; url += "&table=" + table;

// Load the URL into an iframe document.getElementById("query").src = url;}

01-click-query.jsp?lon=-122.8451943397522&lat=42.344141057680226&table=medford.taxlots

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ page contentType="text/html" %>

<sql:query var="rs" dataSource="jdbc/medford">

. . . . . . .

</sql:query>

01-click-query.jsp

select st_geometrytype(the_geom) as geometrytype, st_area(the_geom) as area, *from ${param.table}where st_contains( the_geom, st_transform( st_setsrid( st_makepoint(${param.lon},${param.lat}), 4326), 2270))

SRID?!?

• Location = Coordinate + SRID• Here = (-121.92, 37.37) + EPSG:4326• ST_Transform() to change SRID• Store data in an efficient SRID• Transform inputs to your storage SRID• Transform outputs to your display SRID

#2

– Click to

A

naly

ze

02-click-analyze.jsp?lon=-122.8451943397522&lat=42.344141057680226&radius=200

select count(*) as "Number of Lots", round(avg(st_area(the_geom))::numeric/43560, 1) || ' acres' as "Average Lot Area", '$' || avg(impvalue)::integer as "Average Improvement Value", '$' || avg(landvalue)::integer as "Average Land Value", '$' || avg(impvalue + landvalue)::integer as "Average Total Value", avg(yearblt)::integer as "Average Year Built"from medford.taxlotswhere st_dwithin( taxlots.the_geom, st_transform( st_setsrid( st_makepoint(${param.lon},${param.lat}), 4326), 2270), ${param.radius} )

• Indexed distance query• ST_Distance(g1,g2) < r

is not indexed• ST_DWithin(g1,g2,r)

is equivalent tog1 && ST_Expand(g2,r) AND ST_Distance(g1,g2) < r

ST_DWithin()?!?

#3

– Click a

nd

Join

zoning taxlots

Everything is related to everything else, but near things are more related than distant things.

- Waldo Tobler

Spatial relationships are a universal key for joining otherwise disparate data.

customer table

census table

road table

stream table

zoning table

taxlot table

select count(*) as num_lots, sum(st_area(taxlot.the_geom)) as total_lot_area, zone.zoning as zoning, sum(taxlot.landvalue) as total_land_value, sum(taxlot.landvalue) / sum(st_area(taxlot.the_geom)) as value_per_ft

from medford.taxlots taxlot join medford.zoning zone on ( st_contains( zone.the_geom, st_centroid(taxlot.the_geom) ) )

where st_dwithin( taxlot.the_geom, st_transform( st_setsrid( st_makepoint( ${param.lon}, ${param.lat}), 4326), 2270), ${param.radius} )group by zone.zoningorder by total_lot_area desc

#4

– Click a

nd

U

nio

n

select st_asgeojson(the_geom)from medford.streetswhere st_npoints(the_geom) < 6limit 1;

ST_AsGeoJSON()

{"type":"MultiLineString", "coordinates":[[ [4289753.869,253537.254], [4290375.489,253518.361] ]]}

GeoJSON Geometry

ST_As*()• Standard

– ST_AsText() – defined by OGC (SFSQL)– ST_AsBinary() – defined by OGC (SFSQL)– ST_AsGML() – defined by OGC (GML)

• PostGIS– ST_AsKML() – defined by Google (OGC)– ST_AsSVG() – defined by W3C– ST_AsGeoJSON() – defined by community

Feature

Feature

Geometry

Geometry Properties

Properties

FeatureC

ollection

<%@ taglib uri="http://java.sun.com/jsp/jstl/sql" prefix="sql" %><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %><%@ page contentType="text/x-json" %>

<sql:query var="rs" dataSource="jdbc/medford">${param.sql}</sql:query>

{"type":"FeatureCollection", "features":[<c:forEach var="row" items="${rs.rows}" varStatus="rowStatus"> {"type":"Feature", "geometry":<c:out value="${row.st_asgeojson}" escapeXml="false" />, "properties":{ <c:forEach var="column" items="${row}" varStatus="columnStatus"> <c:if test="${column.key != 'st_asgeojson'}"> "<c:out value="${column.key}" escapeXml="false" />": "<c:out value="${column.value}" escapeXml="false" />" <c:if test="${! columnStatus.last}">,</c:if> </c:if> </c:forEach>}} <c:if test="${! rowStatus.last}">,</c:if></c:forEach>]}

select st_asgeojson( st_transform(the_geom,900913) )from medford.taxlotswhere st_dwithin( the_geom, st_transform( st_setsrid( st_makepoint(-13676108, 5212594), 900913), 2270), 100 )

// Make a fresh vector layer, pulling features our URLjson_layer = new OpenLayers.Layer.Vector("GeoJSON", { strategies: [new OpenLayers.Strategy.Fixed()], protocol: new OpenLayers.Protocol.HTTP({ url: json_url, format: new OpenLayers.Format.GeoJSON() }) });

// Add our vector layer to the mapmap.addLayer(json_layer);

#5

– Arb

itrary

SQ

L

#6

– Walk a

N

etw

ork

medford.storm_drains

node_fm

node_to

medford.storm_drains

id node_fm node_to

91058

D372W25CN0169

D372W25CN0168

id node_fm node_to

91061

D372W25CN0168

D372W25CN0167

id node_fm node_to

91062

D372W25CN0167

D372W25CN0166

select d.node_fm, d.node_to, d.pipe_idfrom medford.storm_drains d, medford.storm_drains ewhere st_dwithin(d.the_geom, e.the_geom, 5) and e.node_to = 'D371W28CN0134' and e.gid != d.gid and st_distance( st_endpoint(st_geometryn(e.the_geom, 1)), st_startpoint(st_geometryn(d.the_geom, 1)) ) < 5;

e.node_to = 'D371W28CN0134'

ST_DWithin()

ST_DWithin()

e.gid != d.gid

st_distance( st_endpoint(st_geometryn(e.the_geom, 1)), st_startpoint(st_geometryn(d.the_geom, 1)) ) < 5;

st_distance( st_endpoint(st_geometryn(e.the_geom, 1)), st_startpoint(st_geometryn(d.the_geom, 1)) ) < 5;

ST_GeometryN()

• Convert– MULTILINESTRING((0 0, 1 1, 2 2))

• To– LINESTRING(0 0, 1 1, 2 2)

In conclusion…

Standards are good…

SFSQL

GMLGeoJSON

KML WMS

WKT

WKB WFS

Special middleware is unnecessary…

2009.foss4g.org

top related