Freitag, 23. Mai 2014

Ein GeoRaster ETL Werkzeug als grafische Oberfläche für gdal zum Laden nach SDO_GEORASTER

In meinem letzten Blog-Posting, dem 1. zum Thema Rasterdaten, hatte ich den Georaster-Viewer vorgestellt.
Für den Einstieg ins Thema und den schnellen Erfolg, ein Rasterbild in die Datenbank zu laden, war das sicher erst mal hilfreich.
Was das Laden oder Exportieren von Rasterdaten betrifft, kommt man sicher an gdal nur schwer vorbei. Daher wird die Nutzung auch schon länger von Oracle empfohlen. Allerdings braucht es doch ein wenig Übung, auf Kommandozeilenebene damit umzugehen. (Infos u.a. hier)

Eine grafische Oberfläche vom Spatial Development Team schafft Abhilfe. Diese verwendet intern gdal. Die Rede ist vom Georaster Batch ETL Werkzeug (GDAL-based GeoRaster Concurrent Batch Loading and Exporting Wizard). Dessen neueste Version kann von den Oracle Spatial and Graph Sample Code Webseiten im OTN heruntergeladen werden. Es kann sowohl für die Version 12c als auch 11g verwendet werden. Ich habe einen ersten Test mit Version 12cR1 durchgeführt.

Nach dem Download, Auspacken und Anpassen des Shell- bzw. Batch-Skripts (startGeoRasterETL.sh bzw. startGeoRasterETL.bat) kann es auch schon losgehen. Für den Einstieg hilft zudem noch ein kleines Handbuch.
Wie der Name nahelegen soll, können mehrere Rasterdaten-Files gleichzeitig geladen werden. Diese werden ausgeählt, mit den entsprechenden Ladeparameter-Werten versehen (u.a. Blocking oder Anzahl der Pyramid Levels).
Alles zusammen wird als XML-Parameterdatei gespeichert und anschließend als Job ausgeführt.
Die vier in die Tabelle CITY_IMAGES geladenen Rasterdaten-Dateien überprüfe ich dann mit dem schon bekannten GeoRaster-Viewer. Sie wurden mit den (automatisch vergebenen) RasterIDs 49−52 geladen.
Was es mit Blocking und Pyramiden auf sich hat, darüber soll es dann in einem neuen Blog-Posting gehen.

Donnerstag, 15. Mai 2014

In wenigen Schritten zu Rasterdaten in der Oracle Datenbank

Der Management von Vektordaten (SDO_GEOMETRY) ist in diesem Blog schon recht ausführlich behandelt worden. Daher möchte ich in meinem Beitrag heute zeigen, wie auf einfache Art und Weise Rasterdaten als SDO_GEORASTER geladen werden können. Voraussetzung dafür ist, dass die Oracle Database Examples von OTN heruntergeladen und installiert werden.
Relevante Links für die Datenbank-Version 12c sind:
Was finden Sie nach der Installation vor?
Im Verzeichnis %ORACLE_HOME%\md wurden der Ordner demo und weitere themenspezifische Unterordner neu angelegt. So auch einer mit dem Namen georaster.

Für die weiteren Ausführungen nutze ich die SQL-Skripte im Ordner plsql als Basis sowie den GeoRasterViewer, der im Ordner java liegt und den ich schon mal starte.

Was wird noch benötigt? Natürlich ein paar Beispiel-Bilder. Ich nutze .tif-Dateien von San Francisco mit den zugehörigen World Files (.wld).

Von der Anzeige eines Rasterbildes aus der Oracle Datenbank heraus bin ich jetzt nur noch 3 Schritte entfernt:
  1. Anlegen einer SDO_GEORASTER-Tabelle und der zugehörigen Raster Data Table(s)
  2. Initialisieren des SDO_GEORASTER Objekts (oder gleich mehrerer)
  3. Laden des Rasterbildes über den GeoRasterViewer
Das sieht dann so aus:
-------------------------------------------------------------------
-- Schritt 1: Anlegen einer SDO_GEORASTER-Tabelle.
--            Anlegen der sogenannten Raster Data Table (RDT).
--
-- Tabelle muss eine Spalte vom Typ SDO_GEORASTER enthalten.
-------------------------------------------------------------------

drop table city_images_rdt_1 cascade constraints purge
/
drop table city_images  cascade constraints purge
/
create table city_images (
  id          number primary key,
  city        varchar2(100),      
  type        varchar2(32), 
  georaster  mdsys.sdo_georaster)
