[Oracle] Wer kennt wen über wen? Pfade in einem Graph auflisten
Hallo und herzlich willkommen! Tutorials.de ist eine Hilfe-Community mit dem Motto User helfen Usern. Als Gast verfügst Du über Schreibrechte in unseren Foren und Blogs. Du kannst dich aber gerne auch kostenlos registrieren und Teil unserer Gemeinschaft werden! Viel Spaß & Erfolg bei der Vermehrung deines Wissens :-)
Themen: 242.975 | Beiträge: 1.352.293 | Mitglieder: 169.418 (Stand 28.01.10) | Fragen zur Nutzung von Tutorials.de? Nutzungsregeln | Kontaktformular | Impressum
AW: [Oracle] Wer kennt wen über wen? Pfade in einem Graph auflisten
Schwierig wird das ganze, wenn man lieber eine nur eine Tablle mit zusammengesetzten Primärschlüssel aus UserID und FreindID verwenden will... Bei www.lokalisten.de werden einem nur die Freunde eines Freundes angezeigt, das war es dann auch schon. Es scheint wohl nicht so einfach zu sein.
__________________
Mein neues Projekt: zandman.de - Bericht über den Aufbau einer Entwicklungsumgebung für Test-Driven-Development mit phpUnderControl und dem Aufbau einer Webapplikation mit Zend Framework Version 1.9.x
AW: [Oracle] Wer kennt wen über wen? Pfade in einem Graph auflisten
Die Frage "Wer kennt wen über wen?" ist nüchtern betrachtet, nichts anderes als ein extrem einfacher Pathfinding Algorithmus. Das schöne daran ist, dass übliche Parameter wie "Wegekosten" o.ä. wegfallen und nur die Anzahl der Knoten bis zum Ziel entscheidend für die kürzeste Strecke sind. Daher eignet sich hier das rekursive SQL ("connect by") von Oracle sehr gut.
Rein aus Interesse habe ich mich mal an den wohl bekanntesten Pathfinding Algorithmus (A*) gemacht und in PL/SQL umgesetzt:
Als Grundlage dient mir ein Koordinatensystem mit fixen Orten, dargestellt durch folgende Tabelle und INSERTS
Code:
0 1 2 3 4 5 6 7 8 9101112
0A B
1 H
2 C
3 D
4 F I
5E
6 G
7 K
8 J N
9 M
10 L
11 O
12
CREATE TABLE places
(
placeid NUMBER(10,0) CONSTRAINT NN_places_id NOT NULL,
name VARCHAR2(30) CONSTRAINT NN_places_name NOT NULL,
posx NUMBER(10,0) CONSTRAINT NN_places_posx NOT NULL,
posy NUMBER(10,0) CONSTRAINT NN_places_posy NOT NULL
);
ALTER TABLE places
ADD CONSTRAINT PK_places
PRIMARY KEY ( placeid )
USING INDEX;
INSERT INTO places VALUES( 1, 'A', 0, 0 );
INSERT INTO places VALUES( 2, 'B', 4, 0 );
INSERT INTO places VALUES( 3, 'C', 6, 2 );
INSERT INTO places VALUES( 4, 'D', 2, 3 );
INSERT INTO places VALUES( 5, 'E', 0, 5 );
INSERT INTO places VALUES( 6, 'F', 5, 4 );
INSERT INTO places VALUES( 7, 'G', 7, 6 );
INSERT INTO places VALUES( 8, 'H', 9, 1 );
INSERT INTO places VALUES( 9, 'I', 11, 4 );
INSERT INTO places VALUES( 10, 'J', 9, 8 );
INSERT INTO places VALUES( 11, 'K', 3, 7 );
INSERT INTO places VALUES( 12, 'L', 5, 10 );
INSERT INTO places VALUES( 13, 'M', 1, 9 );
INSERT INTO places VALUES( 14, 'N', 12, 8 );
INSERT INTO places VALUES( 15, 'O', 7, 11 );
Die einzelnen Orte sind untereinander mit Strassen verbunden. Als zusätzliche Information werden die Wegekosten abgelegt. In meinem Fall wurden sie einfach über die Länge der Strecke berechnet. Ich gehe also davon aus, dass ich auf allen Strecken gleich schnell voran komme, keine Steigungen o.ä. vorhanden sind etc..
Code:
CREATE TABLE roads
(
sourceid NUMBER(10,0) CONSTRAINT NN_roads_source NOT NULL,
targetid NUMBER(10,0) CONSTRAINT NN_roads_target NOT NULL,
cost NUMBER(5,0) CONSTRAINT NN_roads_cost NOT NULL
);
ALTER TABLE roads
ADD CONSTRAINT PK_roads
PRIMARY KEY ( sourceid, targetid )
USING INDEX;
CREATE UNIQUE INDEX idx_roads_inv
ON roads ( targetid, sourceid );
INSERT INTO roads VALUES ( 1, 4, 10 );
INSERT INTO roads VALUES ( 9, 14, 15 );
INSERT INTO roads VALUES ( 10, 14, 10 );
INSERT INTO roads VALUES ( 14, 15, 25 );
INSERT INTO roads VALUES ( 12, 15, 5 );
INSERT INTO roads VALUES ( 13, 12, 15 );
INSERT INTO roads VALUES ( 13, 5, 15 );
INSERT INTO roads VALUES ( 5, 4, 7 );
INSERT INTO roads VALUES ( 8, 9, 12 );
INSERT INTO roads VALUES ( 8, 3, 10 );
INSERT INTO roads VALUES ( 3, 4, 15 );
INSERT INTO roads VALUES ( 3, 2, 7 );
INSERT INTO roads VALUES ( 1, 2, 15 );
INSERT INTO roads VALUES ( 7, 10, 7 );
INSERT INTO roads VALUES ( 6, 7, 7 );
INSERT INTO roads VALUES ( 7, 11, 15 );
INSERT INTO roads VALUES ( 11, 5, 13 );
INSERT INTO roads VALUES ( 8, 7, 23 );
Daraus ergibt sich dann folgende Karte:
(siehe Anhang...)
Der Algorithmus selbst benötigt 2 temporäre Tabellen zur Berechnung:
Code:
CREATE GLOBAL TEMPORARY TABLE freelist (
placeid NUMBER(10,0),
parentid NUMBER(10,0),
abscost NUMBER(10,0),
calccost NUMBER(10,0),
CONSTRAINT PK_FREELIST
PRIMARY KEY ( placeid )
USING INDEX
);
CREATE GLOBAL TEMPORARY TABLE locklist (
placeid NUMBER(10,0),
parentid NUMBER(10,0),
abscost NUMBER(10,0),
calccost NUMBER(10,0),
CONSTRAINT PK_LOCKLIST
PRIMARY KEY ( placeid )
USING INDEX
);
Die Funktionsweise des A* Algorithmus möchte ich hier nicht erläutern, das würde den Rahmen sprengen, darum hier einfach der Sourcecode meines Packages:
sql Code:
CREATEORREPLACEFUNCTION CALCCOSTS( sourceid IN places.placeid%TYPE,
AW: [Oracle] Wer kennt wen über wen? Pfade in einem Graph auflisten
Zitat:
Zitat von Thomas Darimont
Deshalb trägt der Thread ja auch die Kennzeichnung [Oracle] Weiterhin ist im Link im ersten Post gezeigt wie man diese Aufgabe auch mit MySQL lösen kann.
Damit hast du wohl Recht. Sry nicht gesehen. Ich dachte es geht jetzt nur um mysql.
Hmm, was das Beispiel angeht - Damit komme ich irgendwie nicht ganz klar. Bin selber dabei eine Lösung zu finden. Bin bereits soweit gekommen, dass ich eine Person zwischen zwei Personen bestimmen kann. Wobei die Lösung mehr oder weniger mit php umgesetzt wurde, mit array Funktionen. Würde mich freuen wenn jemand aus diesem Forum mal ein Script speziell für mysql entwickeln könnte.
AW: [Oracle] Wer kennt wen über wen? Pfade in einem Graph auflisten
Hallo,
Zitat:
Hmm, was das Beispiel angeht - Damit komme ich irgendwie nicht ganz klar. Bin selber dabei eine Lösung zu finden. Bin bereits soweit gekommen, dass ich eine Person zwischen zwei Personen bestimmen kann. Wobei die Lösung mehr oder weniger mit php umgesetzt wurde, mit array Funktionen. Würde mich freuen wenn jemand aus diesem Forum mal ein Script speziell für mysql entwickeln könnte.