Donnerstag, 23. April 2015

PolygonToLine: Geht das auch umgekehrt?

Im PL/SQL Package SDO_UTIL findet sich die Funktion POLYGONTOLINE, welche ein Polygon in eine Linie konvertiert.
Für den umgekehrten Vorgang, eine Linie in ein Polygon umzuwandeln, gibt es (noch) keine solche Funktion im Package. Allerdings kann ich die gerade ganz gut brauchen. Denn für ein Set an Isolinien (SDO_GEOMETRY mit GTYPE=2002) sollen die abgedeckten Flächen berechnet werden. Flächenberechnungen mit SDO_GEOM.AREA sind aber nur für Polygone (inklusive Polygone mit Löchern) erlaubt.
Also schreiben wir uns selbst eine Funktion. Das ist auch nicht weiter schwierig, wie Ihr weiter unten sehen könnt.
Der besseren Lesbarkeit halber habe ich die wichtigsten Erläuterungen als Kommentar in den Code eingefügt.

Viel Spass beim Ausprobieren !

create or replace function line_to_polygon (
  p_line_geom sdo_geometry)
return sdo_geometry deterministic
is 
  p_polygon_geom sdo_geometry;
  k number;
begin
  /* 
   * Geometrietyp prüfen: Muss gleich 2002 für einfache 2D Linien-Geometrie sein.
   * Doku: http://docs.oracle.com/cd/B28359_01/appdev.111/b28400/sdo_objrelschema.htm#g1013735 
   */
  if p_line_geom.sdo_gtype <> 2002 then
    raise_application_error (-20001, 'Geometrie ist keine einfache 2D Linie.  GTYPE <> 2002.');
  end if;

  p_polygon_geom := p_line_geom;

  -- GTYPE neu setzen für einfache 2D Polygon-Geometrie.
  p_polygon_geom.sdo_gtype := 2003;

  /* 
   * ELEMENT_INFO_ARRAY neu setzen.
   * Doku: http://docs.oracle.com/cd/B28359_01/appdev.111/b28400/sdo_objrelschema.htm#SPATL494 
   */
  
  p_polygon_geom.sdo_elem_info := sdo_elem_info_array (1, 1003, 1);

  -- Anzahl der Stützpunkte bestimmen
  k := p_polygon_geom.sdo_ordinates.count;

  /* 
   * Polygon muss geschlossen werden. 
   * Daher prüfen, ob letzter Stützpunkt der Linie gleich dem 1. Stützpunkt ist. 
   * Wenn nicht, neuen Stützpunkt einfügen (SDO_ORDINATE_ARRAY wird erweitert um 2 Werte). 
   */

  if (p_polygon_geom.sdo_ordinates(k-1) <> p_polygon_geom.sdo_ordinates(1)
    or p_polygon_geom.sdo_ordinates(k) <> p_polygon_geom.sdo_ordinates(2))
  then
    p_polygon_geom.sdo_ordinates.extend(2);
    p_polygon_geom.sdo_ordinates(k+1) := p_polygon_geom.sdo_ordinates(1);
    p_polygon_geom.sdo_ordinates(k+2) := p_polygon_geom.sdo_ordinates(2);
  end if;
  
  -- Jetzt nur noch die Polygon-Geometrie zurückgeben
  return p_polygon_geom;
end line_to_polygon;
/
sho err
Diejenigen unter Euch, welche Anfang des Jahres im Oracle Spatial Workshop mit Albert Godfrind waren, finden die Funktion auch im Labs/07-processing-Ordner.

Freitag, 17. April 2015

Welche Geometrietypen sind in einer SDO_GEOMETRY-Tabelle zu finden?

Dieser Tipp fällt wieder einmal in die Kategorie: Lauter kleine Helferlein.

Fragen Sie sich auch manchmal, welche Geometrietypen eigentlich in einer Tabelle so alles zusammengefaßt sind?
Ohne groß weiter nachzudenken, ist ein Ansatz:
  select distinct g.geom.sdo_gtype
    from geom_tab g
order by 1;
Im Ergebnis erhalte ich die numerische Kodierung der verwendeten Geometrietypen.

Das Ganze könnte ich zum Beispiel mit DECODE nun noch so aufbereiten, dass auch nicht mit dieser Kodierung Vertraute den Inhalt verstehen.

Alternativ - und das ist an dieser Stelle meine Empfehlung - kann ich aber auch die Funktion MIX_INFO im SDO_TUNE-Package benutzen.
execute sdo_tune.mix_info('GEOM_TAB','GEOM');
Die gibt mir die Geometrietypen nicht nur in lesbarer Form zurück, sondern zusätzlich auch gleich noch:
  • die Gesamtzahl der Geometrien,
  • die Anzahl an Geometrien pro Geometrietyp sowie
  • die prozentuale Verteilung pro Geometrietyp
Das sieht für meine Beispiel-Tabelle dann so aus:
Total number of geometries: 5274896
   Point geometries:        0  (0%)
   Curvestring geometries:   0  (0%)
   Polygon geometries:      5274896  (100%)
   Complex geometries:      0  (0%)

Montag, 13. April 2015

Oracle Spatial und Twitter

Wir nutzen Twitter als Kommunikationskanal.
Häufig verwendete Hashtags sind: #oraclespatial #oraclemaps #spatial #LIOracleSpatial

