Tipps, Tricks, Best Practices und Aktuelles zu Oracle Spatial Technologies
Freitag, 30. August 2013
Oracle Spatial and Graph Sessions auf der Oracle Open World 2013
Es mit wieder verschiedene Sessions mit Fokus auf die Oracle Spatial Technologies.
Details zu diesen Sessions sind hier zu finden.
Montag, 29. Juli 2013
NURBS-Kurven in Oracle12c - So geht's
diese werden ab Oracle 12.1 als Geometrietyp unterstützt. Die Grundlagen zu NURBS
(Non-Uniform Rational B-Spline) möchte ich im Rahmen dieses Blogs nicht erkläutern; dazu
gibt es eine Reihe guter Literatur und auch online sind eine Menge Informationen verfügbar - als Beispiel
sei der deutschsprachige Wikipedia-Artikel genannt.
Parametern sehr genau beschrieben werden kann. Dagegen verbraucht eine "Approximation" mit
Stützpunkten und geraden Linien als Verbindung wesentlich mehr Parameter für eine
wesentlich ungenauere Beschreibung der Kurve. Anwendung finden NURBS-Kurven vor allem
im CAD Bereich, aber auch Straßenkurven können mit NURBS-Kurven beschrieben werden.
in eine Tabelle gespeichert wird.
insert into nurbs_test values (1, SDO_GEOMETRY( 2002, -- Zweidimensionaler Linienzug 31468, -- Koordinatensystem NULL, SDO_ELEM_INFO_ARRAY( 1, 2, 3 -- 1,2,3 = NURBS-Kurve ), SDO_ORDINATE_ARRAY ( 3, -- Grad der Kurve (3=Kubisch) "d" 7, -- Es gibt 7 Kontrollpunkte "m" 0, 0, 1, -- 1. Kontrollpunkt -50, 100, 1, -- : 20, 200, 1, 50, 350, 1, 80, 200, 1, 90, 100, 1, 30, 0, 1, -- 7. Kontrollpunkt 11, -- Der Knotenvektor hat 11 Elemente = d + m + 1 0, 0, 0, 0, -- Normalisierter Knotenvektor 0.25, 0.5, 0.75, -- Start bei 0 - Ende bei 1 1, 1, 1, 1 -- Ansteigend ) ) ) /
daher wird der SDO_GTYPE in diesem Fall, wie bei einer geraden Linie, auf 2002 gesetzt.
Der zweite Parameter ist, wie bei anderen Geometrien auch, das Koordinatensystem. Wie bei
den bisher auch schon unterstützten einfachen Kurven (Arc Line Strings) sind geodätische
Koordinatensysteme für NURBS-Kurven nicht zugelassen.
SDO_ORDINATE_ARRAY besteht aus mehreren Abschnitten:
- Der erste Wert ist der Grad der Kurve, welcher die verwendete Basisfunktion festlegt. Die Basisfunktion
beschreibt den Verlauf der NURBS-Kurve.
- "1" bedeutet, dass eine lineare Funktion verwendet wird - es ergibt sich eine einfache, zusammengesetzte Linie durch die Kontrollpunkte. Dazu braucht man dann eigentlich keine NURBS-Kurve, daher wird eine "1" wohl nur sehr selten verwendet
- "2" ist eine quadratische Basisfunktion (die NURBS-Kurve entspricht dann einer Parabel)
- "3" ist eine kubische Basisfunktion - die Kurve wird dann einen S-Verlauf bekommen
- "5" ergibt eine mehrfach geschwungene Linie
- Der zweite Wert im SDO_ORDINATE_ARRAY gibt an, wieviele Kontrollpunkte vorliegen. Die Kontrollpunkte
kann man sich so vorstellen, dass sie gewissermaßen "an der Kurve" ziehen.
Die NURBS-Kurve wird (außer am Anfang und am Ende) nicht durch die Kontrollpunkte laufen. Jeder Kontrollpunkt
ist gewichtet, mit der Gewichtung (zwischen 0 und 1) kann man festlegen, wie stark der
Kontrollpunkt an der Kurve ziehen soll. Gibt man eine 0 an, so wird der Punkt quasi nicht berücksichtigt. - Der darauf folgende Wert gibt die Anzahl der Elemente im dann folgenden Knotenvektor - hier
muss immer der Wert (d + m + 1) stehen - also der Grad der Kurve plus die Anzahl der Kontrollpunkte
plus eins. Für eine Kurve dritten Grades mit 7 Kontrollpunkten steht dort also eine 11. - Der dann folgende Knotenvektor legt den Kurvenverlauf nicht direkt fest (das tun ja schon die Kontrollpunkte),
sie haben nur indirekt Einfluß. Die absoluten Werte sind ohne Bedeutung, interessant ist allein das
Verhältnis der Differenzen zueinander. Die Knotenvektoren 0,0,1,2,3,4,4 bedeuten also das
gleiche wie 1,1,2,3,4,5,5 oder 0,0,0.25,0.50.0.75,1,1. Ein Knotenvektor muss steigend sein.
Oracle erwartet normalisierte Werte (also zwischen 0 und 1). Ferner müssen die ersten "d+1" Werte gleich 0 und die letzten "d+1" Werte gleich 1 sein (siehe obiges Beispiel).
SQL> select gid, sdo_geom.validate_geometry_with_context(geom, 1) as valid 2 from nurbs_test where gid=1 GID VALID ---------- -------------------- 1 13072 [Element <1>] 1 Zeile wurde ausgewählt. SQL> exit $ oerr ora 13072 13072, 00000, "incorrect number of knots for SDO_GEOMETRY object" // *Cause: An incorrect number of knot values was passed for a Non-Uniform // Rational B-Spline curve. // *Action: Correct the number of knot values passed for the Non-Uniform // Rational B-Spline curve.
SQL> select SDO_UTIL.GetNurbsApprox(geom, 0.05) as geom from nurbs_test where gid = 1; GEOM -------------------------------------------------------------------------------- SDO_GEOMETRY(2002, 31468, NULL, SDO_ELEM_INFO_ARRAY(1, 2, 1), SDO_ORDINATE_ARRAY (0, 0, -2,9128395, 5,96995228, -5,6243745, 11,8211319, -8,1393559, 17,5559751, - 10,462535, 23,1769184, -12,598662, 28,6863981, -14,552488, 34,0868505, -16,32876 4, 39,380712, -17,932241, 44,5704191, -19,36767, 49,6584079, -20,639802, 54,6471 15, -21,753387, 59,5389767, -22,713177, 64,3364292, -23,523922, 69,0419091, -24, 190374, 73,6578527, -24,717284, 78,1866962, -25,109401, 82,6308762, -25,371477, :
Mittwoch, 10. Juli 2013
Vektordaten mit mehr sehr vielen Stützpunkten speichern
Das ist für so manche Geometrie zu wenig, um sie als SDO_GEOMETRY abzulegen.
Daher gibt es einen Workaround, der für die Version 11.2 nun auch im Oracle Spatial and Graph Online Handbuch dokumentiert und als Skript sdoupggeom.sql im Installationspfad der Oracle Datenbank liegt @$ORACLE_HOME/md/admin.
Das Kernstück des Skriptes ist das Überschreiben des Typs mittels:
alter type mdsys.sdo_ordinate_array modify limit 10000000 cascade;
Der Wert 10000000 kann bei Bedarf angepasst werden.
Zusätzlich werden über das Skript Prüfungen (z.B. ob Versionierung für Tabellen mit SDO_GEOMETRY-Spalten eingeschaltet ist) und anschließend ein Recompile der betroffenen Objekte vorgenommen.
Freitag, 21. September 2012
Aufgezeichneter Webcast "Wie kommen Daten auf die Karte"
Da mit Sicherheit nicht alle Interessierten die Gelegenheit hatten, den Webcast live zu verfolgen, haben wir diesen aufgezeichnet. Er steht auf ON24 bereit. Einfach auf "Präsentation starten" klicken und los geht's.
Mittwoch, 1. August 2012
Das Navi in der Datenbank
Dafür braucht´s doch eigentlich nicht so viel. Lassen Sie mich mal "laut" denken:
Vom Start- als auch Endpunkt kenne ich die (ungefähre) Adresse.
Was ich jetzt brauche, ist ein Prozess, der Folgendes für mich erledigt:
- Suche in einem Straßennetz nach Start- und Zielpunkt.
- Berechne den kürzesten oder auch schnellsten Weg zwischen diesen beiden Punkten.
- Gib mir die ermittelte Route zurück sowohl in ihrer textlichen Beschreibung als auch grafisch in einer Karte dargestellt.
Ein Straßennetz als Datengrundlage
Wo bekomme ich ein Straßennetz her? Wie findet das seinen Weg in meine Datenbank?Sie merken schon, ich verwende den Begriff Straßennetz. So ein Netz hat eine bestimmte Struktur, ist es doch aus Knoten und Kanten aufgebaut, das mit Hilfe des Netzwerkdatenmodells (NDM) (Funktionalität der DB EE Option Oracle Spatial) abgebildet wird. Soll das Netz noch "routingfähig" sein, so sind noch zusätzliche Dinge zu berücksichtigen. Um hier nicht „Hand anlegen“ zu müssen, kann man auf bekannte Datenanbieter zurückgreifen an, welche routingfähige Datensets für die Oracle Datenbank bereitstellen. Die Zauberformel hier heißt: Bitte im "Oracle Delivery Format" (ODF).
Für diesen Blog verwende ich ein Demo-Datenset für die Stadt San Francisco, welches vom Datenanbieter NAVTEQ kostenfrei abgegeben wird. Zwar war ich dort noch nicht, aber Start- und Endpunkte für Testanfragen zu finden, sollte nicht so schwer sein.
Also laden Sie sich das Datenset zunächst einmal herunter. Den entsprechenden Link darauf finden Sie auf den "Oracle Spatial – Partners´ Data Downloads" Seiten.
Nach dem Auspacken finden Sie typischerweise sowohl die eigentlichen Daten als .dmp-Datei sowie Installationsanleitung und Setup-Skript.
Die Daten sollen einem eigenen DB-Benutzer zugeordnet werden. Von daher lege ich diesen erst einmal an und statte ihn mit notwendigen Rechten aus.
sqlplus system/oracle
-- Neuen Datenbank-Nutzer anlegen als SYSTEM create user navteq_sf identified by navteq_sf; -- Nutzer NAVTEQ_SF mit notwendigen Rechten ausstatten alter user NAVTEQ_SF default tablespace USERS quota unlimited on USERS; grant connect,resource,create view to navteq_sf; grant create any directory to navteq_sf; -- Ausloggen exit;So jetzt geht´s daran, das San Francisco Datenset zu importieren. Bei diesem doch relativ kleinen Datenbestand von ca. 230MB reicht der altbekannte imp-Befehl aus.
REM Importieren der Daten REM Vorher in das Verzeichnis wechseln, in welchem die Daten liegen imp navteq_sf/navteq_sf file=NAVTEQ_SF_Sample.dmp log=NAVTEQ_SF_Sample.log full=yesIm Installationsskript finden Sie Hinweise, dass anschliessend ein bisschen Postprocessing notwendig ist. Es müssen nämlich noch Darstellungsvorschriften für die spätere Visualisierung als Karte eingefügt werden. Und auch das Netzwerk ist zu registrieren sowie für eine effiziente Anfragebearbeitung zu partitionieren. Letzteres setzt übrigens nicht die Option Partitioning voraus, sondern gehört zum Funktionsumfang von Oracle Spatial und dessen NDM.
sqlplus navteq_sf/navteq_sf
-- Postprocessing wie im Installationsskript bei NAVTEQ beschrieben -- Metadaten einfügen insert into user_sdo_maps select * from my_maps; insert into user_sdo_cached_maps select * from my_cached_maps; insert into user_sdo_themes select * from my_themes; insert into user_sdo_styles select * from my_styles; commit; -- Anmelden als SYSTEM connect system/oracle -- DB Verzeichnis für die Log-Datei anlegen create or replace directory sdo_router_log_dir AS '/tmp/NAVTEQ'; -- Zugriffsrechte sowohl auf DB- als auch OS-Verzeichnis einräumen grant read, write on directory sdo_router_log_dir to navteq_sf; call dbms_java.grant_permisssdo_router_partitionion( 'NAVTEQ_SF', 'SYS:java.io.FilePermission', '/tmp/NAVTEQ/sdo_router_partition.log', 'write' ); call dbms_java.grant_permission( 'MDSYS', 'SYS:java.io.FilePermission', '/tmp/NAVTEQ/sdo_router_partition.log', 'write' ); -- Anmelden als NAVTEQ_SF -- Netzwerk einrichten -- Parameter: -- Name der Log-Datei (Default: 'sdo_router_partition.log') -- Name des Netzwerkes (Default: 'NDM_US') execute sdo_router_partition.delete_router_network('sdo_router_partition.log', 'NAVTEQ_SF_NET'); execute sdo_router_partition.create_router_network('sdo_router_partition.log', 'NAVTEQ_SF_NET'); -- Noch mal prüfen select network from user_sdo_network_metadata; -- Netzwerk partitionieren -- Parameter: -- Name der Log-Datei (Default: 'sdo_router_partition.log') -- Max. Anzahl von anzulegenden Partitionen (Default: 10000) -- Fahrseite (Default: 'R') -- Name des Netzwerkes (Default: 'NDM_US') -- Cleanup (Default: TRUE) execute sdo_router_partition.partition_router('sdo_router_partition.log',1000,'R','NAVTEQ_SF_NET'); -- Partitionen prüfen select count(*) from partition; -- Remove the directory as user SYSTEM connect system/oracle drop directory sdo_router_log_dir;Wie sieht mein soeben geladenes, registriertes und partitioniertes Netzwerk eigentlich aus?
Das überprüfe ich mit dem NDM Editor, einer Java-Anwendung, welcher im Verzeichnis $ORACLE_HOME/md/demo/network/editor liegt, sofern man die Oracle DB Examples installiert hat. Da dieser Editor "einst" für Demozwecke mit Spatial in der Oracle DB 10g entwickelt wurde, ist dessen Oberfläche schon "etwas in die Jahre" gekommen. Aber voilá, mein Netzwerk ist da.
Damit ist der 1. Teil auch schon geschafft.
Routing Engine aufsetzen
Im Gegensatz zu den Datensets (routingfähiges Netzwerk) ist die Routing Engine Bestandteil von Oracle Spatial. Über diese wird eine XML-basierter Web Service bereitgestellt, der entweder- eine individuelle Route von A nach B und für diese Informationen zu Distanz, Richtung und voraussichtlicher Fahrzeit berechnet oder
- Mehrfachrouten von A nach B, C, D, ... berechnet und für jede der ermittelten Routen die Distanz sowie voraussichtlicher Fahrzeit ausgibt.
Wenn für das Routing besondere Einschränkungen (sogenannte Netzwerk-Constraints wie z.B. gesperrte Bereiche, Abbiegeverbote) oder dynamische Kosten zu berücksichtigen sind, dann steht dafür eine Java-API bereit.
Die Routing Engine ist technisch gesehen eine J2EE Web-Anwendung, die ich auf einem WebLogic Server deployen werde. Dazu habe ich vorab über OTN den WebLogic Server 10.3.6 heruntergeladen (wls1036_dev.zip), ausgepackt und eine Domain (Name: route_domain / Port: 7001) angelegt. Hinweise für das Anlegen der Domain können der Online-Dokumentation entnommen werden.
Hinweise zum Deployment gibt es im Kapitel 13 des Oracle Spatial Developer´s Guide. Das Netzwerk hatten wir ja schon registriert. Dadurch können die Punkte 1 und 2 im Kap. 13.2 übersprungen werden. Auch die Default-Web-Seite wird im Moment nicht benötigt. Was ich jedoch benötige, ist das routeserver.ear-File aus $ORACLE_HOME/md/jlib. Hier folge ich genau der Handbuch-Beschreibung inklusive dem Kopieren von xmlparserv2.jar aus $ORACLE_HOME/LIB/ nach $routeserver.ear/web.war/WEB-INF/lib/.
Da wir für die Umwandlung von Adressen in Geokoordinaten auch einen Geocoding-Service benötigen, wird das geocoder.ear-File aus $ORACLE_HOME/md/jlib analog in die gleiche WebLogic-Domain deployed. Hinweise dazu gibt es im Kapitel 11.7 des gleichen Handbuchs.
Bevor die Admin Console des RouteServers das 1. Mal gestartet wird, um den RouteServer zu deployen, sollte noch die Speicherzuweisungen für die Java-Umgebung in $MW_HOME/user_projects/domains/route_domain/bin/setDomainEnv.sh erhöht werden. Ich habe die folgenden Werte für meine 32-bit Java Runtime Umgebung verwendet:
- -Xms512m
- -Xmx1024m
- -XX:PermSize=128m
- -XX:MaxPermSize=256m
Und jetzt kann der RouteServer gestartet werden.
cd $MW_HOME/user_projects/domains/route_domain/bin ./startWebLogic.shUm zu sehen, ob RouteServer als auch Geocoder richtig deployed sind, starte ich zunächst die Admin-Console auf der Route Domain. Einfach einen Browser öffnen und als URL http://localhost:7001/console eingeben.
Jetzt muss der RouteServer noch so konfiguriert werden, dass er auf das zuvor angelegt Straßennetz von San Francisco zugreift, um für diesen Bereich dann Routen berechnen zu können. Die Admin-Konsole kann geschlossen und der RouteServer gestoppt werden.Zum Stoppen reicht eine CTRL-C im Terminalfenster.
Die Konfigurationsdatei web.xml für den RouteServer liegt im Verzeichnis $MW_HOME/routeserver.ear/web.war/WEB-INF.
Die vorgenommenen Änderungen sind nachfolgend aufgeführt. In der Tabelle angegebene Parameterwerte bleiben unverändert.
param-name | param-value |
---|---|
routeserver_schema_jdbc_connect_string | jdbc:oracle:thin:@localhost:1521:orcl |
routeserver_schema_username | NAVTEQ_SF |
routeserver_network_name | NAVTEQ_SF_NET |
geocoder_http_url | http://localhost:7001/geocoder/gcserver |
geocoder_schema_host | localhost |
geocoder_schema_port | 1521 |
geocoder_schema_sid | orcl |
geocoder_schema_username | NAVTEQ_SF |
geocoder_schema_password | navteq_sf |
max_speed_limit | 100 |
language | German |
Hinweis: Die Parameterwerte beziehen sich auf meine Testumgebung. Gegebenenfalls müssen Sie diese für Ihre Testumgebung anpassen.
Die Konfigurationsdatei geocodercfg.xml für den Geocoder liegt im Verzeichnis $MW_HOME/geocoder.ear/web.war/WEB-INF und ist nicht ganz so umfangreich. Hier genüt es, die Datenbank-Attribute im element geocoder abzuändern.
Um alle Änderungen zu aktivieren, starte ich den RouteServer noch mal wie oben bereits beschrieben. Im Browser geben sie dann die URL http://localhost:7001/routeserver ein. Was Sie dann erhalten, ist die nachfolgend abgebildete Webseite:
Mit diesem Schritt sind alle vorbereitenden Maßnahmen abgeschlossen und der RouteServer kann wie eingangs beschrieben verwendet werden.Routen berechnen mittels XML Request und Response
Anfragen an den RouteServer werden nun als XML-Request gestellt. Ergebnisse kommen als XML-Response zurück.Jetzt können einfache (simple) als auch Batch-Anfragen gestellt werden über die vorhandenen Links. Die Angaben im XML Dokument (Request) zu Start und Ziel(en) sind dabei auf das Datenset für San Francisco anzupassen. Auch die Angaben zu den Präferenzen im Element route_request sind anpaßbar. Erläuterungen zu den gültigen Werten finden sich im Handbuch.
Nachfolgend ein Beispiel:
<?xml version="1.0" standalone="yes"?> <route_request id="10" route_preference="fastest" road_preference="local" return_driving_directions="true" distance_unit="km" time_unit="minute" return_route_geometry="true"> <start_location> <input_location id="1"> <input_address> <us_form2 street="3001 Taraval St" city="San Francisco" state="CA" zip_code="94116" /> </input_address> </input_location> </start_location> <end_location> <input_location id="2"> <input_address> <us_form1 street="3010 Geary Boulevard" lastline="san francisco, ca" /> </input_address> </input_location> </end_location> </route_request>Das Ergebnis sieht dann so aus:
Für die Spezifikation der Adressen (Element input_address) gibt es verschiedene formatierte als auch unformatierte Eingabemöglichkeiten. Detaillierte Informationen dazu finden sich in der Geocoding Request XML Schema Definition.
Für den Eistieg in das Routing mit Oracle Spatial will ich es mit diesen Ausführungen bewenden lassen. Probieren Sie es einfach aus.
P.S. Zum besseren Verständnis sind die verwendeten Umgebungsvariablen nachfolgend aufgeführt:
ORACLE_HOME=/home/oracle/app/oracle/product/11.2.0/dbhome_2
JAVA_HOME=/usr/java/latest
MW_HOME=/home/oracle/middleware
WL_HOME=/home/oracle/middleware/wlserver