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;