Ihr könnt auch Carsten, mir und anderen aus der Spatial Community bei Oracle direkt folgen:
@cczarski @kpatenge @agodfrin @richpitts

Dienstag, 7. April 2015

Beispielhaft den Nutzen von VPA testen - Ein kleines Skript für den Eigengebrauch


Im Anschluss an einen Workshop zu Oracle Spatial 12c hat einer der Teilnehmenden das Feature VPA (Vector Performance Accelerator) erfolgreich getestet.
Ich habe dazu eine kurze Nachricht in der Oracle Spatial and Graph Gruppe von LinkedIn geposted.

Für diejenigen, die VPA selbst mal ausprobieren wollen, habe ich hier ein kleines Skript. Dieses vergleicht die Ausführungszeiten einer SQL Query ohne VPA gegen die mit VPA. Es kann für eigene zu testende Abfragen entsprechend angepaßt werden.

Das Ergebnis für 3 beispielhafte Queries kann sich mehr als sehen lassen. Die Zusammenfassung findet Ihr am Ende.

Für die Tests habe ich Beispieldaten (Postleitzahlgebiete von DE) des Oracle Partners GfK GeoMarketing verwendet. (Den anzupassenden Teil habe ich rot gekennzeichnet.)
REM spatial_12c_vpa_perf_test.sql - collect performance information related to Oracle Spatial 12c
REM Run script as user SYSTEM
define SRDCNAME='SPATIAL_VPA_PERF_TRACE'
set TERMOUT off FEEDBACK off VERIFY off TRIMSPOOL on HEADING off
COLUMN SRDCSPOOLNAME NOPRINT NEW_VALUE SRDCSPOOLNAME
select 'SRDC_'||upper('&&SRDCNAME')||'_'||upper(instance_name)||'_'||
       to_char(sysdate,'YYYYMMDD_HH24MISS') SRDCSPOOLNAME from v$instance;
set TERMOUT on
REM
spool &&SRDCSPOOLNAME..txt
select '+----------------------------------------------------+' from dual
union all
select '| Diagnostic-Name: '||'&&SRDCNAME' from dual
union all
select '| Timestamp:       '||
          to_char(systimestamp,'YYYY-MM-DD HH24:MI:SS TZH:TZM') from dual
union all
select '| Machine:         '||host_name from v$instance
union all
select '| Version:         '||version from v$instance
union all
select '| DBName:          '||name from v$database
union all
select '| Instance:        '||instance_name from v$instance
union all
select '+----------------------------------------------------+' from dual
/

set HEADING on
set echo on feedback on termout on pages 999 lines 132 long 300000000

DEFINE OBJ_OWNER = &1
DEFINE OBJ_PASSWD = &2

/*
 * Grant necessary privileges
 */

grant alter system to &&OBJ_OWNER;
grant alter session to &&OBJ_OWNER;

connect &&OBJ_OWNER/&&OBJ_PASSWD
alter system flush shared_pool;

alter session set tracefile_identifier='SRDC_Spatial_VPA_Perf_Test';
alter session set events '10046 trace name context forever, level 12';
-- alter session set sql_trace = TRUE;

alter session set spatial_vector_acceleration = FALSE;

set timing on
REM -- ------------------------------------
REM -- Add query to be traced and analyzed
REM -- Run without VPA first
REM -- ------------------------------------

REM -- Begin of query
with test as (
  select sdo_aggr_union(sdoaggrtype(g.geometry,0.05)) aggr_geom 
    from de_5digpc_2010 g
   where substr(g.id,1,1) in ('0','1','2'))
select count(*) 
  from test;
REM -- End of query

set timing off

alter system flush shared_pool;
alter session set spatial_vector_acceleration = TRUE;
 
set timing on
REM -- ------------------------------------
REM -- Add same query
REM -- Run with VPA now
REM -- ------------------------------------

REM -- Begin of query
with test as (
  select sdo_aggr_union(sdoaggrtype(g.geometry,0.05)) aggr_geom 
    from de_5digpc_2010 g
   where substr(g.id,1,1) in ('0','1','2'))
select count(*) 
  from test;
REM -- End of query
  
set timing off

spool off

Im Ergebnis erhalte ich Faktoren von 10 bis 253, was die Ausführungszeiten betrifft.
Fazit:
Je grösser die Anzahl der zu aggregierenden Polygone, umso höher ist der Performancegwinn.

Und hier sind die Ergbnisse im Detail:

Anzahl der aggr. Objekte Geometrietyp Elapsed time in Sek. ohne VPA Elapsed time in Sek. mit VPA Faktor Abfrage
10 Polygon 18,33 1,78 10 with test as (
select sdo_aggr_union(sdoaggrtype(g.geometry,0.05)) aggr_geom
from de_1digpc_2010 g)
select count(*)
from test;
95 Polygon 151,66 2,44 62 with test as (
select sdo_aggr_union(sdoaggrtype(g.geometry,0.05)) aggr_geom
from de_2digpc_2010 g)
select count(*)
from test;
2168 Polygon 1338,65 5,29 253 with test as (
select sdo_aggr_union(sdoaggrtype(g.geometry,0.05)) aggr_geom
from de_5digpc_2010 g
where substr(g.id,1,1) in ('0','1','2'))
select count(*)
from test;