PostGIS
udvidelsen, der giver PostgreSQL geometri
Hvad det er
PostGIS er en open source-tilføjelse til databaseserveren PostgreSQL, som gør det muligt at gemme en form i en kolonne, for eksempel en adresse, et vandløb eller et matrikelskel, og at spørge med almindelig SQL, hvordan formerne ligger i forhold til hinanden. Det startede som et forskningsprojekt hos Refractions Research, et konsulentfirma inden for GIS og databaser, og udvikles i dag som et selvstændigt open source-projekt.
Udvidelsen installeres i én database ad gangen med CREATE EXTENSION postgis;,
og med den følger tre ting.
- Rumlige typer.
geometrybeskriver former på en flad plan i det koordinatsystem, dataene blev indsamlet i.geographybeskriver dem på jordens krumme overflade og måler i meter. - Rumlige funktioner. En stor familie af funktioner, hvis navne begynder med
ST_:ST_IntersectsogST_Containstil relationer,ST_AreaogST_Lengthtil målinger,ST_Transformtil at flytte data mellem koordinatsystemer ogST_AsGeoJSONtil at levere resultatet til et webkort. - Rumlige indeks. PostGIS bygger et R-træ oven på PostgreSQL’s GiST-ramme og understøtter desuden SP-GiST og blokintervalindeks til særlige slags data.
Formerne følger Simple Features-modellen fra Open Geospatial Consortium, som
også er udgivet som ISO 19125: punkter, linjer og polygoner, deres flerdelte
udgaver og samlinger af blandede typer. Hver værdi bærer et SRID, et tal, der
peger på en række i tabellen spatial_ref_sys og fortæller, hvad koordinaterne
betyder. SRID 4326 står for længde- og breddegrad i grader på WGS 84-datummet,
det system GPS regner i. Et projiceret system måler i stedet i meter mod øst og
nord fra et fast nulpunkt og er kun præcist inden for det område, det er lavet
til.
Rasterdata, topologi og visse 3D-operationer ligger i særskilte udvidelser,
postgis_raster, postgis_topology og postgis_sfcgal, så en database kun
bærer de dele, den rent faktisk bruger.
Hvorfor det betyder noget
PostGIS tvinger et valg frem: Hvor skal de stedbundne data bo? Uden udvidelsen ender koordinaterne gerne i to talkolonner, mens det egentlige rumlige arbejde foregår et andet sted. Det kan være applikationskode, der løber alle rækker igennem for at regne afstande ud, et desktop-GIS, som nogen eksporterer til hver mandag, eller en separat geotjeneste med sin egen kopi af dataene. Kopierne glider fra hinanden. Med PostGIS bliver »hvilke kunder bor inden for to kilometer af et lager, der har varen på hylden« til én forespørgsel, der forbinder lagerstatus, kundedata og former i samme transaktion, under samme backup og samme rettigheder som resten af databasen.
Dermed får de rumlige data også de garantier, resten af skemaet allerede har. En check-constraint kan afvise en ugyldig polygon, før den bliver gemt. Row-level security kan begrænse et regionalt team til matriklerne i dets egen region. En import, der går i stå halvvejs, bliver rullet tilbage i stedet for at efterlade et halvt lag.
Det andet valg står mellem geometry og geography, og PostGIS-manualen siger
det ligeud. Data, der holder sig inden for en by eller et land, gemmes som regel
bedst som geometry i en projektion, der er valgt til netop det område, fordi
hele funktionssættet er til rådighed, og regningen går hurtigt. Data, der
spænder over kontinenter, eller hvor brugerne vil have afstande i meter mellem
vilkårlige punkter på kloden, er lettere at få rigtige som geography. Den type
klarer selv matematikken på den krumme overflade, til gengæld med færre
funktioner.
Somme tider er svaret, at PostGIS er mere, end opgaven kræver. En app, der blot gemmer bredde- og længdegrad for hver butik og sætter nåle på et kort, klarer sig fint med to talkolonner. PostGIS gør sig fortjent til pladsen, når spørgsmålene handler om afstand, indeholdelse eller overlap, eller når dataene rummer linjer og polygoner frem for enkelte punkter.
Sådan ser det ud i praksis
To projekter her på siden viser PostGIS i de to roller, udvidelsen oftest får: som grunden til en migrering og som arbejdshest under en oprydning.
En kortapplikation med rumlige forespørgsler i realtid for mange brugere kørte på en Microsoft SQL Server-database uden indbygget geospatial indeksering, og ventetiden gik ud over både kortet og tjenesterne bag det. Løsningen blev en flytning til PostgreSQL med PostGIS, med et skema designet til rumlige data, GiST- og SP-GiST-indeks på geometri- og geografikolonnerne og constraints på de rumlige koordinater. Over 50 millioner rumlige poster gik gennem ETL-pipelines, der transformerede dem til EPSG:4326 undervejs. Den gennemsnitlige svartid faldt fra 2,5 sekunder til under 250 millisekunder, en forbedring på 10 gange, og CPU-belastningen i backend faldt med 65 %.
Det andet projekt handlede om data frem for fart. Et stort geospatialt analyseprojekt afslørede over 1.000 uoverensstemmelser i geografiske datasæt og tidsseriedatasæt. GDAL, QGIS og ArcGIS blev brugt til at finde og rette de rumlige fejl, mens PostGIS stod for de rumlige forespørgsler og indekseringen, og procedurer i PL/pgSQL transformerede dataene inde i PostgreSQL, før det rensede resultat blev vist i Mapbox. Køretiden for rumlige forespørgsler faldt med 35 %.
Hvor det går galt
Afstande kommer tilbage som små decimaltal. En forespørgsel spørger, hvor
langt der er mellem to byer, og får 0.08. Kolonnen er geometry i SRID 4326,
så svaret er i grader, og en længdegrad skrumper fra omkring 111 kilometer ved
ækvator til ingenting ved polerne. Cast til geography for at få svaret i
meter, eller brug ST_Transform til at flytte dataene over i et projiceret
system, der passer til området, før der måles.
En radiussøgning læser hver eneste række. Tabellen har et rumligt indeks,
men planen viser en sekventiel scanning. Den typiske årsag er et filter skrevet
som ST_Distance(a, b) < 500. Manualens liste over funktioner, der selv tager
indekset i brug, rummer ST_DWithin, men ST_Distance står der ikke. At pakke
den indekserede kolonne ind i en cast eller en transformation har samme
virkning, for et indeks på geom siger intet om geom::geography.
-- en geography-kolonne, indekseret som den er gemt, målt i meter
CREATE INDEX depots_geog_idx ON depots USING GIST (geog);
SELECT id FROM depots
WHERE ST_DWithin(geog, ST_MakePoint(12.57, 55.68)::geography, 500);
Skal dataene blive i en geometry-kolonne i 4326, så tilføj en
geography-kolonne som denne og indeksér den, eller opret indekset på præcis
det udtryk, forespørgslen bruger. Kør ANALYZE efter en stor indlæsning, så
planlæggeren ved, at indekset er værd at tage.
Punkterne havner i havet. Mønsteret ser rigtigt ud, men det hele ligger
forkert, ofte på et andet kontinent. To fejl giver det billede. ST_SetSRID
sætter kun et nyt mærke på en geometri og lader tallene være, så hvis den
bruges, hvor ST_Transform var ment, bliver meter stemplet som grader. Eller
også er længde- og breddegrad byttet om et sted tidligere i kæden: PostGIS
forventer ligesom GeoJSON x før y, altså længdegrad før breddegrad. Brug
ST_SetSRID til at erklære, hvad tallene allerede er, ST_Transform til at
omregne dem, og test hver import med ét punkt, hvis placering man kender.
Areal- og overlapsberegninger kaster fejl. En import fra en shapefil går
igennem, og senere fejler ST_Intersection med en topologiundtagelse. PostGIS
gemmer med vilje ugyldig geometri, så den kan findes og repareres, og en
polygon, hvis rand krydser sig selv, er ugyldig. Tjek med ST_IsValid, reparér
med ST_MakeValid, der bevarer alle inputpunkter, og tilføj en
check-constraint, så en dårlig form bliver afvist ved døren i stedet for at
dukke op i en rapport.
Læs mere
- PostGIS Documentation — projektets eget indgangspunkt til manualen, FAQ’en og undervisningsmaterialet.
- Data Management — geometry og geography, SRID’er, gyldighedsregler og de tre indekstyper, som manualen selv beskriver dem.
- Spatial Indexing — workshopkapitlet om afgrænsningsbokse og de funktioner, der bruger et indeks af sig selv.
- ST_DWithin — referencesiden for afstandstesten med enhederne for hver type.
- Simple Feature Access – Part 1 — OGC-standarden bag de geometrityper, PostGIS gemmer.