Probleme mit geomunion()

Hallo,

ich bin noch ein Anfänger was PostGIS angeht und daher gibt es vielleicht eine ganz einfach Erklärung für mein Problem:

Ich möchte um eine Menge von Punkten eine konvexe Hülle bilden. Dazu gibt es die Funktion convexhull(). Laut PostGIS-Tutorial muss ich dazu zuerst mittels geomunion() die Punkte zu einer Einheit zusammenfassen. Das Problem ist jedoch, dass wenn ich den Aufruf:

select geomunion(geom) from test limit 10;

mache mein postgresql auf 100% last geht und nichts passiert. Ich habe die Anfrage auch mal mehrere Minuten laufen lassen, aber kein Ergebnis. Auch eine Veränderung der Punktzahl bringt nichts, selbst ein Punkt kann geomunion nicht zusammenfassen.
Die Tabelle sieht so aus:

gisdba=# select asewkt(geom) from test limit 3;
            asewkt            
------------------------------
 POINT(4514195 5838521 32.83)
 POINT(4514188 5838520 32.79)
 POINT(4514189 5838520 32.78)

Wenn ich die Funktion so aufrufe:

select geomunion('POINT(4514195 5838521 32.83)');

gibt es hingegen keine Probleme.

Hat jemand eine Idee wie ich das lösen kann?
Eike

Hallo!

Ich denke du must das ‘geom’ als Argument von GeomUnion() durch ein subselect oder eine andere Art der Selektion ersetzen.
Also etwa so:

select GeomUnion((select the_geom from myGeomTable where blabla ));

Gruß Uwe

Hallo Uwe,

danke für die Antwort. Leider funktioniert deine Idee nicht:

gisdba=# select GeomUnion((select geom from test limit 10 ));
FEHLER:  als Ausdruck verwendete Unteranfrage ergab mehr als eine Zeile

allerdings habe ich inzwischen festgestellt, dass GeomUnion scheinbar ein Problem damit hat wenn viele (>10000) Punkte in der Tabelle sind bzw. wenn GeomUnion mehr als diese Anzahl Punkte zusammenfügen muss.

Meine Idee ist jetzt mir so zu behelfen, dass ich zunächst immer etwa 10000 Punkte hole, die mit GeomUnion zusammenfasse und diese Unions dann nachher wieder zusammenfasse.

Jetzt belese ich mich gerade in den Postgresql und Postgis-Dokus wie ich das am sinnvollsten anstelle.
Gruß Eike

So hatte grad ein wenig Zeit zum Lesen und Testen:

select convexhull(geomunion(geom)) from fok_geom;

hat einwandfrei funktioniert mit ca 2200 Punkten, Dauer ca 22s, aber die Daten kommen aus einem View, also sollte es bei einer pysikalischen Tabelle noch etwas fixer sein. Ich such mir aber mal noch nen großen Datensatz.
Du konntes mal ein explain hier posten, dann könnte man vielleich sehen, wo es hängt.
Der Versuch, das ganze in kleine Stücke mit Union zu hacken, dürfte eher nichts bringen.
Sind die SRIDs der Punkte eigentlich alle gleich?
Gruß Uwe

Die erste Frage zuerst: Ja, die SRIDs sind alle gleich.

gisdba=# select srid(geom) from test limit 2;
 srid 
------
   -1
   -1
(2 Zeilen)

Ein EXPLAIN mit dem Befehl geomunion sagt mir:

gisdba=# explain SELECT geomunion(geom) FROM test;
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Aggregate  (cost=277212.20..277212.20 rows=1 width=29)
   ->  Seq Scan on test  (cost=0.00..244751.16 rows=12984416 width=29)
(2 Zeilen)

Ich habe selber noch ein wenig getestet und scheinbar steigt die benötigte Zeit mit der Anzahl der Punkte exponentiell:

~/ $ psql gisdba -q -c 'DROP TABLE tausend_a ;' -o /tmp/bla
~/ $ gisdba -q -c "SELECT geom INTO tausend_a FROM test LIMIT 1000 ;" -o /tmp/bla
~/ $ time psql gisdba -q -c 'SELECT geomunion(geom) FROM tausend_a ;' -o /tmp/bla
real    0m5.869s

~/ $ psql gisdba -q -c 'DROP TABLE tausend_a ;' -o /tmp/bla
~/ $ gisdba -q -c "SELECT geom INTO tausend_a FROM test LIMIT 2000 ;" -o /tmp/bla
~/ $ time psql gisdba -q -c 'SELECT geomunion(geom) FROM tausend_a ;' -o /tmp/bla
real    0m24.092s

~/ $ psql gisdba -q -c 'DROP TABLE tausend_a ;' -o /tmp/bla
~/ $ gisdba -q -c "SELECT geom INTO tausend_a FROM test LIMIT 3000 ;" -o /tmp/bla
~/ $ time psql gisdba -q -c 'SELECT geomunion(geom) FROM tausend_a ;' -o /tmp/bla
real    0m54.664s

Ich habe dann ein Script geschrieben, dass die Tabelle tatsächlich in 1000er-Stücke hackt und diese Stücke dann mittels INSERT in eine weitere Tabelle eingefügt, so dass ich eine Tabelle namens unions haben in der immer 1000 Punkte in einer Geometry zusammengefasst sind. Schließlich mache ich dann ein “SELECT geomunion(geom) FROM unions;”. Für 3000 Punkte braucht das Script dann 18 Sekunden statt wie oben gesehen 55 Sekunden.

~/ $ time sh unionpsql.sh 
real    0m17.903s

Ich kann mir das Verhalten nicht erklären, aber da ich die convexhull nur sehr selten erstellen muss denke ich, dass ich mit dem Workaround leben kann. Wenn natürlich eine bessere Lösung für das Problem existiert wäre ich natürlich trotzdem dankbar.

Ja ich habe auch festgestellt, das geomunion bzw convexhull sehr teuer ist und die Zeit exponentiell mit der Punktezahl steigt. Hatte am Freitag nur vergessen das Ergebnis zu posten… :astonished:
Wenn man die Funktion nicht oft braucht ist wohl das Anlegen einer extra Tabelle am sinnvollsten.

Gruß Uwe