Nested-Sets sind für normale Baumstrukturen super, aber wenn man etwas flexibler sein möchte und z.B. ein Item in mehreren Kategorien haben möchte oder eine Kategorie auch als Kind-Element von z.B. einer Angebots-Kampanie, ist man schon nicht mehr bei einem Baum sondern bei einem Netz. Nun hier Eltern-Elemente zu finden und zu wissen in welchen Kategorien ein Item sich befindet ist etwas aufwendiger.
CREATE TABLE exp_structure(
ID int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
NAME VARCHAR(255) NOT NULL,
TYPE VARCHAR(255) NOT NULL,
PRIMARY KEY(ID)
);
CREATE TABLE exp_links(
ID_PARENT int(11) UNSIGNED NOT NULL,
ID_CHILD int(11) UNSIGNED NOT NULL,
IS_SHADOW_LINK int(1) DEFAULT 0,
REFCOUNT int(1) DEFAULT 0,
PRIMARY KEY(ID_PARENT, ID_CHILD)
);
Damit man nun schnell herausfinden kann wird, beim Anlegen eines Items in der Struktur wird nicht nur ein Link auf das direkte Parent-Element gesetzt sondern werden auch rekursiv alle weiteren Parent-Element aufgerufen und ein Shadow-Link darauf gesetzt. Dieser Shadow-Link besagt, dass das Item nicht direkt am Parent-Element hängt sondern Subelement zugeordnet ist. In der Oberfläche sind mit Shadow-Links verlinkte Items also nicht anzuzeigen.
Ist ja erst einmal ganz einfach. Wenn ich nun aber z.B. ein Item mit 2 Parent-Elementen habe, muss man wenn man weiter nach oben in die Hierarchie kommt darauf achten, dass man nicht mehrere Shadow-Links setzt. Das ist an sich auch kein großes Problem. Schwierig wird wenn man ein Item entfernt und die Shadow-Links entfernen muss. Bei jedem Shadow-Link müsste man prüfen, ob er durch einen weiteren Pfad noch verwendet wird oder nicht. Dafür gibt die REFCOUNT... ja genau.. wie im Garbage Collector. Wenn man ein Shadow-Link setzten soll, dieser aber schon existiert zählt man Counter hoch. Beim Entfernen zählt man einfach alle Shadow-Links des Pfades runter und entfernt dann alle die auf 0 stehen, weil man dann sicher ist, dass dieser Shadow-Link nicht noch von einem anderen Pfad verwendet wird.
Wenn man noch einzelne Nodes oder Relations hat, kann man eine Summe schnell und einfach mit sum() berechnen. Wenn man aber schon eine Collection vorliegen hat oder komplexere Berechnungen ausführen möchte, hilft hier die
reduce() Funktion.
Die an sich wie eine kleine Schleife arbeitet und einen Ausdruck auf jedes
Element einer Collection ausführt.
Das man eine direkt eine Collection erhält, kann ganz schnell der Fall sein. Gerade wenn man mit variablen Path Längen arbeitet.
MATCH p = (start:entity{id:4})-[:relates_to*1..10]->(end:entity{id:100})
RETURN p
hier erhält man alle Relations bis zu einer Anzahl von 10, die einen Path zwischen start und end bilden.
Will man nun Gewichtungen an den Relations zusammen rechnen, damit nicht nur die Anzahl der Relations als Bewertung genutzt werden kann, kommt reduce() zum Einsatz.
Mit so einem Prinzip kann man auch reale Wege mit Meter-Angaben zwischen Stationen und Wegpunkten und Neo4j abbilden.
MATCH p = (start:entity{id:4})-[rels:relates_to*1..10]->(end:entity{id:100})
RETURN reduce(weight=0, r in rels) | weight + r.weight) AS total_weight
Wenn man nicht möchte, dass ein CodeMirror Eingabefeld unkontrolliert in die Breite wächst und statt desen Scroll-Balken zeigt, hilft dieses CSS:
<style type="text/css">
.CodeMirror{
width:99%;
max-width:700px;
border:1px solid #000000;
}
</style>
Ich habe gestern Abend mal eine Animation so wohl als animiertes GIF als auch WebM ausgegeben.
Der Unterschied in der Dateigröße ist schon enorm.
Wenn man also überlegt, ob man auf der eigenen Seite Animationen als GIF oder WebM (selbst der neue Edge wird es unterstützen) nimmt, ist WebM wohl die beste Wahl. Damit es sich wie ein GIF verhält muss man es so einbinden:
<video src="ani.webm" autoplay loop mute></video>
Das man in einer PHP-Seite mal in eine Exception läuft ist ja nicht schlimm, nervig ist nur, wenn man merkt, dass diese Exception wiederum aus einen catch-Block stammt und man erst einmal Debuggen muss, um an die original Exception zukommen und den wirklichen Fehler zu sehen.
try{
$a = 1* array(2,3);
}
catch(Exception $e){
throw new Exception("something went wrong");
}
Man sollte immer, wenn es mögich ist, die original Exception mit an die eigene Exception ran hängen.
try{
$a = 1* array(2,3);
}
catch(Exception $e){
throw new Exception("something went wrong", 0, $e);
}