/
create table city_images_rdt_1 of mdsys.sdo_raster (
  primary key (rasterId, pyramidLevel, bandBlockNumber, rowBlockNumber, columnBlockNumber))
  lob(rasterblock) store as securefiles (nocache nologging)
/

-------------------------------------------------------------------
-- Schritt 2: Initialisieren des SDO_GEORASTER Objekts.
-------------------------------------------------------------------

insert into city_images values( 
  1, 
  'San Francisco', 
  'TIFF', 
  mdsys.sdo_geor.init('CITY_IMAGES_RDT_1'))   -- RasterID wird automatisch generiert 
/                                             -- bei fehlendem 2. Parameterwert
commit
/
Für Schritt 3 wird im GeoRasterViewer eine Verbindung auf die Datenbank geöffnet mit dem Nutzer, welcher Eigentümer der zuvor angelegten Tabellen ist.
Zunächst erscheint beim Auswählen des initialisierten SDO_GEORASTER-Objekts (es hat die automatisch generierte ID 29) eine Fehlermeldung:
Das ist richtig so. Habe ich doch das Rasterbild selbst noch gar nicht geladen.
Aber ich hole das jetzt nach mit Tools > Import into DB. Bei den Ladeoptionen entscheide ich mich dafür, kein Blocking anzuwenden.
Die Bestätigung, dass das Rasterbild geladen wurde, erfolgt prompt.
Und das Ergebnis selbst sieht dann so aus:
Ggf. müssen die Daten noch mal gelesen werden über Rasters > Refresh List, damit das Rasterbild wie erwartet angezeigt wird. Aber das war es dann auch schon.
Ausführliche Hinweise finden sich wie immer in der Online Dokumentation im Oracle Technology Network. Für die Rasterdatenverwaltung mit Oracle Spatial gibt es ein eigenes Dokument (hier der Link auf die Dokumentation für Version 12.1).

Zusätzliche Hinweise:
  • Eine Besonderheit ist bei den Beispiel-Dateien ist zu beachten. ESRI WorldFiles enthalten keine Information &uunml;ber das Bezugssystem. Daher muss die SRID beim oder nach dem Laden manuell gesetzt werden. Dazu wird die Prozedur sdo_geor.setModelSRID verwendet.
  • Wie von den Vektordaten mit SDO_GEOMETRY bekannt, werden auch für SDO_GEORASTER Metadaten registriert (also nach dem Anlegen der Tabelle in Schritt 1).
  • Der in früheren Oracle Spatial Versionen (ich habe mit 12.1 getestet) manuell für jede Tabelle mit SDO_GEORASTER anzulegende DML-Trigger (sdo_geor_utl.createDMLTrigger), wird automtisch erzeugt. Dieser trägt den Präfix GRDMLTR.
  • "Tonnenweise" Rasterdaten in Oracle Spatial gibt es übrigens im Geoproxy des Freistaates Thüringen.
-------------------------------------------------------------------
-- Prozedur zum Setzen der SRID
-------------------------------------------------------------------
declare
  geor  sdo_georaster;
begin
  select georaster into geor from city_images where id = 1 for update;
  sdo_geor.setModelSRID(geor, 26943);
  update city_images set georaster = geor where id = 1;
  commit;
end;
/

-------------------------------------------------------------------
-- Metadaten prüfen
-------------------------------------------------------------------
select * from user_sdo_geor_sysdata
/

-------------------------------------------------------------------
-- SDO_GEORASTER Objekt validieren
--
-- Jeweils erwartetes Ergebnis: isvalid = TRUE
-------------------------------------------------------------------
select 
  r.id,
  mdsys.sdo_geor.validategeoraster(r.georaster) isvalid
from 
  city_images r 
order by 
  id
/

select 
  r.id,
  mdsys.sdo_geor.schemavalidate(r.georaster) isvalid
from 
  city_images r 
order by
  id
/

Montag, 12. Mai 2014

Wieviel Speicherplatz brauchen Ihre SDO_GEOMETRY-Tabellen?

