Graphendatenbank: Flexible Datenabfragen mit Neo4j

Moderne IDEs bieten zwar umfangreiche Möglichkeiten für Code-Analysen, sie sind aber eingeschränkt, wenn es darum geht, projektspezifische Konstrukte zu finden. Helfen mag hier ein Ansatz, bei dem Softwarestrukturen aus Java-Anwendungen in einer Graphendatenbank eingelesen werden und der flexible Abfragen auf diesen Daten ermöglicht.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 11 Min.
Von
  • Dirk Mahler
Inhaltsverzeichnis

Mit wachsender Größe eines Softwaresystems reduziert sich schnell der Überblick über darin umgesetzte Strukturen und Muster. Moderne IDEs bieten zwar umfangreiche Möglichkeiten für Code-Analysen, sie sind aber eingeschränkt, wenn es darum geht, projektspezifische Konstrukte zu finden. Helfen mag hier ein Ansatz, bei dem Softwarestrukturen aus Java-Anwendungen in einer Graphendatenbank eingelesen werden und der flexible Abfragen auf diesen Daten ermöglicht.

Am Anfang steht die Frage nach der Modellierung der Daten. Die Graphendatenbank Neo4j stellt dafür zwei grundlegende Elemente zur Verfügung: Knoten und Beziehungen zwischen diesen. Es gibt dabei kein Schema im herkömmlichen (relationalen) Sinne, die Datenbank ist vergleichbar mit einem Whiteboard, auf das einfach alle Elemente "gezeichnet" werden.

Es ist naheliegend, Java-Sprachelemente wie Packages, Klassen, Felder und Methoden als Knoten umzusetzen. Doch wie lassen sich Typen der entstehenden Knoten voneinander unterscheiden? Neo4j bietet hierfür ein komfortables Konzept: Einem Knoten kann man eine beliebige Menge sogenannter Labels hinzufügen. Ein Java-Package würde beispielsweise mit dem Label PACKAGE markiert werden, Methoden und Felder entsprechend mit METHOD und FIELD.

Etwas komplizierter gestaltet sich die Situation bei Klassen. Diese werden durch .java- beziehungsweise .class-Dateien repräsentiert und stellen immer einen Java-Typen dar, der aber unterschiedliche Ausprägungen haben kann: Klasse, Interface, Enumeration oder Annotation. Die Lösung liegt in der Formulierung des vorhergehenden Satzes: Es wird ein Knoten erzeugt, der mit dem Label TYPE und einem näher spezifizierenden Label, also entweder CLASS, INTERFACE, ENUM oder ANNOTATION, versehen ist.

Die Präsenz eines Labels impliziert das Vorhandensein spezieller Eigenschaften eines Knotens. Jeder Java-Typ besitzt beispielsweise einen voll qualifizierenden Namen und eine Sichtbarkeit. Diese werden als benannte Properties (z. B. FQN, VISIBILITY) des Knotens mit den entsprechenden Werten (java.lang.Object, public) gespeichert. Darüber hinaus kann ein Java-Typ aber auch Methoden deklarieren. Existiert also an einem Knoten ein TYPE-Label, ist zu erwarten, dass er (gerichtete) Beziehungen zu anderen Knoten besitzt, die mit dem Label METHOD versehen sind. Die Beziehungen selbst sind typisiert, im vorliegenden Fall ist dafür DECLARES naheliegend.

Besitzt der TYPE-Knoten darüber hinaus ein weiteres Label CLASS, existiert von ihm ausgehend immer genau eine Beziehung EXTENDS zu einem Knoten, der die Superklasse, des Java-Typen repräsentiert (z. B. java.lang.Object). Etwas allgemeiner ausgedrückt wird also das Schema eines Knotens durch die Menge seiner Labels bestimmt. Die Abbildung 1 veranschaulicht eine – zugegebenermaßen einfache – Java-Klasse und einen Ausschnitt aus dem entsprechenden Graphen-Modell.

Java-Strukturen als Graph mit Knoten, Beziehungen, Labels und Properties (Abb. 1)

Die Bedeutung der bisher nicht beschriebenen Labels, Properties und Beziehungen sollte schnell zu erfassen sein. An der Stelle sei noch einmal darauf hingewiesen, dass die Daten in dieser Repräsentation gespeichert und wieder zugänglich gemacht werden – es gibt keine weiteren technischen Hilfskonstrukte wie Fremdschlüsselbeziehungen.