Dávkové nahrání dat¶
Dávkové zpracování a následné nahrávání dat z různých zdrojů do databáze je nejzákladnějším úkonem při budování databáze prostorových dat. Data obvykle nahráváme ze souborových formátů, případně z webových služeb. Řetězec úkonů mezi uchopením nějakého zdroje dat a jeho konečným umístěním do databáze bychom nejspíš označili termínem ETL. Pro standardní formáty s úspěchem můžeme využít utility knihovny GDAL, jmenovitě ogr2ogr. Pro import Esri Shapefile můžeme využít loader shp2pgsql instalovaný spolu s PostGISem.
shp2pgsql¶
shp2pgsql je utilitka distribuovaná spolu s PostGISem, která vrací data v dump formátu na standardní výstup. Je tedy možné, v případě potřeby, upravit výstup z této utility například unixovým nástrojem sed či případně uložit do souboru a ručně zeditovat.
shp2pgsql umí data přidat do již existující tabulky, tak potřebnou tabulku vytvořit. Lze také pouze vytvořit na základě dat prázdnou tabulku a samotná data do ní nenahrávat. Více v manuálu.
Poznámka
Hlavním limitem pro použití shp2pgsql jsou
samotné limity formátu Esri Shapefile. Jde například o
zkracování názvů sloupců, formát nedovoluje délku názvu
sloupce větší než 10 znaků. Dále můžete mít problém s
některými datovými typy, například numeric bude surově
zakrácen na int, což může způsobit problémy mimo jiné u
dat ve formátu VFK, které používají primární klíče
numeric(30).
V našem příkladě zkusíme nahrát datovou vrstvu ulic.
shp2pgsql Ulice_cp1250.shp ukol_1.ulice | psql pokusnik 2> err
Tabulka se vůbec nevytvoří, problém je s kódováním. Atributová tabulka
vstupních dat je v kódování cp1250 a naše databáze v UTF8. Použijeme
proto přepínač -W pro nastavení kódování vstupního souboru.
shp2pgsql -W cp1250 Ulice_cp1250.shp ukol_1.ulice | psql pokusnik 2> err
Pohled do geometry_columns nám odhalí poměrně nepříjemný fakt a to, že naše nově přidaná vrstva nemá správný souřadnicový systém (SRID 5514), nýbrž neznámý souřadnicový systém s kódem 0.
SELECT * FROM geometry_columns WHERE f_table_schema = 'ukol_1';
f_table_catalog | skoleni
f_table_schema | ukol_1
f_table_name | ulice
f_geometry_column | geom
coord_dimension | 2
srid | 0
type | MULTILINESTRING
Musíme tedy rozšířit předešlý příkaz o zadání SRID, které má být
nové vrstvě přiřazeno (přídáme přepínačý -d, který stavající
tabulku nejprve odstraní).
shp2pgsql -d -W cp1250 -s 5514 Ulice_cp1250.shp ukol_1.ulice | psql pokusnik 2> err
Tip
SRID vrstvy, je samozřejmě možné změnit u hotové vrstvy a to příkazem UpdateGeometrySRID, nicméně v případě, že nad takovou tabulkou už máte kupříkladu postavené pohledy, bude to nutně znamenat je všechny přegenerovat, přičemž si můžete (a také nemusíte) vyrobit nepříjemný chaos v právech. Je tedy lepší na toto pamatovat a tabulky již vytvářet se správným SRID.
Tip
K utilitě shp2pgsql existuje také obrácený nástroj pgsql2shp, který slouží k exportu tabulek do formátu Esri Shapefile. Jeho použití je jednoduché a najdete ho na každém stroji s PostGISem. Nicméně, jak již bylo zmíněno, Esri Shapefile je zastaralý formát. Při jeho použití může dojít k degradaci dat, tudíž ho má smysl použít jen pokud příjemce dat vyžaduje výslovně tento formát.
Poznámka pro pokročilé
Příklad jednoduchého skriptu pro dávkový import souborů ve formátu Esri Shapefile z aktuálního adresáře
#!/bin/sh
for f in *.shp; do
echo $f
shp2pgsql -d -D $f ukol_1.${f%%.shp} 2>/dev/null | \
psql pokusnik >/dev/null 2>err
done
exit 0
ogr2ogr¶
Nástroj ogr2ogr je součástí balíku utilit distribuovaných s knihovnou GDAL. Slouží k převodu dat mezi nejrůznějšími GIS formáty. Mimo jiné, od verze 1.11 podporuje také Výměnný formát RÚIAN, což je v našich podmínkách velice užitečné. Kromě převodů mezi různými formáty geodat můžeme ogr2ogr použít i pro transformaci mezi souřadnicovými systémy.
ogr2ogr se umí buď připojit rovnou do databáze, nebo umí generovat (případně posílat na STDOUT) data v dump formátu PostgreSQL.
Driver PostgreSQL¶
Nejdříve převedeme data z předešlého příkladu. Použijeme driver PostgreSQL, který se připojuje přímo k databázi.
Nahrání Esri Shapefile pomocí ogr2ogr z příkazové řádky
export SHAPE_ENCODING="cp1250"
ogr2ogr -f PostgreSQL PG:dbname=pokusnik -a_srs 'EPSG:5514' Ulice_cp1250.shp \
-nlt MULTILINESTRING \
-lco 'GEOMETRY_NAME=geom' \
-nln ukol_1.ulice
V prvním řádku uvedeme kódování atributových dat vstupního souboru.
Tip
V případě, že bychom chtěli použít pro import jiné kódování,
než je UTF8, nastavíme kódování pro PostgreSQL do proměnné
prostředí PGCLIENTENCODING.
Varování
Příkaz export funguje pod Linuxem, ve Windows se proměnné prostředí nastavují jinak.
Tip
Proměnnou prostředí SHAPE_ENCODING použijeme v
případě, že chceme použít při výstupu do Esri Shapefile
jiné kódování, než je UTF8.
Parametr -f nastaví výstupní formát na PostgreSQL,
PG: nastaví parametry připojení k databázi. Lze
také nastavit např. aktivní schéma - tj. schéma, do kterého budou
vstupní data importována.
Tip
U dávkového nahrávání je výhodné nastavit si heslo do souboru s autentizací.
Parametr -a_srs slouží k nastavení výstupního souřadnicovýho
systému, v tomto případě nastavíme souřadnicový systém na
EPSG:5514, tedy S-JTSK.
Poznámka pro pokročilé
Pokud bychom chtěli data v rámci importu
transformovat, tak použijeme volby t_srs a
s_srs. Souřadnicový systém můžeme zadávat
i v zápisu knihovny Proj.4.
Následuje název vstupního souboru. Po něm je použit parametr
-nlt, který slouží k zadání typu geometrie, v našem případě
je to MULTILINESTRING, ogr2ogr totiž z nějakého důvodu v
tomto případě chybně identifikuje geometrii vstupního souboru jako
LINESTRING.
Nakonec pomoci -nln nastavíme nový název vrstvy (včetně
názvu schématu, které ovšem musí být předem vytvořeno).
Driver PGDump¶
Driver PGDump místo přímého spojení s databází zapisuje do souboru (nebo na STDOUT). To může být užitečné například v případě, že nemáme přímé připojení k databázi, nebo když chceme převedený soubor nějakým způsobem dále upravit. Můžeme ho například poslat rourou přes sed a potom rovnou na psql. Tento postup však bude fungovat na OS, kde je tento nástroj dosupný, např. GNU/Linux.
Nahrání Esri Shapefile pomocí ogr2ogr (PGDump) z příkazové řádky
Zde přejmenujeme ulici Kaštanová na Jírovcová.
export PG_USE_COPY=YES
ogr2ogr -f PGDump /dev/stdout -a_srs 'EPSG:5514' Ulice_cp1250.shp \
-lco 'GEOMETRY_NAME=geom' \
-nlt MULTILINESTRING -nln ukol_1.ulice_3 \
| sed 's/Kaštanová/Jírovcová/g' \
| psql pokusnik 2> err
V prvním řádku nastavíme proměnnou prostředí
PG_USE_COPY. Tím řekneme, že data mají být přenesena jako
COPY tabname FROM STDIN, namísto řady INSERT
statementů. Stejným způsobem by fungoval i PostgreSQL driver.
Parametry na dalším řádku již známe. Jedná se o formát, následuje název výstupního souboru (v našem případě odesíláme na stdout), výstupní souřadnicový systém a vstupní soubor. Další řádek též nepřináší nic nového. Nakonec nahradíme pomocí sedu „Kaštanová“ za „Jírovcová“ a odešleme rourou na psql.
Důležité
PostgreSQL driver může mít problém vytvořit tabulku s více geometrickými sloupci, potom nezbývá než použít PGDump driver nebo vytvořit tabulku ručně.
Poznámky k dalším formátům¶
Esri Shapefile není samozřejmě jediný formát, se kterým ogr2ogr pracuje. Předvedeme si, jak snadno nahrát soubor ve formátu GML.
GML¶
Nahrání GML pomocí ogr2ogr z příkazové řádky
Data ke stažení zde.
ogr2ogr -f PGDump /dev/stdout -a_srs 'EPSG:5514' \
-lco 'GEOMETRY_NAME=adresnibod' \
adres_mista.gml.gz \
-nln ukol_1.adresy | \
psql pokusnik 2> err
VFR¶
Nahrání Výměnného formátu RÚIAN (VFR) pomocí ogr2ogr z příkazové řádky
Nejprve vytvoříme nové schéma
psql gismentors -h training.gismentors.eu -U skoleni -W -c "create schema ltm"
A poté naimportujeme data vybrané obce (Litoměřice - 564567)
ogr2ogr -f PostgreSQL \
"PG:dbname=gismentors host=training.gismentors.eu user=skoleni password=XXX active_schema=ltm" \
/vsicurl/http://vdp.cuzk.cz/vymenny_format/soucasna/20170331_OB_564567_UKSH.xml.gz
Bližší informace: http://freegis.fsv.cvut.cz/gwiki/RUIAN
WFS¶
V ogr2ogr je možné pracovat i s webovými službami, například můžeme načíst katastrální území z WFS ČÚZK.
Nahrání WFS z příkazové řádky
ogr2ogr -f "PostgreSQL" PG:"dbname=pokusnik" \
"http://services.cuzk.cz/wfs/inspire-cp-wfs.asp?\
service=WFS\
&request=GetFeature&version=2.0.0\
&srsName=urn:ogc:def:crs:EPSG::5514\
&typeNames=CP:CadastralZoning\
&featureid=CZ.605999" \
-nln ukol_1.katatest
Poznámka pro pokročilé
Ve WFS bývá nastaven limit na maximální počet prvků. V praxi není možné obvykle stáhnout větší objem dat. Můžeme však stahovat prvky po jednom. Z číselníku katastrálních území vybereme katastrální území Prahy.
Dávkového nahrání dat z WFS z příkazové řádky
wget http://www.cuzk.cz/CUZK/media/CiselnikyISKN/SC_SEZNAMKUKRA_DOTAZ/SC_SEZNAMKUKRA_DOTAZ.zip?ext=.zip
unzip SC_SEZNAMKUKRA_DOTAZ.zip?ext=.zip
psql -c "truncate table ukol_1.katatest" pokusnik;
cut -d ';' -f 7,8 SC_SEZNAMKUKRA_DOTAZ.csv | \
tail -n +2 | \
grep Praha |
cut -d ';' -f 2 |
while read kodku; do
echo $kodku;
ogr2ogr -append \
-f "PostgreSQL" PG:"dbname=pokusnik" \
"http://services.cuzk.cz/wfs/inspire-cp-wfs.asp?\
service=WFS\
&request=GetFeature&version=2.0.0\
&srsName=urn:ogc:def:crs:EPSG::5514\
&typeNames=CP:CadastralZoning&\
featureid=CZ.$kodku" \
-nln ukol_1.katatest
done;
Varování
Bagrování WFS ovšem není ideální způsob jak plnit databázi daty (limit na bbox a počet prvků tam není jen tak pro nic za nic). Tato data je možné získat i pohodlněji a šetrněji k infrastruktuře ČÚZK.
Zobrazení dat¶
Data si můžeme zobrazit a dále s nimi pracovat například v QGISu, viz školení pro začátečníky. Pokročilejší uživatelé mohou výužít funkce PostGISu, viz příklad níže.
Poznámka pro pokročilé
Na závěr si naše data zobrazíme ve formátu SVG.
SET SEARCH_PATH = public, ukol_1;
SELECT
XMLELEMENT(
NAME svg,
XMLATTRIBUTES(
height, width, "viewBox"
, 'http://www.w3.org/2000/svg' AS xmlns, '1.1' AS version)
, linie, body, popisky
)
FROM
(
SELECT
600 AS height
, 800 AS width
, array_to_string(ARRAY[MIN(ST_XMIN(geom)) - 50, -1 * (MAX(ST_YMAX(geom))) - 50
, (@(MAX(ST_XMAX(geom)) - MIN(ST_XMIN(geom)))) + 100
, (@(MAX(ST_YMAX(geom)) - MIN(ST_YMIN(geom)))) + 100], ' ') AS "viewBox"
, XMLAGG(
XMLELEMENT(NAME path,
XMLATTRIBUTES( ST_AsSVG(geom, 1, 0) AS d
, 'rgb(55,230,100)' AS stroke
, 25 AS "stroke-width"
, 'none' AS fill
)
)
) linie
FROM
(
SELECT geom AS geom FROM ulice --LIMIT 1
) ok
) podklad,
(
SELECT
XMLAGG(
XMLELEMENT(NAME circle,
XMLATTRIBUTES( ST_X(geom) AS cx, -1 * ST_Y(geom) AS cy, 150 AS r
, 'black' AS stroke
, 100 AS "stroke-width"
, 'rgb(255,0,0)' AS fill
)
)
) body
, XMLAGG(
XMLELEMENT(NAME text,
XMLATTRIBUTES( ST_X(geom) + 250 AS x, -1 * ST_Y(geom) AS y
, 'Verdana' AS "font-family"
, 750 AS "font-size"
, 'rgb(0,0,0)' AS fill
), id
)
) popisky
FROM
(
SELECT id, geom_p AS geom FROM vesmirne_zrudice --LIMIT 1
) body
) data;