In Ergänzung zu meinem ersten Blog-Posting heute, möchte ich noch kurz eine einfache Funktion zum Berechnen des allokierten Speichers hinzufügen. Diese berücksichtigt ausschließlich Tabellen-, Lob- und Index-Segmente (ist also nicht für partitionierte Tabellen anwendbar).
create or replace function alloc_space_in_mbytes(tablename in varchar2)
return number 
is
tablesize number;
begin
  select 
    sum(bytes) into tablesize
  from (
    select 
      segment_name, 
      bytes  
    from 
      user_segments                     -- Tabellensegmente             
    where  
      segment_name = tablename
    union all
    select 
      s.segment_name segment_name, 
      s.bytes bytes
    from 
      user_lobs l,                      -- Lobsegmente
      user_segments s
    where 
      l.table_name = tablename and
      s.segment_name = l.segment_name
    union all
    select 
      s.segment_name segment_name, 
      s.bytes bytes
    from 
      user_indexes i,                   -- Indexsegmente
      user_segments s
    where 
      i.table_name = tablename and
      s.segment_name = i.index_name);

  tablesize := tablesize/1024/1024;     -- Umrechnung in MB
  return tablesize;
end;
/
Der Aufruf der Funktion kann dann wie folgt aussehen:
select
  alloc_space_in_mbytes('GEOM_TABLE_UNTRIMMED') untrimmed, 
  alloc_space_in_mbytes('GEOM_TABLE_TRIMMED') trimmed
from dual
/
Für eine Testtabelle mit 218237 Polygonen, insgesamt 60754462 Stützpunkten und vorhandenem Spatial Index ergaben sich damit folgende Werte:
  • SDO_ORDINATE_ARRAY-Werte mit überwiegend 12 bis 13 Nachkommastellen: 1643.5 MB
  • SDO_ORDINATE_ARRAY-Werte gekürzt auf 5 Nachkommastellen: 1033.5 MB

Koordinatenwerte in SDO_ORDINATE_ARRAY auf sinnvolles Mass an Nachkommastellen trimmen

Kürzlich hatte ich Gelegenheit, Blick auf SDO-GEOMETRY-Daten zu werfen, die Gaus-Krüger 3 als Bezugssystem hatten. Was mir dabei auffiel, war die immens hohe Anzahl an Nachkommastellen bei den Koordinatenpaaren (Rechts- und Hochwert). Teilweise 30 Stellen und mehr.

Aus fachlicher Sicht macht das natürlich keinen Sinn. 2 oder 3 (cm, mm) Nachkommastellen sind üblich.
Auch technisch gesehen bedingen mehr Nachkommastellen sowohl mehr Speicherbedarf als auch möglicherweise negative Einflüsse auf die Performance bei Pflege und Abfragen.

Wie kann man aber nun schnell und ohne großen Aufwand, die Nachkommastellen trimmen?

Eine entsprechende Funktion in PL/SQL Package SDO_UTIL gibt es leider (noch) nicht. Das macht aber nichts. Denn der PL/SQL-Code dafür ist schnell geschrieben:

create or replace procedure trim_ordinates(
  p_geom in out nocopy sdo_geometry,
  p_prec in number default 5                -- Anzahl der Nachkommastellen
) is
begin
  for i in 1..p_geom.sdo_ordinates.count loop
    p_geom.sdo_ordinates(i) := round(p_geom.sdo_ordinates(i), p_prec);
  end loop;
end trim_ordinates;
/

create or replace function func_trim_ordinates(
  p_geom in sdo_geometry,
  p_prec in number default 2
) return sdo_geometry is
  l_geom sdo_geometry := p_geom ;
begin
  trim_ordinates(l_geom, p_prec);
  return l_geom;
end func_trim_ordinates;
/

sho err

-- Ergebnis der Funktion testen
select func_trim_ordinates(geom,3) from geom_tab;
/

-- Update durchführen
update geom_tab set geom=func_trim_ordinates(geom,3)
/
commit
/
Was spare ich ein an Speicherplatz?
Um diese Frage zu beantworten, überprüfe ich, wieviel Bytes für einen Rechts- bzw. Hochwert mit 30 Nachkommastellen benötigt werden versus einem mit 3.
select 
  vsize(5397831.164000000816421415421630849375) "Bytes_30_Nachkommastellen", 
  vsize(5397831.164) "Bytes_3_Nachkommastellen" 
from dual
/
20 Bytes werden für 30 Nachkommastellen benötigt, aber nur 7 Bytes bei 3 Nachkommastellen.
Bei einem Koordinatenpaar sind das 14 Bytes pro Stützpunkt.
Es ist also durchaus sinnvoll, sich über die notwendige Genauigkeit für die Speicherung von Geodaten Gedanken zu machen.