Entwurf und Realisierung einer relationalen Datenbank für die Darstellung kombinatorischer Bibliotheken in der Biochemie Mohammad Reza Jafari Diplomarbeit am Institut für Informatik III Rheinische Friedrich-Wilhelms-Universität Bonn Gutachter: Prof.Dr.Rainer Manthey Inhaltsverzeichnis 1 Einleitung 1 2 Mathematisch-Chemische Grundlagen 2.1 Biochemischer Hintergrund . . . . . . . . . . . . . . . . . . . 2.2 Elementare Begriffe der Graphentheorie . . . . . . . . . . . . 2.2.1 Darstellungsformen für Graphen . . . . . . . . . . . . 2.2.2 Suchalgorithmen für Graphen . . . . . . . . . . . . . . 2.3 Darstellung Chemischer Strukturen als Graph . . . . . . . . . 2.3.1 Darstellung kombinatorischer Bibliotheken als Graph . 2.4 Subgraphisomorphismus . . . . . . . . . . . . . . . . . . . . . 2.5 Darstellung chemischer Strukturen als ASCII-Dateien . . . . 2.5.1 Das (C)SLN-Dateiformat . . . . . . . . . . . . . . . . 2.6 Kombinatorische Bibliotheken im Protein-Ligand-Docking . . 2.6.1 Das Docking-Programm FlexX . . . . . . . . . . . . . 2.6.2 Das FlexX-Modul FlexXC . . . . . . . . . . . . . . . . 3 Datenbank-Grundlagen 3.1 Datenbankmodellierung . . . . . . . . . . . . . . . . 3.1.1 Das Entity-Relationship-Modell . . . . . . . . 3.1.2 Das relationale Datenmodell . . . . . . . . . 3.1.3 Abbildung des Entity-Relationship-Modells in 3.2 Relationale Anfragesprachen . . . . . . . . . . . . . . 3.2.1 Relationenalgebra und Relationenkalkül . . . 3.2.2 SQL . . . . . . . . . . . . . . . . . . . . . . . 3.3 Das Oracle DBMS . . . . . . . . . . . . . . . . . . . 3.3.1 Objekt-Relationale Konzepte in Oracle . . . . 3.3.2 Oracle Data-Cartridges . . . . . . . . . . . . . . . . . . . . . . . . 4 4 6 7 7 8 9 10 11 11 13 13 14 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . das relationale Datenmodell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 16 17 19 19 20 21 22 27 28 29 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Modellierung kombinatorischer Bibliotheken 4.1 Konzeptueller Entwurf . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Modellierung eines chemischen Moleküls . . . . . . . . . . . 4.1.2 Modellierung der kombinatorischen Natur der Bibliotheken 4.2 Logischer Entwurf . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Darstellung von Entitytypen als Relationen . . . . . . . . . 4.2.2 Darstellung von Relationshiptypen als Relationen . . . . . . 4.3 SQL-Implementierung . . . . . . . . . . . . . . . . . . . . . . . . . i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 31 32 33 37 37 37 39 INHALTSVERZEICHNIS 5 Die Programmierumgebung 5.1 FlexX-Datenstrukturen für kombinatorische Bibliotheken 5.2 Das Python-Modul pyflexx . . . . . . . . . . . . . . . . . 5.2.1 Die Programmiersprache Python . . . . . . . . . . 5.2.2 Python Database API . . . . . . . . . . . . . . . . 5.2.3 Interne Kommunikation in FlexX über STREAM s ii . . . . . 43 43 46 46 47 48 . . . . . 49 49 49 50 53 54 7 Evaluierung 7.1 Views zum Subgraphisomorphismus . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Vergleich von Suchergebnissen mit und ohne Datenbank . . . . . . . . . . . . . . 58 58 68 8 Zusammenfassung und Aussichten 73 . . . . . . . . . . . . . . . 6 Implementierung 6.1 Füllen der statischen Tabelle Atomtype . . . . . . . . . . . . . . 6.2 Zugriff auf die Bibliotheksdaten in den FlexX-Datenstrukturen 6.2.1 Moleküldaten . . . . . . . . . . . . . . . . . . . . . . . . 6.2.2 clib molecule Daten . . . . . . . . . . . . . . . . . . . . 6.3 Datenimport in die Datenbank . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kapitel 1 Einleitung Stoffwechselprozesse im Körper werden durch eine Vielzahl von Molekülen - meistens Proteine reguliert. Wenn diese Prozesse fehlerhaft ablaufen, zum Beispiel durch die Wirkung von Viren, Bakterien oder Autoimmunprozessen, entstehen Krankheiten. Diese kann man medikamentös behandeln, in dem mit Hilfe von Wirkstoffmolekülen Einfluss auf die oben genannten Regulatoren genommen wird. Die Suche nach neuen Medikamenten ist somit zunächst die Suche nach geeigneten Wirkstoffmolekülen [H.J96]. Am Beginn dieser Suche nach neuen Wirkstoffmolekülen steht die Identifizierung der defekten Regulatoren, also der Enzyme bzw. Proteine. Dann sucht man nach kleineren Molekülen, sog. Liganden, die sich stark genug an das sog. Ziel-Molekül/Protein binden können. Dies setzt die geometrische und chemische Komplementarität der beiden beteiligten Moleküle voraus. Das Ergebnis dieser Suche sind sog. Leitstrukturen, die bereits hinreichend starke Wechselwirkung zeigen, jedoch noch im Hinblick auf einige physische und chemische Eigenschaften optimiert werden müssen, damit sie die weiteren Vorraussetzungen eines Medikamentes erfüllen können. In der letzten Phase, der klinischen Untersuchung, wird der Wirkstoff an Patienten erprobt. Erst dann kann der Wirkstoff als neues Medikament zugelassen werden. Für die Suche nach Leitstrukturen können experimentelle oder virtuelle Methoden oder auch eine Kombination aus beiden eingesetzt werden [Cla01, Rar01]. Bei der experimentellen Suche werden bekannte Verbindungen auf die gewünschte Wirkung getestet. Dazu werden große Bibliotheken mit Millionen von Verbindungen mit Hilfe von Roboteranlagen automatisch getestet. Diese Methode ist unter dem Namen High-Throughput-Screening (HTS ) bekannt. Bei der virtuellen Suche gibt es zwei Szenarien: entweder kennt man bereits - über experimentelle Methoden wie Röntgenkristallographie oder NMR Spektroskopie - die Struktur der Proteine und versucht die Liganden zu finden, die sowohl geometrisch als auch chemisch zu dem Protein passen (das Docking Problem) oder man kennt die Struktur nicht und versucht durch einen Vergleich mit einem bereits bekannten Liganden Rückschlüsse zu ziehen und diesen als Leitstruktur für einen neuen Wirkstoff zu nutzen (die ligand-basierte Suche). In der virtuellen Suche liegen die Informationen über Verbindungen in elektronischer Form vor. Somit können sie zur Suche nach geeigneten Strukturen bei virtuellen Verfahren eingesetzt werden, die virtuelles Screening genannt werden. 1 KAPITEL 1. EINLEITUNG 2 Die HTS -Methode hat einige Nachteile [Cla01]. Ein wesentlicher Nachteil ist, daß alle Verbindungen, die getestet werden sollen auch verfügbar sein müssen. Dazu müssen sie entweder synthetisiert oder gekauft und für spätere Tests gelagert werden, wobei sich die Moleküle während der Lagerung nicht verändern dürfen. Außerdem können Verunreinigungen und Nebenreaktionen zu fehlerhaften Ergebnissen führen. Der größte Vorteil virtueller Verfahren ist somit, daß die Moleküle nicht real existieren müssen. Stattdessen werden lektronisch gespeicherte Daten genutzt. Diese liegen in der Regel in Form von ASCII-Dateien vor. Nur in Ausnahmefällen sind diese Informationen über die Verbindungen auch in Datenbanken repräsentiert. Damit braucht man vor allem keine Verbindungen zu kaufen, zu synthetisieren und zu lagern. Deshalb sind die Kosten solcher Verfahren wesentlich geringer. Aufgrund der hohen Komlexität der Problemstellung müssen virtuelle Verfahren gezwungenermassen vereinfacht werden und können Messsungen nicht ersetzen. Virtuelle Methoden können zur Vorauswahl von geeigneten Verbindugen eingesetzt werden, die später synthetisiert und getestet werden sollen. Die zum HTS notwendigen Molekülbibliotheken werden durch Sammlung aller Verbindungen erstellt, die während der pharmazeutischen Forschung synthetisiert wurden [Rar01, Cla01]. Bei dieser Methode werden einerseits die Daten- bzw. Substanzmengen immer größer und andererseits kommt es innerhalb dieser Datenmengen zu einem Mißverhältnis bei der Repräsentation der Molekülklassen. Einige Klassen sind überrepräsentiert während andere wiederum gar nicht oder kaum vertreten sind. Letzteres Problem wurde bis vor wenigen Jahren durch gezieltes Hinzukaufen von Verbindungen gelöst. In der Größe der Datenmenge und dem Mißverhältnis bei der Molekülklassenrepräsentation liegen also die wesentlichen Nachteile dieser Methode. Während der letzten Jahre konnte sich zur Erzeugung großer Molekülbibliotheken mit strukturell verwandten Molekülklassen eine alternative Technologie etablieren: die kombinatorische Chemie. Bei dieser Technologie werden ausgewählte Baukästen, die jeweils eine Menge von Alternativfragmenten enthalten, in unterschiedlicher Kombinationen mittels chemischer Standardreaktionen der Reihe nach aneinander gehängt und zusammenfügt. So lassen in kürzester Zeit eine große Anzahl strukturell verwandter Substanzen erzeugen. Im Laufe der rasanten Entwicklung der kombinatorischen Chemie und der Screening-Verfahren wurde ein neues Szenario für das virtuelle Screening geboren [MR00]. Anders als zu der Zeit, in der man sich auf die Analyse großer Bibliotheken von Verbindungen stützte, wird heutzutage die Kombination mehrerer großer, falls möglich virtueller Bibliotheken dazu verwendet. Die Anwendung virtueller Bibliotheken führt zu neuen Suchproblemen auf dem Gebiet des virtuellen Screening, vor allem da die Anzahl der gesuchten Verbindungen zur Kombination im Vergleich zu den klassischen Methoden erheblich größer wurde. Der Vorteil liegt aber darin, daß dadurch die Suchzeit reduziert werden kann. Für die Suche in einer Menge unstruktuierter Verbindungen müssen alle Moleküle unabhängig voneinander analysiert werden. Kombinatorische Bibliotheken dagegen besitzen einen struktuierten Aufbaumechanismus durch eine bestimmte Anzahl von Baublöcken. Daher können Informationen von anderen, schon analysierten Molekülen für ein neues Molekül genutzt werden. Die kombinatorischen Bibliotheken werden zur Zeit unter anderem in Form von ASCII-Datein oder als enumerierte Moleküle repräsentiert [Cla04]. Letztere eignet sich besser zur Suche innerhalb der Bibliotheken, hat aber den Nachteil, daß die Molekülzahl sehr groß ist und daher die Suche unter ihnen zeitlich nicht effizient ist. KAPITEL 1. EINLEITUNG 3 Aus diesem Grund ist eine Repräsentation in kombinatorischen Bibliotheken wünschenswert, die auf der einen Seite kompakt und auf der anderen Seite gut durchsuchbar ist. Eine Alternative kann ein geeignetes Datenbank-Schema für kombinatorische Bibliotheken sein. Das Ziel dieser Arbeit ist daher die Entwicklung eines solchen Schemas, das die kombinatorische Natur von kombinatorischen Bibliotheken nutzt und diese in einer geschlossenen Form mit minimaler Redundanz ablegt. Die Vorteile dieser Vorgehensweise ist, daß so einerseits nicht alle Moleküle abgelegt werden müssen und damit Platz gespart wird und andererseits die Suche beschleunigt wird, da man nicht alle Bibliotheksmoleküle - also alle Fragmentkombinationen - durchsuchen muss, sondern nur die Fragmente selbst. Eine Datenbank für kombinatorische Bibliotheken kann in mehreren Anwendungsfeldern benutzt werden [Cla04], unter anderem bei der ligand-basierten Suche nach Wirkstoffmolekülen oder beim Vergleichen zwischen verschiedenen kombinatorischen Bibliotheken zur Auswahl der jenigen mit bestimmten Substrukturen. Die vorliegende Arbeit wurde im Rahmen einer Kooperation zwischen der Arbeitsgruppe Intelligente Datenbanken von Prof. Dr. Rainer Manthey vom Institut für Informatik III der Rheinischen Friedrich-Wilhelms-Universität Bonn und der Firma BioSolveIT durchgeführt. Die Firma BioSolveIT ist ein in den Bereichen Bio- und Chemieinformatik tätiges Unternehmen, die im Jahre 2001 als Spin-Off der Arbeitsgruppe von Professor Lengauer am GMD-Institut SCAI (heute Fraunhofer Gesellschaft) gegründet wurde. Sie entwickelt und vermarktet Software für die pharmazeutische Industrie und biotechnologische Unternehmen. Die Firma BibSolveIT entwickelte das Tool FlexX [G.K96], das im strukturbasierten Wirkstoffdesign eingesetzt wird. Ausgehend von der 3-dimensionalen Struktur des Proteins kann mit Hilfe von FlexX die Geometrie von Protein-Liganden Komplexen vorhergesagt werden. Dieses Tool verfügt über das zusätzliche Modul FlexXC , das es erlaubt, die kombinatorische Natur kombinatorischer Bibliotheken effizient beim Docking auszunutzen. FlexXC besitzt bereits Datenstrukturen, um kombinatorische Bibliotheken in geschlossener Form kompakt abzulegen, eine effiziente Suche innerhalb von kombinatorischen Bibliotheken ist damit jedoch zur Zeit noch nicht möglich. In der vorliegenden Arbeit verwende ich die FlexXC Datenstrukturen als Ausgangsbasis. Damit erübrigt sich das Schreiben eines Parsers für die ASCII-Dateien, da diese bereits in FlexXC vorliegen. In Kapitel 2 werden die mathematisch-chemischen Grundlagen erläutert, deren Verständnis für den Rest dieser Arbeit notwendig ist. Zusätzlich wird hier das Prinzip der kombinatorischen Bibliotheken vorgestellt, auf die diese Arbeit basiert. Kapitel 3 enthält eine allgemeine Einführung in die Datenbankmodellierung. Dort werden Techniken zum Aufbau einer Datenbank und deren Manipulation erläutert. Am Ende des Kapitels wird das Datenbank Management System Oracle vorgestellt, das in dieser Arbeit verwendet wurde. Die im Kapitel 3 diskutierten Modellierungstechniken werden im Kapitel 4 für kombinatorische Bibliotheken umgesetzt. In Kapitel 5 wird die Programmierumgebung dieser Arbeit vorgestellt. Die Art und Weise, wie die Informationen der ASCII-Dateien aus den FlexX-Datenstrukturen für kombinatorischen Bibliotheken in die Datenbank importiert werden, wird in Kapitel 6 erörtert. In Kapitel 7 werden zunächst die Views zur Substruktursuche vorgestellt. Die Ergebnisse dieser Substruktursuche werden dann anhand realer Daten dokumentiert und mit den Ergebnissen von FlexX verglichen. Am Ende schließt eine Zusammenfassung und ein Ausblick auf mögliche Erweiterungen die Arbeit ab. Kapitel 2 Mathematisch-Chemische Grundlagen In der vorliegenden Arbeit geht es um kombinatorische Bibliotheken, die aus Molekülen bestehen. Diese bedürfen einer geeigneten Repräsentation. Besonders geeignet für diese Darstellung sind Graphen. Zuerst sollen die kombinatorischen Bibliotheken und ihr Inhalt - die Moleküle - vorgestellt werden. Danach werden die Graphen als Darstellungsform eingeführt und gezeigt, wie man die chemischen Strukturen mit ihrer Hilfe repräsentieren kann. Schließlich wird das Programm FlexX und dessen Handhabung von Molekülen in kombinatorischen Bibliotheken thematisiert. Zunächst werden einige wichtige biochemische Begriffe vorgestellt, deren Verständnis für das weitere Vorgehen innerhalb dieses Kapitels und der gesamten Arbeit unverzichtbar ist. Eine ausführliche Beschreibung der gesamten Thematik ist zum Beispiel in [H.J96, PK94, Alb90] zu finden. 2.1 Biochemischer Hintergrund Moleküle bestehen aus Atomen, die durch kovalente Bindungen miteinander verbunden sind. Im Organismus kommen die Atome Wasserstoff (H), Kohlenstoff (C), Stickstoff (N), Sauerstoff (O), Phosphor (P) und Schwefel (S) am häufigsten vor. Der Typ der Atombindung hängt von der Art der Interaktion zwischen den beteiligten Atomen und den freien Valenzen ab. Die Bindungen können als Einfach-, Mehrfach- und aromatische Bindungen vorkommen. Da einfache Atombindungen leicht um die eigene Achse rotieren können, sind bei einem solchen Molekül viele verschiedene Konformationen, also räumlichen Strukturvarianten möglich. Größere Moleküle enstehen durch die Kombination kleinerer Moleküle. Diesen Vorgang der Verbindung nennt man Reaktion. Bei der Reaktionen werden Atombindungen in beiden Molekülen aufgebrochen und eine neue Bindung zwischen den Molekülen gebildet. Es werden also von beiden Molekülen Atome abgespalten und an den Bruchstellen entsteht die neue Bindung zwischen den Molekülen. Die Reaktionen finden nicht an beliebigen, sondern an bestimmten, prädisponierten Bindungen im Molekül statt. Die kombinatorische Chemie beruht auf dem Prinzip, daß mit einem Reaktionsschema viele Moleküle, die alle dieselbe spezifische Atombindung enthalten, untereinander verknüpft werden können [Cla04]. Die entstandene Moleküle sind strukturell verwandt und enthalten in der Regel 4 KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 5 Abbildung 2.1: Schematischer Aufbau einer kombinatorischen Bibliothek mit dem Kern K und den R-Gruppen R1-R4. ein Kerngerüst, das bei allen entstandenen Molekülen gleich ist [Rar01]. Dieses bezeichnet man als Kern (engl. core) (Abbildung 2.1). Mit diesem Kern sind an verschiedenen Positionen, den sog. R-Gruppen, alternative Molekülfragmente verknüpft. Von einem abstrakten Standpunkt betrachtet bilden der Kern und die Fragmente eine Art Baukasten, aus der sich kombinatorisch eine große Zahl von Molekülen zusammensetzen läßt. Der große Vorteil ist daher, daß man aus einer kleinen Menge von Grundverbindungen eine große Anzahl von Molekülen zusammensetzen kann, die alle einer gewissen Aufbaustrategie folgen. Eine kombinatorische Bibliothek ist also ein Reaktionsschema plus einer Menge von verknüpfbaren Molekülen oder abstrakter ausgedrückt sie ist eine Menge von alternativen Fragmenten pro R-Gruppe sowie eine Verknüpfungsregel [Cla04]. Die Fragmente der R-Gruppen in kombinatorischen Bibliotheken werden auch als Teilmoleküle bezeichnet weil es in diesen Fragmente Atome gibt, über die beim Zusammenbauen der Bibliotheksmoleküle solche Fragmente mit anderen Fragmenten verknüpft werden können [Rar01]. Die Art und Weise der Verknüpfung solcher Fragmente wird in den meisten anwendungsrelevanten Fällen über die Struktur bestimmt, auf die die kombinatorische Bibliothek aufgebaut ist. Darauf wird im Abschnitt (2.3.1) ausführlicher eingegangen. Die Produkträume auf der Basis von Multikomponentenreaktionen in der kombinatorischen Chemie sind um Größenordnung mächtiger als alle derzeit existierenden Strukturdatenbanken zusammen, so daß man bis zu 1014 verschiedene Produkte aus etwa 500 Alternativfragmenten erreichen kann [BK97]. Derartige Mengen von chemischen Strukturen kann man nicht mit klassischen Datenbanken verwalten. Da später kurz auf FlexX eingegangen wird, werden im Folgenden einige weitere Begriffe vorgestellt, die in diesem Zusammenhang wichtig sind: Proteine sind große Moleküle, deren Entstehung ebenfalls auf dem Prinzip der Kombination einer definierten Menge von Komponenten beruht. Sie bestehen aus einer Kette mit einer Kombination von 20 verschiedenen Bausteinen, den Aminosäuren, die über kovalente Bindungen miteinander verbunden sind. Dieser Art der Atombindung ist als Peptidbindung bekannt. Proteine können sich an andere, kleinere Moleküle legen und mit ihnen in Wechselwirkung treten. Diese Bindungen sind in manchen Fällen sehr fest, in anderen Fällen aber schwach. In allen Fällen aber sind sie sehr spezifisch, so daß nur einige wenige Molekülen aus der Umgebung des Proteins eine solche Bindung eingehen können. Voraussetzung dafür ist, daß die beteiligten Partner chemisch und geometrisch komplementär zueinander sein müssen wie ein Schlüssel zum KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 6 entsprechenden Schloß das Schlüssel-Schloß Prinzip). Ligand ist die Bezeichnung für den kleineren Bindungspartner eines Komplexes. Im Prinzip können es beliebige Moleküle sein, in der Wirkstoffentwicklung sind jedoch meist nur Moleküle mit höchstens rund hundert Atomen interessant. Im Gegensatz zu Proteinen besitzen Liganden - aufgrund der hohen Zahl ihrer Konformationsmöglichkeiten - sehr flexible Strukturen, die bei der Anpassung an das Protein berücksichtigt werden müssen. Eine Bindetasche ist diejenige Region eines Proteins, in die ein spezifischer Ligand passt. Die chemischen Bindungen zwischen Protein und Ligand dürfen nicht sehr stark sein, damit die Produkte nach der Wechselwirkung das Protein wieder verlassen können. Daher kommen hier in der Regel keine kovalenten Bindungen zustande, sondern basieren meist auf Wechselwirkungen wie beispielsweise Wasserstoffbrücken. Dabei handelt es sich um gerichtete intermolekulare Bindungen, in denen ein Wasserstoffatom mit einem Sauerstoff-, Stickstoff- oder Flur-Atom interagiert. Ein chemisches Molekül ist in verschiedenen Formen repräsentierbar [Gas03]. Zwei dieser Formen sind der Graph und ASCII-Dateien. Da im Rahmen dieser Arbeit beide Darstellungsformen für Moleküle benutzt werden, sollen sie hier vorgestellt werden. Im weiteren wird zunächst eine allgemeine Einführung in die Graphentheorie gegeben, dann wird das ASCII-Format (C)SLN vorgestellt. 2.2 Elementare Begriffe der Graphentheorie Ein Graph ist wie eine Menge oder eine Relation ein mathemathisches Objekt [Sed91, THC99]. Ein Graph ist ein Paar (V, E), wobei V eine endliche Menge und E eine binäre Relation auf V ist. Die Menge V wird die Knotenmenge (engl. vertex set) und ihre Elemente die Kanten (engl. vertieces (pl.), vertex (singl.)) genannt. Die Menge E nennt man die Kantenmenge (engl. edge set) von G. Ist im Graph G = (V, E) jedes Paar (u, v) ∈ E mit u, v ∈ V geordnet, ist G gerichtet (engl. directed ), sonst ist er ungerichtet (engl. undirected ). Demnach ist der Knoten v adjazent zu dem Knoten u. Die Adjazenzrelation ist für ungerichtete Graphen symmetrisch, für gerichtete Graphen hingegen ist dies nicht immer so. Der Grad (engl. degree) eines Knotens in einem ungerichteten Graphen ist gleich der Anzahl der sich in ihm treffenden Kanten. In gerichteten Graphen wird für jeden Knoten ein Eingangsgrad (engl. in-degree) und ein Ausgangsgrad (engl. out-degree) definiert, die gleich der Anzahl von ein- bzw. ausgegangenen Kanten des Knotens sind. 0 Ein Pfad (engl. path) der Länge k von einem Knoten u zu einem Knoten u in einem Graph 0 G = (V, E) ist eine Sequenz < v0 , v1 , · · · , vk > von Knoten, so daß u = v0 und u = vk und (vi−1 , vi ) ∈ E for i = 1, 2, · · · , k. Die Pfadlänge ist dann die Anzahl der Knoten im Pfad. In einem gerichteten Graph bildet ein Pfad < v0 , v1 , · · · , vk > einen Zyklus (engl. cycle), wenn v0 = vk und der Pfad mindestens eine Kante enthält. In einem ungerichteten Graph bildet der Pfad < v0 , v1 , · · · , vk > einen Zyklus, wenn v0 = vk und v0 , v1 , · · · , vk disjunkt sind. Ein Graph ohne Zyklus heißt azyklisch (engl. acyclic). Ein ungerichteter Graph ist zusammenhängend KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 7 (engl. connected ), wenn jedes Knotenpaar mit einem Pfad verbunden ist. 0 0 0 0 Ein Graph G = (V , E ) ist ein Subgraph (engl. subgraph) von G = (V, E), wenn V ⊆ V 0 und E ⊆ E. Die ungerichtete Version (engl. undirected version) eines gerichteten Graphen 0 0 0 G = (V, E) ist ein Graph G = (V, E ), wobei (u, v) ∈ E wenn und nur wenn u 6= v und (u, v) ∈ E. In einem gerichteten Graph G = (V, E) ist der Nachbar (engl. neighbor) von einem Knoten u jeder Knoten, der in der ungerichteten Version von G zu u adjazent ist. Mit anderen Worten ist v ein Nachbar von u, wenn entweder (u, v) ∈ E oder (v, u) ∈ E. In einem ungerichteten Graph sind u und v Nachbarn, wenn sie adjazent sind. Ein Wald (engl. forest) ist ein azyklischer, ungerichteter Graph. Ein zusammenhängender Wald ist dann ein Baum (engl. tree). 2.2.1 Darstellungsformen für Graphen Zur Repräsentation eines Graphen G = (V, E) gibt es zwei Standardwege: entweder als eine Sammlung von Adjazenzlisten in einer Adjazenzstruktur oder als eine Adjazenzmatrix. Zwischen den Beiden wird die Adjazenzstruktur oft bevorzugt, weil sie einen kompakten Weg zur Darstellung für einen lichten Graph(engl. sparse) bedeutet, bei dem |E| viel kleiner als |V |2 ist. Für einen dichten (engl. dense) Graph hingegen, bei denen |E| nah an |V |2 ist, wird die Adjazenzmatrix bevorzugt. Da die hier behandelten Graphen ziemlich klein und daher eher lichte Graphen sind, wird im Folgenden auf deren Darstellung, also die Adjazenzstrukturen näher eingegangen. Die Adjazentstruktur eines Graphen G = (V, E) besteht aus einem Array Adj von |V | Adjazenzlisten und zwar eine für jeden Knoten in V . Für jeden u ∈ V enthält die Adjazenzliste Adj[u] (Zeiger auf) alle Knoten v, so daß es eine Kante der Form (u, v) ∈ E existiert , d.h. Adj[u] enthält alle Knoten in G, die zu u adjazent sind. Für gerichtete Graphen ist die Summe der Länge aller Adjazenzlisten gleich |E|, weil die Kante der Form (u, v) nur in der Adj[u] repräsentiert wird. Für ungerichtete Graphen aber ist die Summe gleich 2|E|, da bei einer ungerichteten Kante wie (u, v) u in der Adj[v] und auch v in Adj[u] repräsentiert wird . 2.2.2 Suchalgorithmen für Graphen Die Durchmusterung eines Graphen bedeutet die systematische Verfolgung von Kanten des Graphen zum Treffen von Knoten des Graphen [THC99]. Zwei populären Durchmusterungsalgorithmen für Graphen sind die Breitensuche (engl. Breadth-first search) und Tiefensuche (engl. Depth-first search). Diese beide Strategien unterscheiden sich vor allem in der Reihenfolge, nach der die Knoten des Graphen aufgesucht werden. Der Ablauf der beiden Algorithmen lässt sich durch den folgenden Algorithmus beschreiben (übernommen aus [Blu01]): Algorithmus: Algorithmische Suche Eingabe: Graph G = (V, E), repräsentiert durch seine Adjazenzstruktur und Startknoten s ∈ V Ausgabe: Hängt von der Anwendung ab. Die von s aus erreichbaren Knoten sind markiert. KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 8 Methode: for alle v ∈ V do H[v] := Adj[v] od; Q := {s}; markiere s while Q 6= ∅ do wähle v ∈ Q; if H[v] 6= ∅ then 0 wähle v ∈ H[v]; 0 0 H[v] := H[v ] \ {v }; 0 if v nicht markiert then 0 Q := Q ∪ {v }; 0 markiere v fi else Q := Q \ {v} fi od. In diesem Algorithmus ist Adj[v] die Adjazenzliste für den Knoten v. Die Menge Q enthält in jedem Schritt die Knoten des Graphen G, die bisher noch nicht vollständig bearbeitet worden sind. Möchte man in jedem Schritt dieser Suche einen der bisher noch nicht besuchten benachbarten Knoten des aktuellen Knoten in Q treffen und ihn zum aktuellen Knoten machen, verwendet man für Q einen Stapel (engl. stack ). Da diese Suche so weit sie möglich in die Tiefe des Graphen verläuft wird sie Tiefensuche genannt. Besucht man in jedem Schritt alle direkt benachbarten Knoten des aktuellen Knotens in Q dann verwendet man eine Schlange (engl. queue) für Q. Hier verläuft die Suche soweit wie möglich in die Breite, daher heißt diese Suche Breitensuche. Aufgrund der zugrundeliegenden Datenstrukturen ist die Tiefensuche ein rekursives Verfahren, dagegen ermöglicht die Breitensuche die Implementierung der einfachen nichtrekursiven Verfahren. 2.3 Darstellung Chemischer Strukturen als Graph Die Suche in einer Datensammlung nach Chemikalien oder sonstigen beliebigen Objekten erfordert die maschinlesbare Repräsentation dieser Objekte. Eine Repräsentation chemischer Strukturen muß Informationen über die Art und Weise der Verknüpfung zwischen den Atomen und Spezifitäten der Atombindungen liefern können [Gas03]. Dies wird vor allem dann benötigt, wenn man bestimmte Strukturen innerhalb chemischer Datenbanken sucht oder versucht wird, innerhalb der Datenbank Strukturen mit bestimmten Substrukturen zu finden. KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 9 Abbildung 2.2: Darstellung eines chemischen Moleküls (rechts) als Graph (links) Zur Repräsentation chemischer Strukturen in Computersystemen sind mehrere unterschiedliche Formen benutzt worden [Gas03]. Die Auswahl einer bestimmten Form ist von der Informationsbzw. Datenmenge abhängig, die sie enthalten soll. Auf dem einfachsten Level könnte es beispielsweise nur die Atom-Repräsentation der Struktur sein. Werden mehr Informationen benötigt, kann man auch die Konnektivität der Struktur repräsentieren (Abbildung 2.2). In dieser wird angegeben, welches Atom mit welchem und über welchen Bindungstyp verbunden ist. Diese Art der Repräsentation wird 2D- oder topologische Strukturrepräsentation genannt. Das höchste Level der Repräsentation ist jene, in der die 3D-Koordinaten des Atoms in einer bestimmten räumlichen Struktur des Moleküls angegeben ist. Sie wird 3D- oder topographische Strukturrepräsentation genannt. Im Rahmen dieser Arbeit wird - wegen der hohen Komplexität der 3D-Strukturen - auf die Atomkoordination verzichtet und daher nur die 2D-Struktur benutzt. Eine 2D-Struktur läßt sich unter anderem in den folgenden zwei Formen darstellen: als Graph oder als lineare Notation von alphanumerischen Symbolen. Diese beiden Varianten zur Repräsentation von 2D-Strukturen werden im weiteren Text vorgestellt. 2.3.1 Darstellung kombinatorischer Bibliotheken als Graph Bereits im Abschnitt (2.1) wurde deutlich, daß eine kombinatorische Bibliothek aus R-Gruppen besteht, die jeweils über eine Menge von alternativen Fragmenten verfügen. Eine kombinatorische Bibliothek wird in den meisten Fällen durch einen ungerichteten Baum, also einen speziellen Graph modelliert [Rar01, MR00](Abbildung 2.3). Jeder Knoten des Baumes repräsentiert eine R-Gruppe, wobei die Wurzelknoten als R-Gruppe 0 oder Core ausgezeichnet ist. In solchen Modellierungen kann jede R-Gruppe die Rolle des Cores übernehmen, daher gibt es keinen prinzipiellen Unterschied zwischen dem Core und anderen R-Gruppen. Dieser legt fest, wie die Molekülfragmente miteinander verknüpft werden sollen, um ein Molekül der Bibliothek zu erhalten. Zur Konstruktion eines Moleküls aus der Kombination der in der Bibliothek vorhandenen Fragmente wählt man zuerst aus dem Core genau ein und aus den anderen R-Gruppen maximal ein Fragment aus. Sie werden dann über kovalente, einfachen Atombindungen miteinander KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 10 Abbildung 2.3: Die Baum-Darstellung einer kombinatorischen Bibliothek mit einem core und vier R-Gruppen R1-R4 verknüpft. Die in einer Atombindung zwischen zwei Fragmenten beteiligten Atome werden durch den Benutzer eindeutig markiert (Abbildung 2.4). 2.4 Subgraphisomorphismus Beim Subgraphisomorphierproblem betrachtet man zwei Graphen G1 und G2 und versucht herauszufinden, ob G1 ein Subgraph von G2 ist [THC99]. Eine der Anwendungsmöglichkeiten des Subgraphisomorphismus in der Chemie ist die Frage, ob eine gegebene chemische Struktur eine Substruktur einer anderen chemischen Struktur ist [Gas03]. Das Subgraphisomorphierproblem kann anhand einer brute-force-Aufzählungsmethode auf die Suchbäume gelöst werden, die eigentlich einem Tiefensuchenalgorithmus auf die Suchbäume entspricht. Eine Verbesserung dieser Methode wurde 1976 von J. R. Ullmann vorgestellt [Ull76]. In dem von ihm vorgestellten Algorithmus kann man die brute-force Methode beschleunigen, indem es möglich ist unter bestimmten Voraussetzungen einige der noch nicht besuchten Knoten aus dem Suchbaum zu löschen und dadurch den Suchraum zu verkleinern. Die Substrukturen kombinatorischer Bibliotheken können in zwei Hauptgruppen - lineare Ketten und Ringsysteme - aufgeteilt werden, in denen die Knoten Atome und die Kanten die (a) Vor der Bildung; Links der core, rechts ein Fragment der R-Gruppe R2 (b) Das fertige Bibliotheksmolekül Abbildung 2.4: Der Zusammenbau eines Bibliotheksmoleküls. KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 11 Bindungen zwischen diesen Atomen darstellen. Eine lineare Kette kann man als einen linearen Graphen Kn mit n − 2 Knoten vom Grad 2 und zwei Knoten mit dem Grad 1 definieren [Gas03]. Ein Ringsystem läßt sich als ein geschlossener Pfad definieren, in dem Anfang- und Endknoten identisch sind. Diese zwei Subgraphen können dann in allgemeiner Form innerhalb der Fragmente von kombinatorischen Bibliotheken beliebig miteinander kombiniert vorkommen. (Abbildung 2.5) (a) Lineare Ketten (b) Ringsystem (c) Allgemeiner Form mit dem Verzweigungspunkt (Branch) B Abbildung 2.5: Drei Substrukturen kombinatorischer Bibliotheken 2.5 Darstellung chemischer Strukturen als ASCII-Dateien Wie bereits am Anfang dieses Kapitels erwähnt, ist die lineare Notation eine der Darstellungsformen für chemische Strukturen. Diese lineare Notation kann man als eine Kette alphanumerischer Symbolen verstehen, durch die eine Strukur als eine Menge mehrerer Substrukturen in einer kompakten Form repräsentiert wird. Im Rahmen dieser Arbeit wurde eine solche Darstellungsform - das (C)SLN- Format - verwendet, dessen Struktur im folgenden Abschnitt vorgestellt wird. 2.5.1 Das (C)SLN-Dateiformat Die SYBYL Line Notation, SLN von Tripos inc.[Tri99] ist eine kompakte Repräsentation eines Moleküls als eine lineare Zeichenkette von alphanumerischen Symbolen. Die Basiskomponenten zur Spezifikation chemischer Strukturen in SLN sind Atome, Bindungen zwischen Atomen, Verzweigungen (engl. Branches) zur Identifizierung von Verzweigungspunkten innerhalb der Struktur, Ringsysteme (engl. Ring Closures) zur Spezifizierung der Bindungen zu den vorher definierten Atomen und Attribute, die den Atomen, Bindungen und Strukturen spezielle Eigenschaften zuweisen. (Abbildung 2.6) Atome werden in SLN mit ihren Elementnamen benannt. Dabei wird der erste Buchstabe groß und das Zweite, falls vorhanden, klein geschrieben. Die Bindungen hingegen werden durch spezielle Zeichen zwischen zwei Atomen repräsentiert, beispielsweise steht ”-” für einfache Bindungen, ”=” für Doppelbindungen, ”:” für aromatische Bindungen. Verzweigungen werden durch Klammern dargestellt. Innerhalb einer Klammer steht eine Gruppe von Atomen, die an das Atom unmittelbar vor der Klammer gebunden ist. Das Atom oder die Gruppe unmittelbar KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 12 Abbildung 2.6: Ein chemisches Molekül (oben) und seine SLN-Notation (unten) Abbildung 2.7: Darstellung einer CSLN-Datei mit 3 R-Gruppen. Kommentarzeilen beginnen mit #. Die erste unkommentierte Zeile definiert die Aufbauregel der Bibliotheksmoleküle. RGruppen werden mit Y 01, Y 02, Y 03 bezeichnet. Innerhalb jeder R-Gruppe werden die Fragmente durch vertikale Linien voneinander getrennt. nach der geschlossenen Klammer ist ebenfalls an das Atom unmittelbar vor der öffnenden Klammer gebunden. Mehrere Atomgruppen, die verschiedene an das Atom gebundenen Gruppen repräsentieren, können in Klammern hinter einem Atom stehen. Bindungen zu einem vorher schon einmal untersuchten Atom werden als Ringsystem spezifiziert. Dabei wird dieses Atom zuerst mit einem Label markiert, dann wird das Ringsystem durch ein ”@” Zeichen repräsentiert, das mit dem Typ der Atombindung davor und dem Label des gefundenen Atom danach begleitet wird. Das SLN-Dateiformat ist aufgrund seiner Kompaktheit eine topologische Repräsentation chemischer Strukturen. Es ist jedoch möglich, den Atomen eines bestimmten Moleküls in einer bestimmten Konformation Koordinaten zuzuweisen. Dies geschieht über spezielle graphische Programme, die für eine bestimmte Molekülstruktur in SLN-Form die Atomkoordinaten des Moleküls berechnen. KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 13 Durch SLN-Dateien kann man auch kombinatorische Bibliotheken repräsentieren. Dabei werden alle R-Gruppenfragmente der Bibliothek innerhalb einer kombinatorischen SLN-Datei (engl. Combinatorial SLN, CSLN ) gespeichert, in der die Bindungsstellen (bzw. Bindungsatome) der Fragmente eindeutig markiert sind (Abbildung 2.7). 2.6 Kombinatorische Bibliotheken im Protein-Ligand-Docking Wie bereits in der Einführung erwähnt, ist das Docking-Problem einer der Anwendungsfälle für kombinatorische Bibliotheken. Dabei sucht man - ausgehend von der dreidimensionalen Struktur des Zielproteins - nach Verbindungen, die geometrisch und mit ausreichender Affinität an das Protein passen und mit diesem interagieren können. Brauchte man eine große Anzahl solcher Verbindungen, so kann man sie aus der Kombination mehrerer Baukästen erzeugen, die jeweils über eine Menge von Alternativfragmenten verfügen. Beim Docking-Problem wird die Vorhersage der Struktur des Protein-Ligand-Komplexes von einer Reihe von Freiheitsgraden begleitet [Cla01]. Die Liganden besitzen - aufgrund der hohen Zahl ihrer Konformationsmöglichkeiten - sehr flexible Strukturen, die bei der Anpassung an das Protein berücksichtigt werden müssen. Auch die Proteine ändern ihre Form bei der Komplexbildung. Sie sind jedoch wegen der großen Zahl ihrer Atome und den internen Wechselwirkungen im Vergleich zu den Liganden weitaus weniger flexibel. 2.6.1 Das Docking-Programm FlexX FlexX ist ein Docking-Programm zur Modellierung von Protein-Ligand-Komplexen. Anhand der Struktur des Proteins sucht das Programm nach Liganden, die geometrisch in die Bindetasche des Proteins passen und chemisch eine hohe Affinität zum Protein aufweisen. Zum Docking nimmt man eine starre Struktur des Proteins an, die Liganden sind allerdings flexibel [HC01]. Die Flexibilität der Liganden wird durch diskrete Torsionswinkel an den Einfachbindungen modelliert. Zur Plazierung von Liganden in die Bindetasche benutzt das Programm einen iterativen greedy-Aufbaualgorithmus (Abbildung 2.8): Im ersten Schritt werden die Liganden azyklischer Bindungen in einzelne Fragmente zerteilt. Dann wird im zweiten Schritt ein Fragment oder eine Gruppe von Fragmenten als Basisfragment in die Bindetasche plaziert. Im letzten Schritt werden die weiteren Fragmente entsprechend ihrer Torsionswinkel iterativ in der Bindetasche angebaut. An dieser Stelle wird eine Bewertungsfunktion zur Auswahl der besten Fragmentplazierungen für die nächste Aufbaustufe benutzt. Durch das beschriebene Verfahren läßt sich die Struktur der Protein-Ligand-Komplexe einzeln vorhersagen. Die Stärke der Dockingalgorithmen liegt aber im Screening, also im Durchsuchen großer Molekülbibliotheken nach geeigneten Verbindungen [MR01]. In FlexX lassen sich Protein-Ligand-Komplexe mit potentiellen Wirkstoffmolekülen typischer Größe - 6-10 frei drehbare Bindungen - mit dem obern beschriebenen Algorithmus in 30 sec. vorhersagen. Damit können auf einem einzelnen Prozessor 2500-3000 Verbindungen pro Tag gedockt werden. Um die Effizienz zu steigern, kann man die parallele Hardware nutzen. Dabei verteilt ein Scheduler die Liganden dynamisch auf mehrere Prozessoren, welche die eigentliche Docking-Berechnung durchführen und die Ergebnisse zurück an den Scheduler schicken. Auch im Rahmen der FlexX Software ist ein solcher Scheduler entwickelt worden, womit pro Tag bis zu 250.000 Vergleiche KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 14 auf 100 Computern gemacht werden können. (a) Auswahl des Basisfragmentes (b) Plazierung des Basisfragmentes (c) Inkrementieller Aufbau des Liganden Abbildung 2.8: Plazierung von Liganden in der Bindetasche. In FlexX sind Algorithmen zur Substruktursuche implementiert worden, die im Prinzip auf dem Algorithmus von Ullmann, worüber im Abschnitt (2.4) berichtet wurde, basiert sind [MR04]. Mit Hilfe dierser Algorithmen kann man innerhalb eines einzelnen Molekül nach bestimmten Substrukturen suchen, so daß zur Suche innerhalb einer Menge von Molekülen müssen sie nacheinander nach der gewünschten Struktur durchsucht werden. 2.6.2 Das FlexX-Modul FlexXC Wie weiter oben erwähnt wurde, verfügt FlexX zur Dockingberechnung an kombinatorischen Bibliotheken über das zusätzliche Modul FlexXC , womit einzelne Fragmente oder eine Kombination von Fragmenten nach derselben Strategie wie in FlexX an das Protein gedockt werden können. In FlexX ist die Anzahl der R-Gruppen begrenzt, so daß zur Konstruktion eines Bibliotheksmoleküls außer dem Core bis zu maximal neun weitere Rest-Gruppen ausgewählt werden dürfen. Wie bereits in (2.1) erläutert, wird bei der Zusammensetzung der Bibliotheksmoleküle aus Fragmenten eine ähnliche Aufbaustrategie verfolgt. Dies führt dazu, daß man zum Aufbau neuer Fragmenten die Informationen von vorherigen, ähnlich struktuierten Fragmenten nutzen und dadurch die Zeit für die Suche begrenzen kann. Somit ist es möglich - je nach Struktur der Bibliothek - eine Beschleunigung der Docking-Rechnung um einen Faktor bis zu 50 erzielen. Beim Bau eines Moleküls in FlexXC werden die Fragmente über die X - und R-Verbindungsatome aneinander gekoppelt. (Abbildung 2.4) Dabei wird das X -Atom durch das benachbarte Atom KAPITEL 2. MATHEMATISCH-CHEMISCHE GRUNDLAGEN 15 des R-Atoms und das R-Atom durch das benachbarte Atom des X -Atom ersetzt. Auf Einzelheiten zu diesem Vorgang wird im Kapitel 5 näher eingegangen. In FlexX können die kombinatorischen Bibliotheken auch nach Substrukturen durchsucht werden. Dazu werden in FlexX die Bibliotheksmoleküle eines nach dem anderen zusammengesetzt und jeweils geprüft, ob das entsprechende Molekül die gesuchte Substruktur enthält. Diese Methode hat den Nachteil, daß die Suche in großen Bibliotheken mit mehreren Millionen Bibliotheksmolekülen sehr lange dauern kann. Kapitel 3 Datenbank-Grundlagen Ein Datenbanksystem ist eine Sammlung von anwendungsspezifischen Daten (Datenbank ) und einem anwendungsunabhängigen Programm (Datenbank management system, DBMS ) zur Verwaltung solcher Daten [Man]. Unter Verwaltung von Daten versteht man die Definition von Strukturen zur Speicherung von Informationen und den Entwurf von Mechanismen zu deren Manipulation. Vor der Entwicklung von Datenbanksystemen wurden die Daten in den Betriebsystemdateien gelagert. Diese Art der Datenerhaltung hat einige wesentliche Nachteile. Einer von ihnen ist die Datenredundanz, d.h. mehrfache Speicherung gleicher Informationen von unterschiedlichen Programmen in Dateien mit unterschiedlichen Formaten. Dies wiederum kann zur Dateninkonsistenz führen, wobei einige Kopien derselben Information nicht aktualisiert werden und daher nicht mehr gültig sind. Auch die Bergung von Informationen wird unter diesen Umständen schwierig, weil die dazu notwendigen Anwendungsprogramme in unterschiedlichen Formen geschrieben werden müssen. Möchte man diese Programme später auf nicht vorgesehenen Fälle erweitern, muss man sie eventuell aktualisieren oder im schlimmsten Fall komplett neu schreiben. Solche Probleme zusammen mit einer Reihe weiterer Probleme schaffen den Bedarf einer systematischen Datenbearbeitung. Dazu muss eine Datenbank entworfen werden, in die die Informationen aus der realen Welt unter Beibehaltung ihrer Strukturen importiert und dann unter Kontrolle eines geeigneten DBMS effizient und zuverlässig verwaltet werden. 3.1 Datenbankmodellierung Die wichtigste Voraussetzung eines Datenbankentwurfes ist eine saubere Modellierung. Es wird ausdrücklich davor gewarnt, den Datenbankentwurf unvollständig und nicht systematisch zu machen, denn die daraus resultierenden Probleme sind meistens nicht mehr korrigierbar.[uA01] Zum Entwurf einer neuen Datenbank verfolgt man, ähnlich wie bei der Erstellung großer Softwaresysteme, eine Phasenweise-Modellierung, in der die Komplexität des Problems in mehrere Schichten aufgeteilt wird [uA01, Vos00]. Bei der ersten Phase des Entwurfprozesses, der Anforderungsanalyse, geht es darum die Anforderungen der zukünftigen Datenbankbenutzer an die zu entwerfende Datenbank zu analysieren und sie in Form einer Anforderungsspezifikation (auch Pflichtenheft genannt) zu dokumentieren. Die Hauptbestandteile solcher Dokumen16 KAPITEL 3. DATENBANK-GRUNDLAGEN 17 te sind Objekte und Beziehungen zwischen den Objekten, die jeweils in den Objekttypen und Beziehungstypen abstrahiert werden, und Attribute, die die Objekte und Beziehungen identifizieren sollen. Das daraus resultierende Dokument wird in der zweiten Phase, dem konzeptuellen Entwurf benutzt, um die darin enthaltenen Informationen der zu modellierenden Welt formal und unabhängig von dem Ziel-DBMS darzustellen. Das hierzu am meisten benutzte Datenmodell ist das Entity-Relationship-Modell (kurz ER-Modell ) [Vos00, uA01, A.S02, Man]. In der dritten Phase, dem logischen Entwurf, erhält man das ER-Schma aus der zweiten Phase und transformiert es dann in das Datenmodell des zu verwendenden DBMS. Auch hier hat sich ein Modell, nämlich das relationale Datenmodell seit Mitte der 80-er Jahren als Standard in kommerziellen DBMS durchgesetzt. Die vierte und letzte Phase des Datenbankentwurfes ist der physische Entwurf, wobei versucht wird, die Effizienz des geasmten Datenbankschemas zu steigern, ohne dabei die logische Struktur der Daten verändern zu müssen. Dazu wird vor allem eine grundlegende Kenntnis des eingesetzten DBMS so wie des dazu verwendeten Betriebsystems benötigt. Im folgenden werden die konzeptuellen und logischen Phasen des Datenbankentwurfes bzw. die dazugehörigen Datenmodelle Entity-Relationship-Modell und relationales Modell näher betrachtet, da sie den Kern eines Datenbankdesigns ausmachen. Einzelheiten zur ersten und vierten Phase des Entwurfprozesses können z.B. [Vos00, uA01, A.S02] entnommen werden. 3.1.1 Das Entity-Relationship-Modell Das Entity-Relationship-Modell wurde 1976 von Peter Chen vorgeschlagen. Dieses Modell spielt eine wichtige Rolle, sowohl bei der Datenbankimplementierung als auch auf anderen Gebieten der Informatik, wo es darum geht, die Gesetzmäßigkeiten der zu modellierenden Welt auf eine abstrakte Ebene zu übertragen [Vos00]. Im Bezug auf den Datenbankentwurf hat dieses Modell unter anderem die Vorteile, daß es erstens unabhängig von einem bestimmten DBMS ist und zweitens seine Grundkonstrukte sehr natürliche Ausdrucksmittel sind, die auch in vielen Anwendungen ausreichend sind. Beim Entwurf einer relationalen Datenbank trifft der zweite Punkt besonders zu. Zwar verfügt das relationale Modell mit seiner Normalisierugstheorie über algorithmische Möglichkeiten zum Datenbankentwurf, aus den o.g. Gründen wird aber das ER-Modell bevorzugt. Die Grundkonstrukte des ER-Modells sind die Gegenstände (engl. Entities) und Beziehungen (engl. Relationships) zwischen den Entities. Entities sind wohlunterscheidbare physisch oder gedanklich existierende Konzepte der zu modellierenden Welt [uA01]. Ähnliche Entities werden zu Entitytypen zusammengefasst, die graphisch als Rechtecke dargestellt und mit einem eindeutigen Namen beschriftet werden. Ein Entity gehört mindestens einem Entitytyp an. Damit wird es eine Instanz dieses Typs genannt. Jedes Entity besitzt ein oder mehrere Attribute, durch deren Werte es eindeutig identifiziert wird. Sie werden dann Schlüsselattribute des Entities genannt. Wurden keine Schlüsselattribute explizit vorgegeben, wird die Menge aller Attributen als Schlüsselattribut genommen. Die Entities eines ER-Modells stehen miteinander in Beziehung. Auch hier werden gleichartige Relationships zu Relationshiptypen zusammengefasst, die graphisch als Rauten beschriftet mit einem Namen repräsentiert werden. Folglich ist eine Instanz eines Relationshiptyps eine KAPITEL 3. DATENBANK-GRUNDLAGEN 18 Relationship zwischen einzelnen Entities der in der Relationship beteiligten Entitytypen. Die Relationships können wie Entities Attribute besitzen, jedoch keine Schlüsselattribute. Der Grund liegt darin, daß jede Relationship in seiner Existenz abhängig von den in der Beziehung beteiligten Entities ist und daher über deren Schlüsselattribute charakterisiert wird. Die Funktion eines Entities in einer Relationship wird als Rolle des Entities bezeichnet, die auf der Kante zwischen dem Entity und Relationship geschrieben wird. Solange jedes Entity nur einmal an einer Relationship beteiligt ist, ist die Rolle des Entities auch implizit. Andernfalls, zum Beispiel bei rekursiven Relationships, wo ein Entitytyp mehrfach in der Relationship vorkommt, muss die Art der Beteiligung extra angegeben werden. Ein weiterer wichtiger Punkt, die man bei der Modellierung der realen Welt unbedingt beachten muss, sind die Integritätsbedingungen, die immer gelten müssen. Möchte man zum Beispiel ausdrücken, daß ein Entity in einer Beziehung sich eingeschränkt beteiligen darf, so kann man eine solche Bedingung im ER-Modell über die Funktionalitäten ausdrücken, die in Form von Annotationen an den Verbindugskanten zwischen den Entity- und Relationshiptypen geschrieben werden. Hinsichtlich der Fuktionalitäten kann man einen binären Beziehungstyp R zwischen den Entitytypen E1 und E2 in vier verschiedene Formen aufteilen: • 1 : 1-Beziehung, wenn jede Instanz e1 ∈ E1 mit maximal einer Instanz e2 ∈ E2 und umgekehrt jede e2 ∈ E2 mit maximal einer Instanz e1 ∈ E1 in Beziehung steht. • 1 : N -Beziehung, wenn jede Instanz e1 ∈ E1 mit vielen Instanzen e2 ∈ E2 aber jede e2 ∈ E2 nur mit maximal einer Instanz e1 ∈ E1 in Beziehung stehen darf • M : 1, ist ähnlich wie bei den 1 : N -Beziehungen • M : N -Beziehung, stellt den allgemeinen Fall dar, wobei jede Instanz e1 ∈ E1 mit beliebig vielen Instanzen e2 ∈ E2 , und umgekehrt jede Instanz e2 ∈ E2 mit vielen Instanzen e1 ∈ E1 in Beziehung stehen darf. Wenn für einen Relationshiptyp keine Funktionalität angegeben ist, ist dieser Fall gemeint. Ähnlich wie bei den binären Relationshiptypen können solche Funktionalitäten auf die n-stelligen Relationshiptypen erweitert werden, die dann als mehrere partielle Funktionen angesehen werden. (Für weitere Details siehe [uA01, A.S02]). Die bis jetzt diskutierten Entitäten waren alle autonom existierende Objekte, die innerhalb ihrer Entitymenge über ihre Schlüsselattribute identifiziert werden können. Daneben gibt es Entitäten, die selber keine Schlüsselattribute besitzen. Ihre Existenz ist von einer weiteren, übergeordneten Entität abhängig und sie sind oft nur in Kombination mit dem Schlüsselattribut der übergeordneten Entität identifizierbar. Sie werden im ER-Modell als schwache Entities bezeichnet und werden graphisch meist als Rechtecke mit doppelten Linien dargestellt. Auch die Beziehung zu dem übergeordneten Entitytyp wird durch eine Verdopplung der Raute und der Linie zwischen der Raute und dem schwachen Entitytyp gezeigt. Im ER-Modell sind noch zwei weitere Konzepte - Generalisierung und Aggregation - vorgesehen, die zur besseren Strukturierung des gesamten Schemas gedacht sind. Bei der Generalisierung handelt es sich um eine Abstraktion auf der Entitytyp-Ebene, indem die gemeinsamen Attribute ähnlicher Entitytypen einem Obertyp zugeordnet werden und die nicht-gemeinsamen Attributen KAPITEL 3. DATENBANK-GRUNDLAGEN 19 bei den Untertypen verbleiben. Dadurch ist jede Instanz eines Untertyps auch eine Instanz des Obertyps. Die Generalisierungsbeziehung wird durch die spezielle is a Beziehung zwischen den beteiligten Entitytypen modelliert und wird in dem ER-Schema anders als normale Beziehungen oft als Sechseck dargestellt. Anders als bei der Generalisierung wird bei der Aggregation die Abstraktion auf der Instanzebene realisiert, indem die Instanzen eines Obertyps aus den Instanzen der unterschiedlichen Untertypen zusammengesetzt werden. Diese Beziehung zwischen den Instanzen, die als is part of bezeichnet wird, ist eine spezielle Form der allgemeinen Relationships. Hingegen ist die is a Beziehung keine Relationship, weil sie eine Relationship zwischen den Entitytypen ist und nicht zwischen den Entities selbst. 3.1.2 Das relationale Datenmodell Die Idee vom relationalen Modell wurde im Jahre 1970 von E. F. Codd in einem Paper A Relational Model of Data for Large Shared Data Banks vorgestellt [Man]. In den bisherigen Datenmodellen, wie dem Netzwerkmodell oder dem hierarchischen Modell, wurden die Informationen in Form von Datensätzen über Referenzen miteinander verbunden. Im Gegensatz dazu werden im relationalen Modell die Informationen mengenorientiert verarbeitet. Grundlage des relationalen Datenmodells ist die Relation. Eine Relation R über die nicht unbedingt unterschiedlichen Mengen D1 , · · · , Dn - d.h. für ∀i, j ∈ [1, n] mit i 6= j ist Di = Dj erlaubt - wird definiert über folgende Formel: D1 × · · · × Dn = {(d1 , · · · , dn )|di ∈ Di } Die Mengen D1 , · · · , Dn nennt man Domäne, das Elemente (d1 , · · · , dn ) Tupel und n die Stelligkeit oder den Grad der Relation R. Somit kann man eine Relation als eine Tupelmenge ansehen. Relationale Datenbanken basieren auf Relationen, die in den meisten kommerziellen Systemen auch als Tabellen bezeichnet werden, weil deren Instanzen optisch als flache Tabellen vorstellbar sind [uA01]. Die Zeilen dieser Tabellen sind die Relationstupeln und die Spalten die Domänen der Relation, die Attribute genannt werden. Innerhalb einer Tabelle müssen die Attribute eindeutige Namen tragen, somit werden alle Komponenten eines Tupels eindeutig benannt. Trotz dieser Analogie unterscheiden sich Tabellen und Relationen in einigen Punkten. Der wichtigste ist, daß die Relationen keine Duplikate erlauben, während in Tabellen Einträge mehrfach vorkommen dürfen. 3.1.3 Abbildung des Entity-Relationship-Modells in das relationale Datenmodell Im Gegensatz zum ER-Modell, wo die Konzepte der zu modellierenden Welt auf zwei Hauptkonstrukte - Entity und Relationship - übertragen werden, steht im relationalen Datenmodell ein einziges Konstrukt, nämlich die Relation. Damit müssen zur Umsetzung des ER-Modells in das relationale Datenmodell die Entity- und Relationshiptypen in Relationen bzw. Tabellen überführt werden. KAPITEL 3. DATENBANK-GRUNDLAGEN 20 Die Abbildung der Entitytypen in Tabellen ist relativ einfach: pro Entitytyp erzeugt man eine Tabelle, die als Tabellennamen die Beschriftung und als Spaltennamen die Attribute des Entitytyps trägt, wobei die Schlüsselattribute des Entitytyps auf Primärschlüsselspalten der Tabelle abgebildet werden. Die Abbildung von Relationshiptypen geschieht in zwei Schritten. Zuerst wird jeder Relationshiptyp ähnlich wie bei den Entitytypen auf eine Tabelle abgebildet, dann werden unter Umständen einige dieser Tabellen in andere Tabellen eingebettet. Bei der Umsetzung des Relationshiptyps in die dazugehörige Tabelle werden die Schlüsselattribute aller beteiligten Entitytypen als Fremdschlüssel neben den eigenen Attributen des Relationshiptyps übernommen. Dadurch können die Tupeln der an der Beziehung beteiligten Entitytypen innerhalb der Tabelle eindeutig identifiziert werden. In jeder Tabelle gibt es ein einziges oder eine minimale Menge von Attributen, deren Werte jedes Tupel der Tabelle eindeutig identifizierbar machen. Sie werden Schlüsselattribute der Tabelle genannt. Gibt es mehrere solcher Schlüsselattribute wird eines von ihnen als Primärschlüssel gewählt. Wie bereits erwähnt, kann man in bestimmten Fällen einige der Relationshiptabellen innerhalb anderer Tabellen repräsentieren und dadurch auf eine eigene Tabelle verzichten. Dies geschieht bei den 1 : 1-, 1 : N - oder N : 1-Beziehungen. Der Grund läßt sich wie folgt beschreiben: Sei R eine N : 1-Beziehung zwischen den Entitytypen E1 und E2 . In diesem Fall kann R als eine Funktion der Form R : E1 → E2 verstanden werden. Damit wird die Relation R durch E1 eindeutig identifizierbar. Das bedeutet, daß die Relation R dieselben Primärschlüssel besitzt wie E1 . Somit lassen sich die beiden Relationen ohne Informationsverlust zusammenfassen. Dasselbe gilt auch für die 1 : N -Beziehungen. Für die 1 : 1-Beziehungen können die Beziehungsinformationen entweder in der einen oder in der anderen Relation dargestellt werden. Ebenso könnte man auch mit n-stelligen Relationshiptypen verfahren. Es ist jedoch etwas komplizierter und kann unter Umständen zu Schwierigkeiten führen [Man]. Das relationale Datenmodell bietet keine Möglichkeit zur Modellierung von Generalisierungen aus dem ER-Modell. Dies läßt sich aber mit Hilfe von Sichten in SQL lösen, was im Abschnitt (3.2.2) näher diskutiert wird. 3.2 Relationale Anfragesprachen Der nächste Schritt nach der Modellierung bei der Datenbankimplementierung ist die Einsetzung der Konzepte des Modells in ein DBMS, welches das jeweilige Modell unterstützt. Dazu wird vor allem eine Sprache zur Kommunikation mit dem DBMS benötigt, die im allgemeinen als Anfragesprache (engl. query language) bezeichnet wird. Für relationale Systeme gibt es eine Reihe von Anfragesprachen. Einige von ihnen, wie Relationenalgebra oder Relationenkalkül, sind formal und dienen als Basis für eine weitere, praxisorientierte Sprache. Eine solche ist SQL, die sehr weit verbreitet ist und von fast allen relationalen DBMS unterschtützt wird. Im Folgenden werden zunächst die Grundprinzipien der beiden Sprachen Relationenalgebra und KAPITEL 3. DATENBANK-GRUNDLAGEN 21 Relationenkalkül erläutert. Dann wird die Sprache SQL ausführlicher vorgestellt. 3.2.1 Relationenalgebra und Relationenkalkül Wie bereits in (3.1.2) erwähnt, geschieht die Datenbearbeitung im relationalen Datenmodell Mengenweise. Daher ist zur Erläuterung aller relationalen Sprachen ein Grundverständnis der Mengenlehre unabdingbar. In diesem Abschnitt wird daher eine kurze Einführung in die Grundbegriffe der Mengenlehre gegeben: Eine Menge aus mathematischer Sicht läßt sich am besten mit einem Satz von Georg Cantor, dem Begründer der Mengenlehre, definieren [Man]: Unter einer Menge verstehen wir eine Zusammenfassung von bestimmten wohl unterschiedenen Objekten unserer Anschauung oder unseres Denkens zu einem Ganzen. Zwei Mengen können über die vier Basisoperatoren Vereinigung ∪, Durchschnitt ∩, Differenz / und Produkt × verknüpft werden. Da das Ergebnis dieser Operationen wiederum Mengen sind, kann man das Ergebnis einer Mengenoperation als Eingabe für andere Mengenoperationen verwenden. Daher können mehrere Mengen über Mengenoperatoren verknüpft werden. Eine spezielle Verknüpfung ist es, wenn man die Mengen D1 , · · · , Dn über den Produktoperator × verbindet. Dann ensteht eine Relation, deren Definition bereits im Abschnitt (3.1.2) vorgestellt wurde. Wie bereits erwähnt, sind die Ergebnisse einer Mengenoperation wiederum Mengen. Das entspricht der Definition einer Algebra in der Mathematik, wo ein System von Operatoren auf eine Trägermenge operieren und die Ergebnisse nochmals derselben Menge angehören. Demensprechend ist eine Mengenalgebra die Algebra, bei der die Trägermenge aus Mengen besteht, auf die die vier oben genannten Operationen (∪, ∩, / und × ) operieren. Die Relationenalgebra RA ist eine spezielle Form der Mengenalgebra, bei der die Trägermenge aus speziellen Mengen - nämlich Relationen - besteht. Es ist zu beachten, daß die Resultate der Operationen in der Relationenalgebra zwar immer Mengen sind, sie sind jedoch nicht immer Relationen. Nur Relationen mit gleichem Grad und gleichen Spaltentypen können vereinigt, geschnitten und subtrahiert werden. Die Relationenalgebra bietet zusätzlich zu den vier Grundoperatoren noch zwei weitere einstellige Operatoren, nämlich die Projektion π und Selektion σ zum Extrahieren von Spalten bzw. Zeilen. Diese beiden Operatoren können dann mit den Grundoperatoren kombiniert werden und dadurch weitere abgeleitete Operatoren bilden, wie etwa Varianten der Produktbildung, die verschiedene Formen von join-Operatoren darstellen. Eine Alternative zur Relationenalgebra bietet die Sprache Relationenkalkül. Im Gegesatz zu der eher prozedural aufgebauten Sprache Relationenalgebra, bei der man einen Abarbeitungsplan erstellen kann, ist die Sprache Relationenkalkül eine deklarative Sprache, bei der die Anfragen über logische Ausdrücke aus der Prädikatenlogik erster Stufe formuliert werden. Bei letzterer gibt man an, welche Kriterien die Daten erfüllen müssen, damit sie als Ergebnis in Frage kommen. Es gibt zwei verschiedene Varianten des Relationenkalküls, die sich jedoch hinsichtlich ihrer Mächtigkeit nicht unterscheiden: diese sind der relationale Tupelkalkül (ensl. tupel relational calculus, TRC ) und der relationale Bereichs- oder Domänenkalkül (engl. domain relational calculus, DRC ). Da die Relationenalgebra wegen ihres prozeduralen Charakters bei KAPITEL 3. DATENBANK-GRUNDLAGEN 22 der Realisierung von Datenbanksystemen eher in Frage kommt als der Relationenkalkül, wird an dieser Stelle auf weitere Einzelheiten über die Sprache Relationenkalkül verzichtet und näher auf die Relationenalgebra eingegangen. Details zum Relationenkalkül können zum Beispiel in [uA01, A.S02] gelesen werden. Die Relationenalgebra wird mittlerweile als eine vollständige relationale Sprache betrachtet. Es geht sogar so weit, daß zur Messung der Ausdrückfähigkeit anderer relationaler Sprachen diese mit ihr verglichen werden. Eine Sprache ist relational volständig, wenn sie für jeden RA-Ausdruck eine äquivalente Darstellung besitzt. Die Kalkülsprachen DRC und TRC sind relational vollständig [Man]. Relationale Algebra und Kalkülsprachen sind theoretische Sprachen, die in der Praxis jedoch nicht zum Einsatz kommen. SQL ist eine weitere relational vollständige Sprache, deren Ausdruckfähigkeit jedoch weit über die der beiden genannten Sprachen hinausgeht. Sie besitzt unter anderem arithmetische Operatoren und Aggregatfunktionen, Gruppierungs- und Sortierungsmöglichkeiten und built-in-Operatoren, die nicht in den o.g. formalen Sprachen vorgesehen sind. 3.2.2 SQL SQL ist die am häufigsten verwendete Anfragesprache für relationale Datenbanksysteme. Sie ist eine deklarative Sprache, wobei man bestimmt, welche Informationen man haben möchte, ohne zu wissen, wie sie ausgewertet werden [Mel03b]. Die Erfindung der Sprache SQL führt zurück zum Beginn der 70-er Jahren, in denen die Firma IBM die Sprache Structured English Query Language (SEQEL) für das relationale Prototyp-DBMS System R entwickelte. Diese Sprache hat sich im Laufe der Zeit weiterentwickelt und wurde schließlich in Structured Query Language (SQL) umbenannt. Im Jahr 1986 haben das American National Standard Institut (ANSI) und die International Organisation for Standardization (ISO) die erste SQL-Norm, SQL-86 vorgelegt. Eine Reihe zusätzlicher Erweiterungen folgten später: SQL-89 (1989), SQL-92 oder SQL 2 (1992) und die aktuellsten Versionen SQL:1999 oder SQL 3. Die Sprache SQL besteht aus zwei Teilsprachen: Data-Definition Language, DDL zur Definition und Manipulation von Datenbankschemata und Data Manipulation Language DML zur Formuliernug von Anfragen an die Datenbankinstanzen und deren Manipulation. Beide Teilsprachen bieten eine Reihe von Befehlen, die die Ausführung der o.g. Operationen ermöglichen. Ein Datenbankschema wird in SQL über den Befehl CREATE SCHEMA mit folgender Syntax erzeugt: CREATE SCHEMA [schema-name] [AUTHORIZATION user-name] [DEFAULT CHARACTER SET character-set] [list-of-schema-elements] Von den soeben genannten Feldern sind nur Schemaname und Benutzerautorisierung unbedingt KAPITEL 3. DATENBANK-GRUNDLAGEN 23 erforderlich. Elementare Bestandteil des obigen Befehls sind die sogenannten Schemaelemente (list-of-schema-elements), worunter die domain-, table-, view -, privilege-, constraint-, character set-, collation- und translation-Definitionen stehen. Der vielleicht wichtigste Befehl der DDL ist der CREATE TABLE-Befehl zum Erzeugen einer neuen Tabelle. Die Syntax lautet: CREATE TABLE table-name column_1_name column_1_type [column-constraint_1], ... column_n_name column_n_type [column-constraint_n], [table-constraints] Die Tabellendefinition kann man in zwei Teile aufteilen: Spaltendefinitionen und Tabelleneinschränkungen. Bei der Spaltendefinition wird für jede Spalte ein eindeutiger Name column-name und der Typ des Wertebereiches der jeweiligen Spalte column-type festgelegt. Zusätzlich besteht die Möglichkeit für die Werte jeder Spalte Einschränkungen column-constraints zu setzen, die wie folgt aussehen können: [NOT NULL | UNIQUE] [PRIMARY KEY] [DEFAULT {literal | NULL}] [REFERENCES table name] [CHECK condition] Diese Einschränkungen lassen sich auf ähnliche Art und Weise wie bei den Spalten über Tabelleneinschränkungen definieren. Ihre Syntax lautete dann: [NOT NULL | UNIQUE] [PRIMARY KEY] [DEFAULT {literal | NULL}] [REFERENCES table name] [CHECK condition] Tabelleneinschränkungen sind optional und gelten i.a. für mehrere Spalten. Bei den Spalteneinschränkungen handelt es sich hingegen immer um die gerade betrachtete Spalte. Die Spalten- und Tabelleneinschränkungen, die auch als Integritätsbedingungen bezeichnet werden, sind wichtige Bestandteile jedes CREATE TABLE-Befehls, die für die Konsistenzerhaltung der Datenbankzustände sorgen. Daher soll im folgenden auf sie genauer eingegangen werden. In einer Tabelle ist eine Spalte oder eine Kombination aus mehreren Spalten ein Kandidatenschlüssel, wenn keine Zeilen dieser Spalten dieselben Werte haben. Solche Spalten gibt werden mit UNIQUE-Optionen ausgezeichnet. Die als UNIQUE ausgezeichneten Spalten dürfen mehrfach NULL-Werte enthalten. Das kann aber durch die Option NOT NULL verhindert werden. KAPITEL 3. DATENBANK-GRUNDLAGEN 24 Für jede Tabelle kann einer der Kandidatenschlüssel als Primärschlüssel deklariert werden. Der Primärschlüssel wird eindeutig über die PRIMARY KEY-Option in den Spalten- oder Tabelleneinschränkungen der Tabelle markiert. Im Gegensatz zu Kandidatenschlüssel, die NULL-Werte enthalten dürfen, sind bei dem Kandidatenschlüssel, der als Primärschlüssel definiert wurde keine NULL-Werte erlaubt. Trotzdem ist ein Primärschlüssel nicht prinzipiell mit einem UNIQUE NOT NULL-Kandidatenschlüssel gleichzusetzen, da der Primärschlüssel eine eindeutige Rolle innerhalb der Tabelle spielt, die nicht einfach durch diese Definition ersetzbar ist. Die Option DEFAULT dient zur Einsetzung von Standardwerten für eine Spalte, wenn dazu explizit keine Angabe bei der Eingabe der jeweiligen Zeile gemacht wurde. Die CHECK-Option prüft, ob die in condition formulierte Bedingung in jedem Datenbankzustand gilt. Oft referenzieren die Spalten der neu deklarierten Tabelle die Primärschlüssel einer zweiten Tabelle. Diesen Fall, der auch referenzielle Integrität genannt wird, kann man entweder innerhalb der Tabelleneinschränkung oder als Spalteneinschränkung formulieren. Bei der Ersten wird die Bedingung über die FOREIGN KEY-Option formulieren, wobei table-name den Tabellennamen der referenzierten Tabelle und die optionale Liste - list-of-column-names - die Zielspalten festlegt. Gibt man keine Liste der Zielspalten an, werden die Primärschlüssel der Referenztabelle als Referenzspalten angenommen. Bei letzterer wird die Integritätsbedingung durch die Option REFERENCES ausgedrückt. Auch hier ist der table-name der Name der Referenztabelle. Wie bereits erwähnt, handelt es sich bei der DML Sprache um den Teil der Sprache SQL, der sowohl für Anfragestellungen an, als auch die eigentliche Manipulation von Datenbankinstanzen verantwortlich ist. Dementsprechend kann man die DML-Befehle in zwei Gruppen aufteilen: Befehle zu Anfrageformulierungen und Befehle zur Durchführung von Änderungsoperationen. Die SQL-Anfragen basieren auf den drei Klauseln SELECT , FROM und WHERE mit der folgenden Syntax: SELECT (list-of-column-names) FROM (list-of-talbe-names) WHERE (condition) Bei der Ausführung dieser Anweisungen wird zuerst im FROM-Teil das kartesische Produkt zwischen den in list-of-table-names aufgelisteten Tabellen gebildet, dann wird im WHERE-Teil die Bedingung - condition - für die aus dem Produkt resultierenden Zeilen geprüft und die gewünschten Zeilen selektiert. Am Ende werden aus den Spalten der selektierten Zeilen die in list-of-column-names aufgelisteten Spalten herausprojeziert, die in Form einer abgeleiteten Tabelle dargestellt werden. Die drei Klauseln SELECT, FROM und WHERE der SQL-Anfragen modellieren die Operatoren Produkt, Selektion und Projektion aus der Relationenalgebra. Weitere RA-Operatoren wie Vereinigung, Durchschnitt, Minus und Join werden jeweils über union, intersect, minus und join in SQL vertreten. Diese kann man auch in kombinierter Form benutzen, um komplexe Anfragen zu formulieren. Innerhalb von SQL-Anfragen kann man auch Bedingungen zu deren Auswertung in Form von booleschen Ausdrücken formulieren, die entweder als Auswahlkriterien im WHERE-Teil der Anfrage oder als Integritätsbedingung in der CHECK-Klausel formuliert werden. Jede Bedingung KAPITEL 3. DATENBANK-GRUNDLAGEN 25 läßt sich in zwei allgemeine Formen aufteilen: Vergleichsbedingungen zum Vergleich von Spalten einzelner Zeilen mit konstanten Werten oder den Werten anderer Spalten und Existenzbedingungen zum Test, ob die Antworttabelle einer Unteranfrage leer ist. Vergleichsbedingungen werden durch booleschen Operatoren und die Operatoren LIKE und BETWEEN realisiert. Diese können auch zusammen mit weiteren AND-, OR- und NOT-Operatoren kombiniert benutzt werden. Die Existenzbedingungen werden innerhalb von (NOT)EXISTS- und (NOT)IN-Klauseln formuliert. Änderungsoperationen in SQL werden in drei Hauptgruppen unterteilt: INSERT zum Einfügen, UPDATE zum Ändern und DELETE zum Löschen von Zeilen. Der INSERT-Befehl hat folgende Syntax: INSERT INTO <table-name> [(<list-of-columns>)] <table-expression> Der UPDATE-Befehl hat folgende Syntax: UPDATE <table-name> SET <list-of-assignmets> [WHERE <conditional-expression>] Der DELETE-Befehl hat folgende Syntax: DELETE FROM <table-name> [WHERE <conditional-expression>] Sichtendefinition Sichten (engl. views) sind abgeleitete, virtuelle Relationen, bei deren Definition keine neue Tabelle abgelegt, sondern nur ein Ausschnitt aus den in den statischen Tabellen enthaltenen Informationen repräseniert (daher virtuell) wird. Sichten werden durch den Befehl CREATE VIEW erzeugt: CREATE VIEW view-name AS query expression Die Sichtendefinition enthält eine SQL-Anfrage, die durch die Definition einen eindeutigen Namen bekommt. Wird eine Anfrage auf eine Sicht gestellt, so wird der AS-Teil der Sichtdefinition statisch an der Stelle eingesetzt, wo die Sicht aufgerufen wurde. Eine der Anwendungen von Sichten erfolgt bei der relationalen Modellierung von Vererbung. Hierzu gibt es zwei Möglichkeiten: entweder existiert der Obertyp als Relation bzw. Tabelle und die Untertypen werden als Sicht modelliert oder die Untertypen liegen physisch vor und der Obertyp wird als Sicht definiert. In beiden Fälle gibt es Vor- und Nachteile, die eine entscheidende Rolle bei der Auswahl einer der beiden Varianten spielen. Diese können in [uA01, Man] gelesen wereden. Datentypen in SQL Der SQL-Standard bietet eine Vielfalt von vordefinierten Datentypen, die man im Allgemeinen in drei Gruppen aufteilen kann: Zahlen, Zeichenketten und Zeit/Datum. Zu Zahlen gehören KAPITEL 3. DATENBANK-GRUNDLAGEN 26 die Datentypen numeric(p, d) zur Darstellung p-stelliger Zahlen, wovon d-Stellen als Nachkommastellen reserviert sind, integer oder int, die für Zahlen ohne Nachkommastellen stehen, und float(n) für Fliesskommazahlen mit einer mindestens n-stelligen Präzision. Zeichenketten sind entweder vom Typ char (n) bzw. character (n) zur Darstellung von Zeichenketten mit der festen Länge n oder varchar (n) bzw. character variying(n) zur Darstellung von Zeichenketten mit maximaler variabler Länge n. Zum Zeit/Datum-Datentyp gehören die Datentypen date zur Darstellung von Jahr, Monat und Tag, time zur Darstellung der Zeit in Stunden, Minuten und Sekunden und timestamp als eine Kombination von beiden. Viele kommerzielle Datenbanksysteme bieten zusätzlich zu den Grunddatentypen noch weitere Datentypen wie Large OBjects (LOBs) zur Speicherung von großen Daten oder user-defined types (UDTs) zum Aufbau komplexer Datentypen, die dann als Attributtypen verwendet werden können. Mehr zum Thema Datentypen in SQL können z.B. bei [Mel03b, uA01, A.S02] gelesen werden. Erweiterungskonzepte in SQL In den 90-er Jahren erlebte die IT-Branche einige wichtige Ereignisse wie zum Beispiel die Weiterentwicklung des Internets von akademischen Netzwerken zu e-commerce und e-business und die Entstehung des ”World Wide Web” als ein Medium für die Geschäftswelt. Alle dieser Vorgänge haben ein gemeinsames Element, nämlich die relationale Datenbanktechnologie zusammen mit DBMS-Produkte, die auf der Sprache SQL basiert sind. Im Gegensatz zu der Zeit, als die IT-Organisationen der relationalen Datenbanktechnologie als Grundlage für ihre Informationssysteme äußerst skeptisch gegenüber standen, setzt man mittlerweile voraus, daß fast alle neuen datenintensiven Programme auf eine relationale Datenbank gesetzt werden, deren Inhalt dann über SQL erreichbar ist. Daher mußte auch SQL an die neuen Anforderungen solcher Programme angepaßt und demensprechend erweitert werden [Mel03a]. Die letzte Version des SQL-Standard - SQL:1999 - bringt einige wesentliche neue Eigenschaften mit sich. Darunter ist die Bereicherung der Sprache durch benutzerdefinierten Datentypen(engl. user-defined types) am effizientesten. Sie wird auch als objektorientierte Erweiterung von SQL bezeichnet und wurde bereits in der Praxis von einigen kommerziellen Systemen eingesetzt. Dafür wird bei den meisten Systemen kein neues objektorientiertes System entwickelt, sondern die objektorientierungskonzepte werden um den relationalen Kern solcher Systeme aufgebaut, die dann zumeist als objekt-relational bezeichnet werden. Das SQL Objektmodell, für das es im Gegensatz zu den objektorientierten Sprachen kein universelles Objektmodell gibt, enthält zwei unterscheidbare Komponenten: die struktuierten benutzerdefinierten Datentypen (engl. structured user-defined types oder structured UDTs), und die Typtabellen (engl. typed tables). Die struktuierten benutzerdefinierten Datentypen sind eine der drei Formen von UDTs in SQL, die Möglichkeiten zum Definieren neuer, möglicherweise komplizierterer Datentypen als SQL built-in Datentypen wie INTEGER, DATE oder BLOB bieten. Eine Typtabelle ist eine Tabelle, deren Zeilen die Instanzen eines bestimmten struktuierten UDT sind, mit dem die Tabelle explizit verbunden wurde. Erst durch die Kombination von struktuierten UDTs und Typtabellen kann man ein richtiges Objektmodell in SQL repräsentieren. Ein SQL UDT beinhaltet nicht nur die Daten, sondern auch die Möglichkeit, mit ihnen in Form von KAPITEL 3. DATENBANK-GRUNDLAGEN 27 SQL-aufrufbaren Routinen zu operieren, worauf im folgenden Abschnitt eingegangen wird. SQL-invoked Routines Eine SQL-aufrufbare Routine (engl. SQL-invoked Routine) wird im SQL:1999 Standard als ein Ausdruck definiert, der über SQL-Codes aufrufbar ist. Die SQL-aufrufbaren Routinen können sowohl in SQL als auch in anderen Programmiersprachen geschrieben werden, die dann entweder als SQL routines oder als external routines bezeichnet werden. Als möglichen externen Programmiersprachen sind in SQL neun Sprachen vorgesehen. Es gibt jedoch kein Datenbanksystem, das alle diese Sprachen einsetzt oder andere Sprachen außer den neun vorgesehenen benutzt [Mel03a]. Die SQL-aufrufbaren Routinen werden in drei Klassen - Prozedur (engl. procedure), Funktion (engl. function) und Methode (engl. method) - unterteilt. Trotzdem wird diese Unterscheidung nicht in allen Systemen so klar eingesetzt. Eine Prozedur ist ein Unterprogramm, das in einem SQL-Code über eine call -Anweisung (engl. call statement) aufgerufen wird. Prozeduren sind Routinen ohne Rückgabewerte außer über explizite Parameter oder result sets. Daher können sie Parameter für Eingabe, Ausgabe oder beides besitzen (IN, OUT und INOUT Parameter). Funktionen unterscheiden sich von Prozeduren in drei Punkten: sie benötigen keine spezielle Anweisung zum Aufruf innerhalb des SQL-Codes, jede Funktion hat einen Rückgabewert und sie besitzen nur IN Parameter. In SQL:1999 wird die Methode als eine spezielle Funktion definiert, die einem bestimmten bentzerdefinierten Datentyp (UDT) angehört. Man unterscheidet zwischen drei Typen von Methoden: Instanzmethoden (engl. Instance methods) sind Methoden, die an bestimmten Instanzen eines UDT operieren, Konstruktormethoden (engl. constructor methods), die jeder neu erzeugten Instanz ihre Initialwerte zuweisen und statische Methoden (engl. static methods), die nicht einer konkreten Instanz des UDT angehören, sondern dem UDT selbst. Solche Methoden kann man mit class methods in manchen objekt-orientierten Programmiersprachen vergleichen. 3.3 Das Oracle DBMS Nachdem Codd sein relationales Konzept vorgestellt hat, entwickelte IBM den System RPrototyp zur Untersuchung dieses Konzeptes. Danach brachte Oracle - ebenfalls in den siebziger Jahren - als erste Firma ein kommerzielles relationales DBMS auf den Markt, das auf dem IBM System R Modell basierte. In diesem Produkt setzte Oracle die Sprache SQL zum ersten Mal ein. Mit der Version 8 hat Oracle das traditionelle relationale System um objekt-orientierte Konzepte erweitert, die in der aktuellen Version 9i diese Konzepte noch weiter entwickelt worden sind. Oracle 9i unterstützt, außer bei einigen Ausnahmen wie etwa distinct data types, alle Kernfähigkeiten von SQL:1999 [SD02, Kyt01]. Außerdem bietet Oracle einige Oracle-spezifische Konstrukte wie zum Beispiel connect by zum Traversieren von Baumstukturen in einen einzigen SQL-Befehl oder die Upsert-Operation als eine Kombination des update- und insert-Befehls [OrS01a]. KAPITEL 3. DATENBANK-GRUNDLAGEN 28 PL/SQL Wie bereits im vorherigen Abschnitt erläutert, kann man die SQL-aufrufbaren Routinen auch in anderen Programmiersprachen als in SQL schreiben. Dazu bietet Oracle unter anderem mit procedural language/SQL (PL/SQL) eine eigene prozedurale Sprache. Sie ist die prozedurale Erweiterung von SQL in Oracle, die an die Programmiersprache Ada angelehnt ist [OrP02]. Der größte Vorteil von PL/SQL liegt daran, daß sie, anders als die meisten anderen prozeduralen Sprachen, keine spezielle Schnittstelle zur Kommunikation mit der Datenbank braucht, sondern direkt in das System in Form von Prozeduren, Funktionen, Paketen oder Trigger integriert und ausgeführt wird. Als Datentyp bietet PL/SQL eine Reihe vordefinierter Datentypen. Sie werden strukturell in vier Gruppen eingestuft: Scaler Types wie INTEGER oder CHAR, die keine internen Komponenten haben, Composite Types wie RECORD oder TABLE, die manipulierbare interne Komponente besitzen, Reference Types wie REF CURSOR, die ähnlich wie Zeiger in C oder Pascal auf einem bestimmten Speicherbereich zeigen und LOB Types zur Speicherung von bis zu vier Gigabyte großen Daten. Syntaktisch basieren die PL/SQL Programme auf Blocks. Das sind die kleinsten Einheiten in den PL/SQL-Codes mit dem folgenden Syntaxformat [DECLARE <declaration>] BEGIN <statement> [EXCEPTION <handlers>] END; Hier werden im optionalen DECLARE-Teil Konstanten und Variablen definiert. Im BEGIN-Teil stehen Anweisungen. Dort können unter anderem Kontrollstrukturen wie IF...THEN...ELSE -Anweisungen sowie FOR - und WHILE-Schleifen eingesetzt werden. Ausnahmefälle werden im optionalen EXCEPTION-Teil behandelt. Schließlich wird ein Block mit END geschlossen. Die Blöcke sind autonom ausführbare Programmeinheiten. Man kann sie auch in Form von Prozeduren und Funktionen benennen und sogar parametrisieren und dann für spätere Anwendungen im System registrieren. SQL∗ Plus SQL∗ Plus ist ein Tool zur Kommunikation mit dem Oracle DBMS. Damit kann der Benutzer (client) sich mit einem Oracle Server verbinden und seine SQL und PL/SQL Skripte ausführen lassen und darauf die Ergebnisse zurückbekommen [OrS01b]. Dabei kann der Server sich entweder auf derselben Maschine oder auf einer anderen Maschine innerhalb des Netzwerkes befinden. SQL∗ Plus ist ein freies Tool und wird mit jedem Oracle DBMS geliefert. Es bietet dem Anwender zudem eine Reihe weiterer Möglichkeiten, wie sie im Detail z.B. in ([SD02]) nachgelesen werden können. 3.3.1 Objekt-Relationale Konzepte in Oracle Oracle brachte mit der Version 8 einige Objekt-Orientierte-Konzepte (OO-Konzepte), mit denen man zusätzlich zu den vordefinierten Datentypen auch die UDTs definieren und neben KAPITEL 3. DATENBANK-GRUNDLAGEN 29 den relationalen Kerneingenschaften des Systems benutzen kann. Diese erste Version der Oracle Objektfunktionalität war nicht ganz das, was die Programmierer erwartet hatten [SD02]. Es fehlten dabei vor allem Schlüsseleigenschaften wie Vererbung und Polymorphismus. Mit der Version 9i machte Oracle große Fortschritte in seinem Objekt-relationalen Modell, worin dann auch die einfache Vererbung und der Polymorphismus implementiert wurden. Wie im SQL:1999 Standard vorgesehen, kann man innerhalb jeder UDT Routinen definieren, die auf die Daten operieren. Diese Routinen können entweder in SQL oder in einigen anderen Sprachen geschrieben werden. Bis zur Version 8.0 waren SQL und PL/SQL die einzigen Programmiersprachen im Oracle DBMS. In Oracle 8.0 hat PL/SQL es ermöglicht, die externen C-Funktionen innerhalb ihrer Codes zur Verfügung zu stellen, die dann auch von den SQL-Codes erreichbar sind. Mit Version 8.1 bietet Oracle eine spezielle Schnittstelle, die call specification, [OrA02, OrC02] über die in anderen Programiersprachen geschriebene externe Funktionen -external procedures oder auch manchmal external routines genannt- aufgerufen werden können. Der Zweck dieser Schnittstelle ist die interne Kommunikation zwischen SQL, PL/SQL, C und Java. Sie ist daher von allen Sprachen erreichbar, die diese vier Basissprachen aufrufen können. Eine external procedure ist eine Prozedur, die in Form einer dynamic link library (.dll) - oder im Fall von Java-Methoden einer libunit - als eine Betriebsystemdatei gespeichert ist. Diese können dann später für spezielle Zwecke vom PL/SQL-Code dynamisch zur Laufzeit aufgerufen werden. Zur Benutzung einer external procedure, müssen nacheinander drei Schritte gemacht werden. Zuerst muß man in der LOAD-Phase muss man das Programm für den PL/SQL-Codes verfügbar machen, indem man es als Betriebsystemdatei ablegt und die nötigen Anpassungen in den Konfigurationsdateien von Oracle für den Zugriff auf das Programm vornimmt. Danach wird in der zweiten, der PUBLISH -Phase die external procedure über eine call specifiation spezifiziert. Hier wird festgehalten, sowohl in welcher Sprache das Programm geschrieben und in welcher Betriebsystemdatei das Programm abgelegt ist, als auch wie die external procedure innerhalb des Programms heißt und welche Parameter sie besitzt. Dann wird in der dritten und letzten Phase, CALL-Phase genannt - die external procedure über einen call statement aufgerufen. Die call specifications und call statements dürfen nur in bestimmten Positionen innerhalb des PL/SQLCodes eingesetzt werden. So dürfen die call specifications nur in PL/SQL-Paketdefinitionen bzw -Bodies, Objekt-Typ-Deklarationen und Object-Typ-Bodies benutzt werden. Auch die call statements dürfen nur in anonymen PL/SQL-Blöcke, Unterprogrammen, Methoden der Objekttypen, Trigger und SQL-Anweisungen vorkommen. 3.3.2 Oracle Data-Cartridges Zur Modellierung von komplexen Objekten der realen Welt in einer Datenbank reichen zumeist die Basisdatentypen allein nicht aus. Daher muss man sie mit zusätzlichen Datentypen, wie zum Beispiel benutzer-definierten Objekttypen oder LOBs, ergänzen. Diese kann man dann zusammen mit weiteren Konzepten wie die Möglichkeit zur Anwendung externer Routinen (engl. external Routines), erweiterbare Indexierungen (extensible Indexing) oder Erstellung von Kostenfunktionen in einem Softwarepaket namens Data Cartridges definieren [OrC02]. Diese KAPITEL 3. DATENBANK-GRUNDLAGEN 30 können dann zur Erweiterung der Leistungsfähigkeit des Oracle-Servers in diesen eingesteckt werden. Diese Erweiterung ist deshalb machbar, weil der Oracle-Server über eine Erweiterungsschnittstelle (engl. extensibility interface) verfügt, die wiederum Funktionen enthält, die der Cartridge-Entwickler für seine Anwendungen implementieren kann. Möchte zum Beispiel einen eigenen Indextyp anlegen, muss man dafür einen Objekttyp definieren, in der die Funktionen der extensible indexing interface als statische Methoden des Objekttyps realisiert sind. Jede Data Cartridge besteht grundsätzlich aus einem oder mehreren Objekttypen, die man auch in Paketen (engl. packages) zusammenpacken kann. Diese können in den komplexeren Data Cartridges mit weiteren Diensten der extensibility interface - wie benutzerdefinierten-Indextypen oder Optiemierungsfunktionen - ergänzt werden. Kapitel 4 Modellierung kombinatorischer Bibliotheken Bei der Modellierung kombinatorischer Bibliotheken geht es zunächst darum, die Konzepte der kombinatorischen Bibliotheken als Entity-Relationship-Modell auf einer abstrakten Ebene in Form von Entity- und Relationshiptypen mit ihren Attributen zu modellieren und danach diese Strukturierungskonzepte im relationalen Datenmodell in Relationen abzubilden. Letzlich werden die Relationen über die relationale Anfragesprache SQL in das relationale DBMS Oracle umgesetzt. Wie bereits in Kapitel 3 beschrieben, beginnt eine Modellierung mit der Anforderungsanalyse. Dabei werden die Informationen über Objekttypen, Beziehungen zwischen ihnen und deren jeweiligen Attributen dokumentiert, die aus den Gesprächen mit den zukünftigen Anwendern gewonnen werden konnten. Bereits in den vorherigen Kapiteln wurde deutlich, daß in der Welt der kombinatorischen Bibliotheken die R-Gruppen, die darin enthaltenen Molekülfragmente und die Atome, aus denen die Moleküle bestehen, wesentliche Objekte dieser Welt sind. Dagegen sind die Atombindungen in ihrer Existenz abhängig von Molekülen und können daher nicht als Objekte dieser Welt betrachtet werden. In diesem Kapitel werden - analog der Reihenfolge in den Abschnitten (3.1) und (3.2) - zuerst die Grundprinzipien der Welt der kombinatorischen Bibliothek in das Entity-Relationship Modell transformiert. Die aus der ersten Phase resultierenden Entity- und Relationshiptypen werden dann in der zweiten Phase zusammen mit ihren Attributen in den Relationen bzw. Tabellen abgebildet. 4.1 Konzeptueller Entwurf Ein Bibliotheksmolekül (d.h. ein Molekül, das auf dem Prinzip von kombinatorischen Bibliotheken aufgebaut ist) kann man aus zwei Sichtenweisen betrachten. Aus der ersten Sicht ist es ein Molekül, das aus der Kombination von mehreren weiteren kleineren Molekülen unter Beachtung bestimmter Vorschriften aufgebaut ist. Aus der zweiten Sicht ist es ein chemisches Molekül, das wie alle anderen Moleküle aus einer Menge von Atomen besteht, die durch Atombindungen aneinander gebunden sind. Genauso kann man auch das Entity-Relationship Modell für kombinatorische Bibliotheken in zwei Teilschemata entwerfen, die man dann im 31 KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 32 Abbildung 4.1: Die Entitytypen Atomtype und Atom stehen über den Relationshiptyp Atom has Atomtype in einer 1 : N Beziehung. globalen Schema zusammenfügt. Der erste Teil des Modells repräsentiert die Modellierung des Aufbauprinzipes eines chemischen Moleküls im Allgemeinen, wobei unter anderem die Modellierung der Atome und Atombindungen zusammen mit ihren Eigenschaften innerhalb der Moleküle thematisiert wird. Danach wird im zweiten Teil des Modells die Modellierung der kombinatorischen Logik von kombinatorischen Bibliotheken repräsentiert. Dabei geht es im wesentlichen darum, die Baumstruktur der kombinatorischen Bibliotheken zu abstrahieren, in der die Verknüpfung der Molekülfragmente aus den R-Gruppen festgelegt ist. 4.1.1 Modellierung eines chemischen Moleküls Wie bereits in (2.1) beschrieben, besteht jedes chemische Molekül aus wohldefinierten, voneinander unterscheidbaren Bausteinen. Diese sind die Atome, die über Atombindungen aneinander gebunden werden. Es liegt daher nahe, die Atome über einen eigenen Entitytyp Atom zu modellieren. Jedes Atom besitzt eine Reihe von Eigenschaften, die es von anderen Atomen unterscheidbar machen. Die vielleicht wichtigste Eigenschaft jedes Atoms ist sein Typ, der wiederum über die spezifische Zusammensetzung einer Reihe von weiteren Merkmalen charakterisiert wird. Eine mögliche Modellierungsform für Atomtypen im ER-Modell bietet das Konzept der zusammengesetzten Attribute. Dabei wird das Attribut als Zusammensetzung mehrerer Felder definiert. Der Nachteil dieser Modellierungsart ist, daß unter Umständen die Daten mehrfach gespeichert werden können. Dies geschieht dann, wenn das gleiche zusammengesetzte Attribut als Attribut für mehrere Entities des jeweiligen Entitytyps benutzt wird. In solchen Fällen lassen sich die zusammengesetzten Attribute auch als separate Entitytypen modellieren, die dann mit dem jeweiligen ursprünglichen Entitytyp in Beziehung stehen. Aus demselben Grund wird der Typ des Atoms im ER-Modell als ein separater Entitytyp Atomtype modelliert, denn es ist durchaus möglich, daß mehrere Atome denselben Atomtyp besitzen. Der Entitytyp Atomtype steht dann über den Relationshiptyp Atom has Atomtype mit dem Entitytyp Atom in einer 1 : N Beziehung (Abbildung 4.1). Die Moleküle selbst werden über den Entitytyp Fragment modelliert, denn sie sind - wie Atome ebenfalls wohldefinierte Objekte der kombinatorischen Bibliotheken. Die Informationen darüber, welche Fragmente aus welchen Atomen bestehen, ist im Relationshiptyp Atom in fragment zwischen den Entitytypen Atom und Fragment festgehalten. Dieser Relationshiptyp stellt eine allgemeine binäre M : N Beziehung dar (Abbildung 4.2). KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 33 Abbildung 4.2: Die Entitytypen Atom und Fragment stehen über den Relationshiptyp Atom in Fragment in einer M : N Beziehung. Aufgrund der Tatsache, daß die Existenz der Atombindungen innerhalb der Fragmente abhängig von der Existenz der Fragmente ist (es gibt also keine Atombindung innerhalb eines Fragmentes, ohne die Existenz des Fragmentes), kann man sie prinzipiell nicht als autonome Objekte und daher auch nicht als Entitytypen darstellen. Stattdessen können sie entweder als schwacher Entitytyp oder als Beziehungstyp modelliert werden. Die Entscheidung für einen der beiden Typen hängt von deren Anwendung innerhalb des Modells ab. Wenn man - ähnlich wie bei den Atomeigenschaften - die Eigenschaften von Atombindungen als einen separaten Entitytyp modellieren wollte, müßte man diese als schwachen Entitytyp definieren, weil es im ER-Modell keine Beziehung mit der Beteiligung von Relationshiptypen geben darf. Da hier die Atombindungen nur atomare Attribute besitzen und nicht mit weiteren Entitytypen in Beziehung stehen sollen, werden sie als ein Relationshiptyp Atombond in fragment zwischen den Entitytypen Atom und Fragment modelliert. Diese Beziehung ist eine allgemeine ternäre M : N : L Beziehung, in der jedes Atom entweder die Rolle des ersten Atoms (Atom A) oder des zweiten Atoms (Atom B ) in der Atombindung übernimmt (Abbildung 4.3). Abbildung 4.3: Atombindungen werden als Relationshiptyp Atombond in fragment zwischen den Entitytypen Atom und Fragment in der allgemeinen ternären M : N : L Beziehung modelliert. Jedes Atom übernimmt entweder die Rolle des ersten (Atom A) oder zweiten Atoms (Atom B ). 4.1.2 Modellierung der kombinatorischen Natur der Bibliotheken Vor der Erklärung dieses Teilschemas soll noch einmal daran erinnert werden, daß eine kombinatorische Bibliothek eine Sammlung von mehreren R-Gruppen ist. Mit anderen Worten ist sie eine Menge der Menge von Fragmenten, die in R-Gruppen zusammengesetzt sind. Kombinatorische Bibliotheke werden über den Entitytyp Combinatorial Library repräsentiert. Die R-Gruppen der Bibliotheken werden ebenso über einen eigenen Entitytyp Fragment List modelliert, da sie innerhalb jeder Bibliothek autonome Einheiten sind, die auch nach der Auflösung der Bibliothek weiterhin existieren. Wäre dieses nicht so, wären also die R-Gruppen mit der Auflösung der jeweiligen Bibliothek verschwunden, müßten sie zum Beispiel als schwacher Entitytyp definiert werden, der dann in seiner Existenz abhängig vom übergeordneten KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 34 Entitytyp Combinatorial Library wäre. Der Relationshiptyp Fragment List in CombilLib bietet dem Anwender die Möglichkeit herauszufinden, aus welchen R-Gruppen die jeweilige Bibliothek besteht. Da jede Bibliothek aus beliebig vielen R-Gruppen bestehen kann und auch jede R-Gruppe in verschiedenen Bibliotheken benutzt werden darf, ist diese Beziehung eine allgemeine M : N Beziehung (Abbildung 4.4). Abbildung 4.4: Der Relationshiptyp Fragment List in CombilLib ist eine allgemeine M : N Beziehung. Er bietet dem Anwender die Möglichkeit herauszufinden, aus welchen R-Gruppen die Bibliothek besteht. Wie bereits in (2.6.2) erwähnt, ist ein Bibliotheksmolekül eine Kombination von bis zu zehn R-Gruppen. Davon ist eine R-Gruppe (R-Gruppe 0) Core und bis zu neun weitere sind Rest-Gruppen, wobei zum Zusammensetzen eines solchen Moleküls aus dem Core genau ein und aus weiteren R-Gruppen maximal ein Fragment ausgewählt werden darf. Die so ausgewählten Fragmente werden dann über Atombindungen aneinander gebunden. Mit derselben Begründung wie bei den Atombindungen innerhalb der Fragmente in (4.1.1) werden auch die Atombindungen zwischen den Fragmenten der Bibliotheksmoleküle über den Relationshiptyp Atombond between Fragments modelliert. Dabei wird ein Atom (Atom A) aus dem Vorgänger-Fragment (predecessor ) mit einem Atom (Atom B ) aus dem NachfolgerFragment (successor ) verbunden. Solche Verbindungsatome können prinzipiell auch in anderen Fragmenten als Verbindungsatom benutzt werden. Ebenso können die Bindungsstellen eines Fragmentes variieren, daher ist der Relationshiptyp Atombond between Fragments eine allgemeine quartäre M : N : K : L Beziehung (Abbildung 4.5). Wie man hier sieht, besteht jedes Bibliotheksmolekül nicht aus den eigentlichen R-Gruppen, sondern aus den Alternativfragmenten der R-Gruppen. Eines dieser Fragmente - das Fragment aus der R-Gruppe 0 - bildet das Core-Fragment und die weiteren - aus den übrigen R-Gruppen - bilden die Rest-Fragmente des jeweiligen Moleküls. Die Bibliotheksmoleküle werden über den Entitytypen CLib Molecule modelliert. KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 35 Abbildung 4.5: Atombindungen zwischen Fragmenten der Bibliotheksmoleküle werden über den Relationshiptyp Atombond between Fragments - eine allgemeine quartäre M : N : K : L Beziehung - modelliert. Ein (Atom A) des Vorgänger-Fragments (predecessor ) wird mit einem (Atom B ) des Nachfolger-Fragments (successor ) verbunden. Die Core- und Restfragmente der Bibliotheksmoleküle werden über zwei ternäre Relationshiptypen - Is Core Of und Is Rest Of - zwischen den Entitytypen CLib Molecule, Fragment und Fragment List modelliert (Abbildung 4.6). Der Grund für die Modellierung dieser Konzepte als Relationships liegt darin, daß die Core und Restfragmente eines Bibliotheksmoleküls solange existieren, wie das Molekül selbst noch vorhanden ist. Löst man ein Bibliotheksmolekül auf, existieren zwar die Fragmente als einzelne Objekte (daher die Modellierung der Fragmente als Entitytypen), nicht aber als Core- oder Restfragmente eines bestimmten Bibliotheksmoleküls. Abbildung 4.6: Die Core- und Restfragmente werden über zwei ternäre Relationshiptypen Is Core Of und Is Rest Of - zwischen den Entitytypen CLib Molecule, Fragment und Fragment List modelliert. Die Einschränkungen der Anzahl der in den Beziehungen Is Core Of und Is Rest Of beteiligten Entitäten werden jeweils über M : 1 : 1 und M : 1 : N Funktionalitäten ausgedrückt. Damit kann man diese Beziehungen als eine partiellen Funktion auffassen, die sich wie folgt beschreiben läßt: Is Core Of : CLib Molecule × Fragment List → Fragment Is Core Of : CLib Molecule × Fragment → Fragment List Is Rest Of : CLib Molecule × Fragment List → Fragment Wie weiter oben erwähnt, werden die Fragmente eines Bibliotheksmoleküls über Atombindungen paarweise miteinander veknüpft. Da an dieser Stelle noch keine Informationen über die Modellierung von Atomen vorliegen, wird die Art und Weise der Modellierung von Atombindungen zwischen den Fragmenten erst im nächsten Abschnitt erläutert. KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 36 Für jeden der bis jetzt vorgestellten Entitytypen wird lediglich ein einziges Attribut vorgesehen, dessen Wert das zugeordnete Entity eindeutig innerhalb aller Entities seines Typs identifizierbar macht, daher kann das auch als Schlüsselattribut angesehen werden. Für die Relationshiptypen wurde hingegen keine zusätzlichen Attributen vorgesehen. Wie bereits in (2.1) erwähnt, ist ein Fragment ein spezielles, offenes Molekül. Auch ein Bibliotheksmolekül kann man als ein besonderes Molekül ansehen, das durch die Kombination von Fragmenten zustande kommt. Um das Schema besser zu struktuieren, kann man diesen speziellen Entitytypen über Generalisierung einen Obertyp Molecule zuweisen. Damit sind sowohl Fragment als auch CLib Molecule vom Typ Molecule, die zusätzlich zu den Molecule-Attributen auch ihre eigenen Attribute besitzen können (Abbildung 4.7). Abbildung 4.7: Generalisierung des speziellen Entitytyps über einen Obertyp Molecule. Damit sind sowohl Fragment als auch CLib Molecule vom Typ Molecule und können zu den MoleculeAttributen auch ihre eigenen Attribute besitzen. Zusätzlich zu den bislang vorgestellten Entity- und Relationshiptypen kann man im ER-Schema noch zusätzlich erweiterte Relationshiptypen (engl. extended relationships) definieren. Damit kann man die Entity- und Relationshiptypen mit anderen schon modellierten erweiterten Relationshiptypen transitiv auf verschiedenste Art und Weise verbinden und dadurch weitere neue Relationshiptypen gewinnen. Die bisher beschriebenen Komponenten werden nun kompakt in einem globalen Schema abgebildet (Abbildung 4.8). KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 4.2 37 Logischer Entwurf Bereits im Abschnitt (3.1.2) wurden ausführlich die Prinzipien zur Umsetzung des Ergebnisses der ER-Modellierung in das relationale Datenmodell diskutiert. Es wurde deutlich, daß die zwei wesentlichen Konzepte des ER-Modells - die Entity- und Relationshiptypen - im relationalen Datenmodell in Relationen abgebildet werden. Hier wird die Transformation des Ergebnisses der ER-Modellierung gemäß der dort beschriebenen Regeln vorgestellt. 4.2.1 Darstellung von Entitytypen als Relationen Wie in (3.1.2) beschrieben, wird jeder Entitytyp in eine Relation abgebildet. Diese werden hier vorgestellt: Combinatorial Library Fragment List CLib Molecule Fragment Atom Atomtype : : : : : : {[Name]} {[Name]} {[Name]} {[Name]} {[nof H, f charge, chirality, donor acceptor, p charge]} {[element, nof bonds, hybridization, free valence, coordination nr, vdW radius]} Hier wird in den eckigen Klammern angegeben, welche Attribute für die einzelnen Tupeln vorhanden sind. Die geschweiften Klammern drücken aus, daß es sich bei einer Instanz einer Relation um eine Menge von Tupeln handelt. Eine Instanz einer Relation ist dann als Menge von Tupeln {[...]} aufzufassen. Im Übrigen wird der Primärschlüssel der Relation durch Unterstreichung gekennzeichnet. An dieser Stelle wurde die Modellierung der Generalisierung von Fragment und CLib Molecule zu Molecule nicht vorgestellt, weil das relationale Modell über keine Vererbungskonstrukte verfügt. Dazu könnte man zwar die verfügbaren Strukturen zur Imitation des Generalisierungskonzeptes nutzen, jedoch wird dabei nicht die volle Information verfügbar sein. (Für weitere Informationen, siehe [uA01]). Später wird diese Modellierung mit Hilfe des Sichtenkonzeptes in SQL erklärt. 4.2.2 Darstellung von Relationshiptypen als Relationen Zur Umsetzung der Relationshiptypen in das relationale Schema wird jeder Typ im InitialEntwurf ähnlich wie die Entitytypen in eine Relation abgebildet. Einige dieser Relationen können dann bei der Schemaverfeinerung in andere Relationen eingebettet und damit eliminiert werden. Somit ergeben sich bei dem Initial-Entwurf folgende Relationen: Atombond between Fragments : {[nof H a, f charge a, chirality a, donor acceptor a, nof H b, f charge b, chirality b, donor acceptor b, predec fragment name, succec fragment name, type, rotatibility]} Is Core of : {[clib molecule name, fragment name, fragment list name]} Is Rest of : {[clib molecule name, fragment name, fragment list name]} Fragment in Fragment List : {fragment name, fragment list name]} Fragment List in CombiLib : {[fragment list name, combilib name]} KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN Atombond in Fragment Atom in Fragment Atom has Type 38 : {[nof H a, f charge a, chirality a, donor acceptor a, nof H b, f charge b, chirality b, donor acceptor b, fragment name, type, rotatibility]} : {[nof H, f charge, chirality, donor acceptor, fragment name]} : {[nof H, f charge, chirality, donor acceptor, element, nof bonds, hybridization]} Auch in diesem Relationenschema sind die Schlüssel durch Unterstreichung gekenzeichnet. Da hier jede Relation nur eine einzige Attributmenge als Schlüssel besitzt, ist diese gleichzeitig auch der Primärschlüssel der Relation. Zuerst werden die Umsetzung der allgemeinen Beziehungen Fragment in Fragment List, Fragment List in CombiLib, Atom in Fragment, Atombond in Fragment und Atombond between Fragments betrachtet. Generell bildet in allen Relationen die Menge aller Fremdschlüsselattribute den Schlüssel der jeweiligen Relation. Die Beziehungen Atombond in Fragment und Atombond between Fragments sind rekursive M : N : L und M : N : K : L Beziehungen. Bei der relationalen Modellierung von Atombond in Fragment wurden die Rollen des ER-Schemas, nämlich die Atom A und Atom B als Attributnamen gewählt. Da es sich hier um eine allgemeine Beziehung handelt, werden im Schlüssel der Relation Atombond in Fragment beide Attribute {Atom A, Atom B } vertreten sein. Genauso ist es auch bei der relationalen Umsetzung von Atombond between Fragments, in der die Menge {Atom A,Atom B, predecessor,successor } eine Teilmenge der Schlüsselmenge der Relation bildet. Anders als die relationale Umsetzung obiger Beziehungen verläuft die Umsetzung der Relation Atom has Type. Da ein Atom nur einen Atomtyp besitzt, hat die zugehörige Relation Atom has Type den Schlüssel {nof H, f charge, chirality, donor acceptor}. Dies kann sich auch aus der funktionalen Sichtweise ergeben, bei der man die obige Beziehung als eine partielle Funktion der folgenden Form auffassen kann: Atom has Type : Atom → Atomtype Diese Ähnlichkeit in der Argumentation kann man auch bei der relationalen Umsetzung der Relationen Is Core of und Is Rest of benutzen, deren funktionale Formen im letzten Abschnitt beschrieben wurden. Somit besitzen die entsprechenden Relationen jeweils die Schlüssel {clib molecule name} und {clib molecule name, fragment list name}. Schemaverfeinerung Im Abschnitt (3.1.3) wurde ersichtlich, daß die Relationen der 1 : 1, 1 : N und N : 1 Beziehungen aus dem Initialentwurf eines relationalen Schemas in andere Relationen des Schemas eingeführt werden können. Dabei werden einige der Relationen aus dem Initial-Entwurf gelöscht. Das geschieht hier bei der Relation Atom has Type. Im Initialentwurf gab es die drei Relationen: Atom has Type : {[nof H, f charge, chirality, donor acceptor, element, nof bonds, hybridization]} Atomtype : {[element, nof bonds, hybridization, free valence, coordination nr, vdW radius]} Atom : {[nof H, f charge, chirality, KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 39 donor acceptor, p charge]} Nach den in (3.1.3) beschriebenen Regeln kann man die Relationen Atom und Atom has Type zusammenfassen, so daß von diesen drei Relationen nur zwei Relevante übrig bleiben: Atomtype : {[element, nof bonds, hybridization, free valence, coordination nr, vdW radius]} Atom : {[nof H, f charge, chirality, donor acceptor, p charge, element, nof bonds, hybridization]} Hier stellt die Menge {element, nof bonds, hybridization} einen Fremdschlüssel auf die Relation Atomtype dar. Da jedes Atom nur einen Typ besitzen kann, gibt es für jedes Tupel aus Atom nur ein einziges Tupel aus Atomtype, das über die Attributmenge {element, nof bonds, hybridization} referenziert wird. 4.3 SQL-Implementierung Nachdem das relationale Schema fertig entworfen ist, könne jetzt die Tabellen (Relationen) definiert werden. Nach der Definition eines Datenbankschemas mittels des CREATE SCHEMA-Befehls können die Tabellen über den CREATE TABLE-Befehl erzeugt werden. Exemplarisch wird die Erzeugung der Tabelle Atom hier dargestellt: 1: CREATE TABLE Atom( 2: nof_H NUMBER(2), 3: f_charge NUMBER(3,2), 4: chirality NUMBER(2), 5: donor_acceptor NUMBER(2), 6: p_charge NUMBER(4,3), 7: element VARCHAR2(2), 8: nof_bonds NUMBER(2), 9: hybridization NUMBER(2), 10: PRIMARY KEY (nof_H,f_charge,chirality,donor_acceptor), 11: FOREIGN KEY (element,nof_bonds,hybridization) 12: REFERENCES Atomtype (element,nof_bonds,hybridization) 13: ); Das Erzeugen einer neuen Tabelle beginnt mit der ersten Zeile, in der nach dem Befehl CREATE TABLE der Name Atom für die Tabelle festgelegt wird. Dann folgt zwischen den Zeilen 2 bis 9 die Liste der Atribute und ihrer Typen, die jeweils durch Komma getrennt werden. Nach der Typangabe könnte hier noch zusätzlich die NOT NULL Integritätsbedingung folgen. In Zeile 10 wird die Integritätsbedingung PRIMARY KEY definiert, womit die Menge der Schlüsselattribute für die Tabelle festlegt wird. Die Zeilen 11 und 12 definieren zusammen den Fremdschlüssel der Tabelle Atom, über den mit Hilfe der Attributenmenge {element, nof bonds, hybridization} aus der Tabelle Atom die Tabelle Atomtype referenziert wird. Schließlich wird die Definition in der 13. Zeile beendet. Es ist zu beachten, daß die Tabelle Atom später um eine weitere Spalte id erweitert wurde. Auf den Grund für diese Erweiterung wird im Kapitel 6 eingegangen. KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 40 Es wurde in diesem Kapitel bereits erklärt, daß das relationale Datenmodell über keine Vererbungskonstrukte verfügt. Diese kann man aber - wie bereits in (3.2.2) beschrieben - mit Hilfe von Sichten in SQL modellieren. Dazu gibt es prinzipiell zwei Möglichkeiten: entweder existiert der Obertyp als Tabelle bzw. Relation und die Untertypen werden als Sicht modelliert oder die Untertypen liegen physisch vor und der Obertyp wird als Sicht definiert. Hier liegen die beide Tabellen CLib Molecule und Fragment vor, daher wird der Obertyp Molecule über die folgende Sichtendefinition definiert: CREATE OR REPLACE VIEW Molecule AS SELECT name FROM Fragment UNION SELECT name FROM CLib_Molecule; Der Vorteil dieser Art von Modellierung ist, daß es zu keiner Duplizierung der Attributwerte kommt. Der Nachteil liegt jedoch darin, daß der Zugriff auf die Attribute des Obertyps Molecule - wegen der Vereinigung der Attribute von CLib Molecule und Fragment über einen UNION-Operator - langsam ist. Auch die erweiterten Relationshiptypen werden mit Hilfe von Sichten realisiert. Zur Definition eines neuen erweiterten Relationshiptyps zwischen zwei Typen des Schemas kombiniert man alle Entity- und (erweiterten) Relationshiptypen auf dem Pfad zwischen den beiden Typen in Form einer SQL-Anfrage, die dann mit Hilfe einer Sicht dargestellt wird. KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 41 Abbildung 4.8: Globales ER-Schema für kombinatorische Bibliotheken: erweiterte Relationshiptypen sind durch gestrichelte, normale Relationshiptypen durch durchgezogene Linien dargestellt. KAPITEL 4. MODELLIERUNG KOMBINATORISCHER BIBLIOTHEKEN 42 Abbildung 4.9: Die SQL-Implementierung des relationalen Schemas für kombinatorische Bibliotheken. Kapitel 5 Die Programmierumgebung Nachdem das Datenbankschema bereit ist, kann es nun mit den entsprechenden Informationen gefüllt werden. Um dieses Ziel zu erreichen muß man zunächst die Daten der kombinatorischen Bibliotheken, die in Form von ASCII-Dateien zur Verfügung stehen, zum Schreiben in die Datenbank vorbereiten. Eine Lösung ist, die Bibliotheksdaten direkt über einen Parser aus den ASCII-Dateien zu lesen um sie dann in die Datenbank zu schreiben. Dies erfordert vor allem ein Parser-Programm, das die o.g. Aufgabe erfüllen kann. Eine zweite Variante ist die Nutzung der FlexX-spezifischen Datenstrukturen für kombinatorische Bibliotheken. Wie bereits in (2.6.2) erwähnt, verfügt FlexX mit dem Modul FlexXC über die Möglichkeit, Dockingberechnungen an kombinatorischen Bibliotheken durchzuführen. Dazu liest FlexX die Bibliotheksdaten aus den ASCII-Dateien, fügt ihnen weitere physiko-chemische Eigenschaften hinzu und legt sie dann in seinen entsprechenden Datenstrukturen ab (Abbildung 5.1). Unter diesen Daten befinden sich auch jene, die für die Datenbanktabellen benötigt werden. In der vorliegenden Arbeit habe ich mich vor allem deshalb für die zweite Variante entschieden, weil die Zusammensetzung von Bibliotheksinformationen aus den ASCII-Dateien über spezifische, zum Teil komplizierte Verfahren geschieht, die schon in FlexX realisiert wurden. Daher werden in diesem Kapitel zuerst die Datenstrukturen vorgestellt, deren Verständnis für die Implementierung eines Programms zum Zugriff auf diese Daten nötig ist. Danach werden die Programmiersprache Python und das in dieser Sprache eingebettete Modul pyflexx vorgestellt, die vor allem die Möglichkeit zum Datentransport in die Datenbank bietet. 5.1 FlexX-Datenstrukturen für kombinatorische Bibliotheken Die Architektur der Datenstrukturen in FlexX ist auf drei Ziele ausgerichtet. Erstens: man behandelt die Bibliotheken in ihrer geschlossenen Form, d.h. sie werden statt über eine durchnummerierte Liste ihrer Moleküle über ihre R-Gruppen-Fragmente repräsentiert. Das führt zur Zeitersparnis beim Generieren von Molekülen, indem man nur die tatsächlich benötigten Moleküle der R-Gruppen generiert. Zweitens: die Datenstrukturen müssen zur effizienten Konstruktion von Bibliotheksmolekülen geeignet sein. Dazu müssen sie in der Lage sein alle physiko-chemischen Daten behandeln zu können, die zur Dockingberechnungen nötig sind. Drittens: die Datenstrukturen müssen eine effiziente Transformation der Dockingergebnisse eines Moleküls der Bibliothek zu einem anderen erlauben. Zum Erreichen dieser Ziele wurden folgende Datenstrukturen für kombinatorische Bibliotheken in FlexX implementiert: 43 KAPITEL 5. DIE PROGRAMMIERUMGEBUNG 44 Abbildung 5.1: Interaktion zwischen FlexX, pyflexx und der Datenbank. Ein Molekül wird in FlexX durch ein Netz von Listen gespeichert (Abbildung 5.2). Jede Liste enthält Informationen über spezifische Objekte wie Atome (Datenstruktur atom), Atombindungen (Datenstruktur bond ) oder Ringsysteme (Datenstruktur ringsystem). Jedes Objekt wird im Laufe der Strukturinitialisierung mit physiko-chemischen Daten markiert. Das Fragment eines Cores oder einer R-Gruppe wird intern ähnlich wie ein komplettes Molekül behandelt mit zusätzlichen Informationen über die Verbindungsatome. Die Sequenz der Fragmente eines Bibliotheksmoleküls wird in der Datenstruktur intlist gespeichert. Diese ist eine einfache verkette Liste, die nur Integerwerte enthält. So verweist das 0. Element der Liste auf das Core-Fragment und das i-te Element der Liste auf das i-te Fragment des jeweiligen Bibliotheksmoleküls. Die Bibliotheksdaten in FlexX werden in der Datenstruktur combilib abgelegt (Abbildung 5.3). Diese besteht aus den Datenfeldern, die die interne Repräsentation einer kombinatorischen Bibliothek in FlexX in geeigneter Weise ermöglichen. Hier sind unter anderem der Name der kombinatorischen Bibliothek, die Anzahl und Namen der R-Gruppen der Bibliothek und die Anzahl der Fragmente jeder R-Gruppe enthalten. Das Lesen der Bibliotheksdaten aus den ASCII-Dateien erfolgt über die read -Operation in FlexXC . Diese liest die ASCII-Dateien, zerlegt sie in einzelne Informationsteile und vervollständigt sie dann mit weiteren physiko-chemischen Informationen. Das Zerlegen der ASCII-Dateien geschieht über das Parser-Programm, das spezifisch für das Format der ASCII-Dateien ist. Das Einlesen von Bibliotheksdaten wird dann über die close-Operation beendet. Nachdem die Bibliotheksdaten vollständig in der Datenstruktur combilib gespeichert wurden, KAPITEL 5. DIE PROGRAMMIERUMGEBUNG 45 Abbildung 5.2: Der Aufbau der Datenstruktur molecule kann man jetzt daraus einzelne Moleküle durch das Kombinieren von Fragmenten zusammenbauen und sie dann wie einzelne Moleküle bei den Dockingberechnungen verwenden. Das so entstandene Molekül wird dann in FlexX in der Datenstruktur clib molecule abgespeichert (Abbildung 5.4). Die clib molecule-Datenstruktur verfügt außerdem über einige Datenfelder, die sämtliche Informationen über das jeweilige Bibliotheksmolekül enthalten. Innerhalb der beiden Datenstrukturen combilib und clib molecule gibt es Verweise auf die zwei Basis-Datenstrukturen molecule und atom. FlexXC verfügt über die extend -Operationen, die eine virtuelle Synthese von Bibliotheksmolekülen ermöglichen. Diese fügt ein R-Guppenfragment entweder zum Core oder einem partiell synthetisierten Bibliotheksmolekül. Eine weitere Operation, die remove-Operation, macht das Gegenteil der extend -Operation, d.h. durch sie wird die entstandene Atombindung gelöscht, die X - und R-Atome werden wieder in den bond - und ring system-Listen eingefügt und die Verknüpfung zwischen den Listen wieder aufgelöst. Somit wird nur die letzte hinzugefügte R-Gruppe entfernt. Anhand dieser Datenarchitektur kann man ein kombinatorisch aufgebautes Molekül als einen Stapel (engl. stack ) von selektierten R-Gruppenfragmenten ansehen. Mit jeder extend -Operation wählt man eine R-Gruppe und ein Fragment dieser R-Gruppe und legt es auf den Stapel. Mit der remove-Operation ist man in der Lage das R-Gruppenfragment vom obersten Level des Stapels zu entfernen. Damit kann man durch das Entfernen einiger R-Gruppenfragmente und Hinzufügen neuer Fragmente von einem Molekül der Bibliothek zum anderen Molekül wechseln. Die R- Abbildung 5.3: Der Aufbau der Datenstruktur combilib KAPITEL 5. DIE PROGRAMMIERUMGEBUNG 46 Abbildung 5.4: Der Aufbau der Datenstruktur clib molecule Gruppenfragmente, die innerhalb dieses Prozesses unverändert bleiben stellen den gemeinsamen Teil zwischen zwei Molekülen dar. Die Plazierungsinformationen, die für diesen Teil berechnet wurden, können für das neue Molekül ohne Modifizierung benutzt werden. 5.2 Das Python-Modul pyflexx Um die Konstrukte einer Script-Sprach für die FlexX-Anwendungen nutzen zu können, wurde der FlexX-Code als ein autonomes Modul in der Script-Sprache Python eingebettet. Das entsprechende Python-Modul wurde pyflexx genannt. Im folgenden wird diese Script-Sprache und danach das Pyhton Database API kurz vorgestellt, die über die DCOracle2-Schnittstelle eine Möglichkeit zur Kommunikation mit der DBMS Oracle bietet (ausführlicherre Informationen über Python sind in [Mar03, MA02] zu lesen). 5.2.1 Die Programmiersprache Python Python ist eine dynamische, objekt orientierte, plattformunabhängige Programmiersprache. Sie läuft unter allen Hauptbetriebsystemen, wodurch es bei der Nutzung dieser Sprache keine Einschränkung gibt. Python lässt sich in mehreren Stellen eines Softwareentwicklungsprozesses einetzen, unter anderem in Analyse, Design, Kodierung, Testing, Fehlersuche, Dokumentation und vieles mehr. Python benutzt - im Vergleich mit klassischen Hochsprachen wie C/C++ oder Fortran - einen höheren Level der Abstraktion. Daher ist sie eine zum Lernen einfache Sprache, die aber gleichzeitig mächtig genug für anspruchsvolle Aufgaben ist. Python ist eine objekt-orientierte Sprache. Gleichzeitig bietet sie dem Programmierer die Möglichkeit, neben den objekt-orientierten Konzepten auch die traditionellen prozeduralen Konzepte einzusetzen und beide miteinander zu kombinieren. Zusätzlich zu der Sprache selbst verfügt man in Python über Standard-Bibliotheken und andere Erweiterungsmodule, die zur effektiven Verwendung von Sprache meist genauso wichtig sind KAPITEL 5. DIE PROGRAMMIERUMGEBUNG 47 wie die Sprache selbst. Die Standard-Bibliotheken in Python enthalten Module, die komplett in Python geschrieben sind. Sie enthalten unter anderem Module zur Daten- und Textverarbeitung, Interaktion mit dem File- und Betriebsystem und Webprogrammierung. Da diese Module alle in Python geschrieben sind, sind sie überall verwendbar, wo Python eingesetzt werden kann. Die Erweiterungsmodule der Standard-Bibliothek oder von anderen Bibliotheken ermöglichen es den Pythonapplikationen, die Funktionalität anderer Softwarekomponenten wie etwa graphische Benutzerschnittstellen (GUIs), Datenbanksysteme und Netzwerke nutzen zu können. Pythonprogramme können zwischen mehreren Programmiersprachen komunizieren, so daß damit mehrere Softwarekomponenten miteinander verbunden werden können, die möglicherweise in verschiedenen Sprachen geschrieben sind. 5.2.2 Python Database API Die Python Standard-Bibliothek enthält keine Schnittstelle zu einem relationalen DBMS. Trotzdem gibt es eine Reihe von frei verfügbaren Module, die die Kommunikation zwischen den Pythonapplikationen und einem bestimmten RDBMS ermöglichen. Diese Module basieren meistens auf dem Python Database Application Programmers Interface 2.0 -Standard (kurz DBAPI ) basiert. Die am meisten benutzte Oracle-Schnittstelle für Python ist die DCOracle2 Schnittstelle, die unter [Zop] frei verfügbar ist. Das Prinzip von Python API ist relativ einfach. Nach dem Importieren eines DBAPI-verträglichen Modules ruft man die connect-Funktion des Moduls mit entsprechenden Variablen auf, die eine Instanz der Klasse Connection zurück liefert. Diese repräsentiert eine Verbindung zu einem DBMS und bietet die Methoden commit und rollback zur Handlung mit Transaktionen, eine close-Methode zum Schließen der Verbindung mit dem DMBS und eine cursor -Methode, die eine Instanz der Klasse Cursor liefert. Diese Instanz liefert dann alle Methoden, die man für die Datenbankoperationen benutzt. Zusätzlich zu den o.g. Diensten bieten solche Modulen noch weitere Klassen und Attribute wie zum Beispiel die exception Klasse zum Abfangen und Behandeln von möglichen Fehlern bei der Ausführung von den DBMS-Operationen. Ein Beispiel Zum besseren Verständnis der Funktionsweise einer DBAPI soll das folgende Beispiel dienen, das eine SELECT-Anfrage modelliert: Als erstes wird eine Verbindung mit der Datenbank hergestellt: con = DCOracle2.connect(’user/password@schema’) dann wird ein cursor erzeugt: cur = con.cursor() die DB-Anfrage wird in Form eines Strings formuliert: sql = ’SELECT * FROM my_table t WHERE t.field = %s’ % value KAPITEL 5. DIE PROGRAMMIERUMGEBUNG 48 hier wird vor allem die Möglichkeit gezeigt, wie man Parameterwerte in den SQL-Anfragen einsetzen kann. Dazu gibt es mehrere Möglichkeiten die bei z.B. [Mar03] nachgelesen werden können. Die SQL-Anfrage wird zur Ausführung an die execute-Methode weiter gegeben: cur.execute(sql) Auf das Ergebnis der Anfrage wird über die Methoden fetchone auf nur ein Ergebnis, mit fetchall auf alle Ergebnisse oder über fetchmany auf einige bestimmte Ergebnisse zugegriffen: result = cur.fetchone() der so entstandene Parameter result ist dann eine Liste, die im Falle von fetchone ein bzw. im Falle von fetchall oder fetchmany mehrere Ergebniswerte enthält. 5.2.3 Interne Kommunikation in FlexX über STREAM s Jedes nichttriviale Programm verwendet viele eigene Datentypen und die Ein- und Ausgabe von Werten dieser Typen muß auf irgendeine Art verwaltet werden. Eine Ein-/Ausgabe-Technik sollte vor allem einfach, bequem, effizient, flexibel und vollständig sein. Eine dieser Techniken ist die Anwendung von I/O-Streams, womit man unter anderem die Daten innerhalb eines Programms von einem Ort zum anderen transportieren kann. In FlexX ist dazu die Datenstruktur STREAM entwickelt worden, die fast die gesamten Funktionalitäten eines I/O-Streams in den bekannten Programmiersprachen wie beispielsweise C anbietet. Der eigentliche Vorteil von STREAM in FlexX ist aber, daß er Plattform- und sprachunabhängig ist. Somit können die Daten innerhalb verschiedener Sprachen transportiert werden. Diese Funktionalität von FlexX kann man vor allem dazu benutzen, um die Werte von FlexX-Datentypen an Python zu übergeben und umgekehrt. Kapitel 6 Implementierung Das Datenbankschema für kombinatorische Bibliotheken wurde bereits im Kapitel 4 vorgestellt und die FlexX-Datenstrukturen, die die Daten der kombinatorischen Bibliotheken enthalten, im Abschnitt (5.1) diskutiert. Hier sollen Programme vorgestellt werden, die einerseits auf die Bibliotheksdaten in FlexX zugreifen und diese andererseits in der gewünschten Form über eine Datenbankschnittstelle in die Datenbanktabellen hineinschreiben. Zur Verwirklichung des ersten Ziels wurde in der vorliegenden Arbeit ein Compiler-Programm in der Sprache C geschrieben, dessen Prinzip in diesem Kapitel vorgestellt werden soll. Zum Importieren der Daten in die Datenbank braucht man eine Datenbank-Applikation, die eine Verbindung zwischen dem Source-Code und dem DBMS Oracle ermöglicht. Da das CompilerProgramm in C geschrieben ist, müsste man die Verbindung entweder als eingebettete SQL in C oder über die Oracle Call Interface-API erstellen [McC96]. Eine zweite Möglichkeit ergibt sich daraus, daß es FlexX auch als das Python-Modul pyflexx gibt. Da diese Sprache (wie beschrieben in 5.2.2) selber über eine Datenbankschnittstelle verfügt, kann man sie zur Kommunikation zwischen dem Compiler und der Datenbank verwenden. Zuerst wird das Füllen der statischen Tabelle Atomtype beschrieben. 6.1 Füllen der statischen Tabelle Atomtype Wie bereits im Abschnitt (4.2.1) beschrieben, wurde für die Atomtypen der kombinatorischen Bibliotheken eine Extra-Tabelle vorgesehen. Diese ist eine statische Tabelle, Deren Inhalt manuell von den Chemikern vorgegeben ist. Ihr Inhalt bleibt also für alle kombinatorischen Bibliotheken unverändert. Es ist jedoch nicht auszuschliessen, daß in einigen Ausnahmefällen innerhalb der Bibliotheken einige Atome gefunden werden können, deren Typen nicht in dieser Tabelle vorgesehen sind. Solche Fälle werden abgefangen und in einer log-Datei protokolliert. Beim Prüfen dieser Datei kann man also feststellen, ob es Atome gibt, deren Typen nicht in der Tabelle Atomtype enthalten sind. 6.2 Zugriff auf die Datenstrukturen Bibliotheksdaten in den FlexX- Bereits im Abschnitt (5.1) wurde beschrieben, daß in FlexX eine kombinatorische Bibliothek über die read -Operation aus den ASCII-Dateien in das System geladen und nach der Ver49 KAPITEL 6. IMPLEMENTIERUNG 50 Abbildung 6.1: Interaktion zwischen FlexX, pyflexx und der Datenbank und den in dieser Arbeit entwickelten Komponenten (grau unterlegt). vollständigung ihrer Fragmente mit den weiteren physiko-chemischen Eigenschaften in den jeweiligen Datenstrukturen zur Verfügung gestellt wird. Wie bereits weiter oben erwähnt, wurde für diese Arbeit ein Compiler-Programm zur Sammlung und Zusammenstellung der Bibliotheksdaten geschrieben, dessen Ablauf im Folgenden vorgestellt wird. Als erstes sieht der Compiler für jede Datenbanktabelle einen STREAM vor, in denen jeweils später die Datensätze der entsprechenden Tabelle geschrieben werden. Der eigentliche Vorgang beginnt mit der Vorbereitung der Daten für die Tabelle Combinatorial Library. Dazu wird für die kombinatorische Bibliothek ein Identifikator erstellt, wofür der Bibliotheksname benutzt wird. Der Grund für die Nutzung des Names als Identifikator ist die Analogie mit dem Primärschlüssel name der Tabelle Combinatorial Library, in die später dieser Identifikator geschrieben wird. In der Datenstruktur combilib ist ein name-Feld vorgesehen, das den Bibliotheksnamen enthalten soll. Da jedoch in den ASCII-Dateien meist kein Name für die Bibliothek vorhanden ist, ist das Feld name von combilib leer und es wird der Bibliothek daher manuell ein clib name gegeben. 6.2.1 Moleküldaten Nachdem der Compiler die Daten für die Tabelle Combinatorial Library in den jeweiligen STREAM geschrieben hat, startet er im nächsten Schritt eine Schleife S über den R-Gruppen der Bibliothek mit 0 ≤ S ≤ M AX N OF RGROU P S wobei M AX N OF RGROU P S der maximal erlaubten Anzahl von R-Gruppen in der Bibliothek entspricht, also M AX N OF RGROU P S = 9 (Abbildung 6.2) . Für jede R-Gruppe wird überprüft, ob sie keine Fragmente enthält. Wenn KAPITEL 6. IMPLEMENTIERUNG 51 dies der Fall ist, wird die Suche in der nächsten R-Gruppe fortgesetzt. Enthält die R-Gruppe jedoch Fragmente, wird zuerst der R-Gruppe ein eindeutiger Identifikator mit der folgenden Syntax zugewiesen: <fragment_list_name>::=<clib_name>_R<R-group_nr> Hier entspricht clib name dem Namen der Bibliothek, R einem Bezeichner für die R-Gruppe und R-group nr der Nummer der aktuellen R-Gruppe innerhalb der Bibliothek. Danach greift das Programm in einer zweiten Schleife nacheinander auf die Fragmente der aktuellen R-Gruppe zu. Auch hier wird für jedes Fragment einen Identifikator zusammengestellt: <fragment_name>::=<clib_name>_R<R-group_nr>_<fragment_nr> Im Vergleich mit dem fragment list name besteht fragment name aus einem weiteren fragment nr-Feld, das der Nummer des Fragmentes innerhalb der R-Gruppe entspricht. Wie bereits in (5.1) beschrieben, sind die Informationen über Atome und Atombindungen jedes Moleküls in zwei Listen - atom und bond - enthalten. Um diese für jedes Fragment erreichen zu können, werden nacheinander zwei Schleifen, jeweils eine für Atome und eine für Atombindungen des aktuellen Fragmentes gestartet, die die Liste aller Atome und Atombindungen innerhalb eines Fragmentes durchgehen. Zuerst wird nun die Atom-Schleife betrachtet: Im Laufe des Entwicklungsprozesses wurde festgestellt, daß nicht alle Atome der kombinatorischen Bibliothek über ihre Primärschlüsseln in die Tabellen Atom in Fragment, Atombond in Fragment und Atombond between Fragments importiert werden können. Da ich die Ursache für dieses Problem nicht herausfinden konnte, habe ich beschlossen, für die Atome einen Identifikator zu definieren, dessen Wert für jedes Atom der Bibliothek eindeutig ist. Der einfachste Identifikator kann hier eine generische Nummer sein, die man sehr einfach jedem Atom zuweisen kann. Alternativ dazu kann man selber - wie bei den übrigen oben definierten Identifikatoren - für jedes Atom einen Identifikator definieren: <atom_id>::=<clib_name>_R<R-group_nr>_<fragment_nr>_<atom_nr> wobei im Vergleich mit dem fragment name das neu dazugekommene Feld <atom nr> der Nummer des Atoms innerhalb des Fragmentes entspricht. Hier wurde die zweite Variante gewählt, weil zum Einen alle bis dahin definierten Identifikatoren demselben Prinzip folgen und zum Anderen aus dem so definierten Identifikator mit einem Blick das Fragment, die R-Gruppe und Bibliothek des Atoms festgestellt werden kann. Dies ist besonders beim Debugging der späteren Datenbank-Anwendung von großem Vorteil. Bereits in (5.1) wurde erläutert, daß die Bindungstellen der R-Gruppen-Fragmente als spezielle Verbindungsatome - X - und R-Atome - markiert werden, über die Atombindungen zwischen den Fragmenten zustande kommen. Da diese Atome nur Platzhalter für die tatsächlichen Verbindungsatome sind und keine weitere Rolle innerhalb des Fragmentes spielen, müssen sie von der Suche ausgeschlossen werden. Daher wird in jedem Suchschritt geprüft, ob das gefundene Atom ein R- oder X -Atom ist. Trifft dies zu, dann wird das Atom übergangen und zum nächsten Atom innerhalb der Kette gesprungen. Die Datenstruktur atom enthält die Felder hybrid, nof bonds, f charge, stereo und charge, die jeweils den Attributen hybridization, nof bonds, f charge, chirality und p charge der Tabelle Atom entsprechen. Daher werden deren Werte für KAPITEL 6. IMPLEMENTIERUNG 52 das Atom übernommen. Im Feld element der atom-Datenstruktur liegt das Element des jeweiligen Atoms als eine Integer-Zahl vor. Dagegen ist das Attribut element der Atom-Tabelle vom Typ char. Die Abbildung der Zahlen in die jeweiligen Element-Bezeichner geschieht über eine switch-case-Anweisung, die jede Zahl dem entsprechenden Bezeichner zuweist. Für die zwei übrig gebliebenen Attribute nof H und donor acceptor der Atom-Tabelle gibt es keine direkten Felder in der Datenstruktur atom. Sie müssen stattdessen indirekt über weitere Datenstrukturen bestimmt werden. Das Attribut nof H der Tabelle Atom entspricht der Anzahl der am Atom direkt gebundenen Wasserstoffatome. Um diese Zahl zu bestimmen, geht man folgendermaßen vor: for (b_p=atom_p->bondlist; b_p; b_p = b_p->next) { if (!b_p->to->r_x_atom_marker && b_p->to->element==1){nof_H_ctr++;} } Ausgehend von dem Atom, auf das mit atom p gezeigt wird, geht man die Liste seiner Atombindungen bondlist durch. Ist das an der Bindung beteiligte Atom ein nicht als X - oder R- Atom markiertes Wasserstoffatom (element==1), inkrementiert man den Zähler nof H ctr. Ob ein Atom Donor- oder Akzeptor ist erkannt man, indem man für das Atom in der Liste m interact den Typ seiner Interaktionen prüft. Nachdem alle Werte für das aktuelle Atom gefunden wurden, werden sie in derselben Reihenfolge in den atom stream geschrieben, nach der die Werte später als eine Zeile in die Tabelle Atom geschrieben werden sollen. Die in den übrigen Iterationen gefundenen Werte für die weiteren Atome werden alle in denselben atom stream geschrieben. Sie werden jedoch durch ein Trennzeichen voneinander getrennt gehalten, damit man sie später beim Schreiben in die Datenbank-Tabelle wieder in die einzelnen Datensätze zerlegen kann. Auch der für die Tabell Atom in Fragment vorgesehene atom in fragment stream wird nach demselben Prinzip wie bei atom stream dargestellt, mit den ensprechenden Werte gefüllt. Hat man alle Atome des aktuellen Fragmentes durchsucht, beginnt man mit der Suche innerhalb der Atombindungen des aktuellen Fragmentes. Bereits aus (5.1) ist bekannt, daß ein X - oder RAtom nur als Platzhalter für die Bindungsatome eines Fragmentes dient und auf das tatsächliche Bindungsatom verweist. Dieses ist das Atom, mit dem es in Verbindung steht. Hier betrachtet man die Atompaare in zwei Haupgruppen: Paare ohne X - oder R-Atom und solche mit einem X oder R-Atom. Für die erste Gruppe werden die Werte der für die Tabelle Atombond in Fragment relevanten Felder aus den Datenstrukturen atom und bond in den bond in stream geschrieben. Die hierzu relevante Menge der Felder der atom-Struktur ist eine Untermenge der Felder, die weiter oben für die Tabelle Atom benutzt wurden. Neu dazu kommen die beiden Felder type und rotatable der Datenstruktur bond, die jeweils den Attributen type und rotatibility der Tabelle Atombond in Fragment entsprechen. Auch die Werte dieser Felder werden für die jeweilige Atombindung in den für die o.g. Tabelle vorgesehenen bond in stream geschrieben. Ebenso werden hier die Werte weiterer Atombindungen in denselben bond in stream getrennt durch Trennzeichen hineingeschrieben. Über die zweite Gruppe der Bindungspaare kann man die Attributwerte einzelner Atombindungen zwischen den Fragmenten bestimmen und sie zum Schreiben in der Tabelle Atombond between Fragments vorbereiten. Dafür geht man folgendermaßen vor: Zuerst wird geprüft, ob die jeweilige R-Gruppe ein Core ist. Ist dies der Fall, werden die Atombindungen wie oben beschrieben durchsucht und auf die Bindungen mit dem R-Atom als Bindungspartner verzichtet. Ist die aktuelle R-Gruppe kein Core, dann wird zuerst das X -Atom KAPITEL 6. IMPLEMENTIERUNG 53 des aktuellen Fragmentes durch sein Partneratom ersetzt. Danach werden auch die R-Atome aller Fragmente der Vorgänger-R-Gruppe durch ihre Partneratome ersetzt. Über die so entstandenen neuen Atome kann das aktuelle Fragment der aktuellen R-Gruppe an die Fragmente der Vorgänger-R-Gruppe gebunden werden. Mit dieser Methode können die Informationen über alle Atombindungen zwischen den Fragmenten gewonnen und dann in den bond between stream geschrieben werden. Am Ende werden die für die weiteren Tabellen vorgesehenen STREAMS mit den jeweiligen Werten gefüllt und schließlich alle zusammen zum Schreiben in die Datenbank an die Datenbank-Schnittstelle weitergegeben. 6.2.2 clib molecule Daten Als nächstes müssen die Attributwerte aller Bibliotheksmoleküle zum Importieren in die dazu vorgesehenen Tabellen CLib Molecule, Is Core of und Is Rest of vorbereitet werden. Dafür benutzt der Compiler eine Funktionalität in FlexX, die ausgehend von einem existierenden clib molecule alle weiteren Bibliotheksmoleküle aufzählt. Hier werden die Moleküle eins nach dem anderen aufgebaut, ohne daß für sie weitere Berechnungen durchgeführt werden. Der Compiler greift auf diese Informationen folgendermaßen zu (Abbildung 6.3): Zuerst wird ein clib molecule mit Hilfe der extract-Operation in FlexXC aus den 0. Fragmenten aller R-Gruppen zusammengesetzt. Für dieses Molekül wird dann ein Identifikator mit folgender Syntax erstellt: <clib_mol_name>::=<clib_name>_<cl_molecule->m->name> Das Feld clib name entspricht - wie bei den, im vorherigen Abschnitt beschriebenen Identifikatoren - dem Bibliotheksnamen. Das Feld cl molecule->m->name repräsentiert den Namen des Bibliotheksmoleküls. Dabei ist m ein Zeiger auf die Datenstruktur molecule, in der das Feld name den Namen des Biliotheksmoleküls enthält. Diesen Identifikator schreibt man dann in den clib mol stream. Im nächsten Durchgang wird die Liste list der Fragmente des Bibliotheksmoleküls geprüft (5.1), in der das erste Element das Core-Fragment und die weiteren die Rest-Fragmente des Moleküls sind. In jeder Iteration werden für das jeweilige Fragment zwei String-Werte erzeugt: <clib_fragment_list_name>::=<clib_name>_R<list_pos> <clib_fragment_name>::=<clib_name>_R<list_pos>_<fragment_name>_<fragment_nr> Hier ist das Feld list pos die Position des aktuellen Fragmentes des Bibliotheksmoleküls innerhalb der Liste list, fragment name der Name und fragment nr die Nummer des aktuellen Fragmentes in der jewiligen R-Gruppe der Bibliothek. Der Grund für das Hinzufügen der fragment nr zum fragment name ist, daß die Fragmentnamen innerhalb der Bibliotheken nicht unbedingt eindeutig sind, so daß es Fälle gibt, wo mehrere Fragmente innerhalb eines Fragmentes mit demselben Namen versehen sind. Sobald die Werte erzeugt sind, werden sie nacheinander in den clib mol core stream und clib mol rest stream geschrieben, wobei die Werte jedes Durchlaufes von den anderen mit einem Trennzeichen getrennt gehalten werden. Sobald die gesamten Bibliotheksmoleküle konstruiert und deren Informationen sowie die Core- und Restfragmentinformationen in die jeweiligen Streams geschrieben wurden, werden die Streams an die Datenbankschnittstelle weitergeleitet. KAPITEL 6. IMPLEMENTIERUNG 6.3 54 Datenimport in die Datenbank Nachdem alle STREAMs mit den jeweiligen Datensätze gefüllt wurden, kann man jetzt beginnen, diese in die Datenbank zu importieren. In der vorliegenden Arbeit wurde zur Kommunikation mit der Datenbank die Python-Datenbankschnittstelle DCOracle2 genutzt. Wie damit einen Schreibzugriff auf die Datenbank erfolgt, wird anhand eines Beispiels verdeutlicht: Beispiel In diesem Beispiel wird das Schreiben der Atom-Daten in die Tabelle Atom exemplarisch dargestellt. Es ist zu beachten, daß die hier gezeigte Python-Funktion stark vereinfacht wurde, damit das Prinzip des Vorgehens deutlicher wird. 1: import DCOracle2 as dbapi2 2: class DB_ACCESS: 3: con=dbapi2.connect(’user/password@schema’) 4: def write_atom(name, str): 5: cur=con.cursor() 6: records=str.split(";") 7: for r in records: 8: sql="INSERT INTO %s VALUES (%s)"%(name,r) 9: try: 10: cur.execute(sql) 11: con.commit() 12: except: Zunächst wird in der 1. Zeile das Modul DCOracle2 in das Programm importiert und über den Alias dbapi2 repräsentiert. Nachdem in 2. Zeile die Klasse DB ACCESS definiert wurde, erfolgt die Verbindung mit der Datenbank in der 4. Zeile über die connect-Funktion der Klasse Connection des Modules DCOracle2. Als Parameter nimmt connect in der gezeigten Form den Benutzernamen user, das Password password und den Namen des Schemas schema, in dem die Tabellen definiert sind. In der 3. Zeile wird die Funktion write atom mit den zwei Parameter name und str definiert, die jeweils dem Namen der Zieltabelle (hier Atom) und der Zeichenkette entsprechen. In str sind die Daten aus dem für die Zieltabelle bestimmten STREAM (hier atom stream) enthalten. Nachdem in der 5. Zeile die Instanz cur der Klasse Cursor erzeugt wurde, muss man vor der Ausführung des INSERT-Befehls zunächst über diese Instanz die lange Zeichenkette str der Atom-Datensätze im atom stream auseinandernehmen, um dann jeden einzelnen Datensatz als eine Zeile in der Tabelle schreiben zu können. Werden die Datensätze in str mit einem Semikolon von einander getrennt gehalten, so kann man sie - wie in der 6. Zeile gezeigt - über die split-Funktion in Python auseinandernehmen und die Datensätze als einzelne Felder in der Liste records ablegen. Daraufhin kann in der 7. Zeile eine for-Schleife gestartet werden, die die Liste records durchgeht. Bei jedem Durchlauf wird in der 8. Zeile eine INSERT-Abfrage als string formuliert, in dem der Name der Zieltabelle Atom und der zu importierende Datensatz eingesetzt werden. Die Ausführung des INSERT-Befehls geschieht in der 10. Zeile über die execute-Methode der Klasse Cursor, die dann über die commit-Funktion der Klasse Connect in der 11. Zeile abgeschlossen wird. Um mögliche Fehler bei dieser Transaktion abzufangen, kann KAPITEL 6. IMPLEMENTIERUNG 55 man die Transaktion zwischen den Zeilen 9 bis 12 in einen try/except-Block setzen und die möglichen Fehler dann beliebig bearbeiten. KAPITEL 6. IMPLEMENTIERUNG 56 Abbildung 6.2: Flußdiagramm zur Darstellung des Zugriffes auf die Moleküldaten der kombinatorischen Bibliotheken in den FlexX-Datenstrukturen. KAPITEL 6. IMPLEMENTIERUNG 57 Abbildung 6.3: Flußdiagramm zur Darstellung des Zugriffes auf die Struktur der Bibliotheksmoleküle der kombinatorischen Bibliotheken in den FlexX-Datenstrukturen. Kapitel 7 Evaluierung Wie bereits in der Einleitung erwähnt, besteht eine der Anwendungsmöglichkeiten für die mittlerweile implementierte Datenbank in der Suche nach spezifischen chemischen Substrukturen innerhalb von kombinatorischen Bibliotheken, deren Informationen mittlerweile in der Datenbank als Tabellen vorliegen. In Kapitel 2 wurde deutlich, daß der Graph eine mögliche Datenstruktur zur Repräsentation chemischer Strukturen ist. Liegt eine chemische Struktur als Graph vor, kann man zur Suche innerhalb der Strukturen auf die für Graphen bekannten Suchalgorithmen, die bereits in (2.2.2) vorgestellt wurden, zurückgreifen und sie für seine Operationen benutzen. Bereits in (2.3) wurde deutlich, daß eine kombinatorische Bibliothek als ein Baum, also einem speziellen Graph, darstellbar ist. Wird die zu suchende Substruktur ebenfalls als Graph repräsentiert, kann man sie mit Hilfe der Suchalgorithmen für Graphen innerhalb der kombinatorischen Bibliotheken aufsuchen. In diesem Kapitel wird zunächst die Realisierung der Views zum Subgraphenisomorphismus auf der Datenbankebene vorgestellt, die eine Breitensuche modelliert. Danach werden die Testergebnisse des Subgraphenisomorphismus in FlexX und auf der Datenbankebene miteinander verglichen. 7.1 Views zum Subgraphisomorphismus In (2.4) wurde dargestellt, daß man die chemischen Substrukturen in zwei Hauptgruppen einfache Ketten und Ringsysteme - aufteilen kann, die im Allgemeinen miteinander kombiniert werden können. Die einfachen Ketten und Ringsysteme sind sich sehr ähnlich, indem beide eine Sequenz von Atomen darstellen, die im ersten Fall offen und im zweiten Fall geschlossen ist. Aus diesem Grund wird zuerst die Suche nach einfachen Ketten realisiert, denn die Suche nach einem Ringsystem läßt sich mit einer leichten Modifikation bei der Modellierung der Substruktur, nämlich der Gleichsetzung des Anfags- und Endatoms, auf die Suche nach einer einfachen Kette zurückführen. Vor der Implementierung der Suchalgorithmen für linearen Ketten innerhalb der Datenbank muss diese zunächst in der für die Suche geeigneten Weise innerhalb der Datenbank vorbereitet werden. Wie bereits in (2.2.1) verdeutlicht, kann man zur Berechnung bzw. zum Operieren auf den Graphen im Computer diesen entweder als eine Adjazenzmatrix oder als eine Sammlung von Adjazenzlisten in Form einer Adjazenzstruktur repräsentieren. Da das relationale Datenmodell 58 KAPITEL 7. EVALUIERUNG 59 Abbildung 7.1: Darstellung einer Kette der Form A-B-C als Tabelle mit dem Anfangsatom A. auf Mengen basiert, wird die Kette in der Datenbank in Form einer Adjazenzstruktur modelliert. Die zu suchende Kette ist ein gerichteter Graph, da man bei der Suche die Atome der Kette von einem Ende zum anderen Ende nacheinander in einer bestimmten Richtung durchläuft und damit für diese Kette eine bestimmte Richtung definiert. Damit wird die Kette in der Datenbank als eine Tabelle subgraph definiert. Diese Tabelle besitzt mindestens vier Spalten: zwei zur Repräsentation der an der Bindung beteiligten Atome, eine - die bond nr -Spalte um die Nummer der aktuellen Atombindung innerhalb der Substruktur darzustellen und die bond type-Spalte zur Repräsentation des Bindungstyps zwischen den beteiligten Atomen. In dieser Tabelle entspricht dann jede Zeile einer Adjazenzliste mit den gesamten Informationen über die aktuellen Atombindung (Abbildung 7.1). In Kapitel 4 wurde dargestellt, daß ein Atom in der Datenbank durch eine Menge von Attributen eindeutig charakterisiert wird. Eigentlich müßten also die beiden Atom-Spalten der Tabelle subgraph die gesamten Atomattribute enthalten. Das ist hier jedoch nicht der Fall, denn bei der ersten Implementierung der Substruktursuche sind lediglich die Sequenzen von Atom-Elementen interessant und es reicht daher, wenn jedes Atom durch sein Element vertreten wird. In den Erweiterungen kann man später die weiteren Atommattribute berücksichtigen, indem man z.B. die Tabelle subgraph um zusätzlichen Spalten erweitert, die diese Atommatribute enthalten. Aus diesem Grund wurden die Atom-Spalten mit element a und element b benannt (Siehe Abbildung subgraph-table). Der Suchraum, in dem nach den gewünschten Substrukturen gesucht werden soll, enthält alle Informationen über die Atome und Atombindungen innerhalb der Fragmente sowie über die Atombindungen zwischen den Fragmenten der kombinatorischen Bibliotheken. Wie bereits in Kapitel 4 beschrieben, werden diese gesamten Informationen in den Tabellen Atom in Fragment, Atombond in Fragment und Atombond between Fragments gespeichert. Diese Tabellen enthalten jedoch nicht alle Informationen über die Atomattribute, die in der Tabelle Atom enthalten sind. Die übrigen Informationen kann man im Suchraum mit dem Joinen der Tabelle Atom mit den o.g Tabellen erreichen. Alternative kann man für jedes Atom in diesen Tabellen das dazugehörige Element direkt in die Tabelle übernehmen. Da das Joinen der Tabellen unter Umständen zur Verlangsamung des Suchprozesses führen kann und weil hier nur das KAPITEL 7. EVALUIERUNG 60 Element als einziges Atomattribut verwendet werden soll, wird an dieser Stelle auf das Joinen der Tabellen verzichtet. Die Atom-Elemente werden in den Tabelle Atom in Fragmentdurch die zusätzliche Spalte atom element und in den Tabellen Atombond in Fragment und Atombond between Fragments durch die zusätzlichen Spalten atom element a und atom element b für die jeweiligen Bindungspartner A und B repräsentiert. Aufgrund der vorgegebenen Richtung für Atombindungen in den ASCII-Dateien und der definierten Reihenfolge, in der die R-Gruppen der Bibliotheken aneinander gebunden werden, sind diese Atombindungen innerhalb der o.g. Tabellen gerichtet abgelegt. Daher kann man ausgehend von einem Atom nur in der vorgegebenen Richtung navigieren. Das ist bei der Suche innerhalb des Suchraumes ein Hindernis, da man in jedem Suchschritt wissen müßte, ob die Suche in der eine oder andere Richtung fortgeführt wird. Um diese Einschränkung aufzuheben und die Suche zu flexibilisieren, wurden die vorgegebenen Richtungen für die Atombindungen aufgehoben. Die Realisierung wurde mit Hilfe der beiden Sichten atom pairs in und atom pairs between erreicht, die für jede Atombindung die Bindungspaare der beiden Bindungstabellen in der vorgegeben und der umgekehrten Richtung ansehen (Abbildung 7.2). 1: CREATE OR REPLACE VIEW atom_pairs_in AS 2: SELECT 3: a1.atom_id AS atom_id_a, 4: a1.atom_element AS atom_element_a, 5: a2.atom_id AS atom_id_b, 6: a2.atom_element AS atom_element_b, 7: a1.fragment_name AS fragment_name, 8: fif.fragment_list_name AS fragment_list_name, 9: aif.type AS bond_type 10: FROM 11: atom_in_fragment a1, 12: atom_in_fragment a2, 13: atombond_in_fragment aif, 14: fragment_in_fragment_list fif 15: WHERE ( 16: aif.atom_id_a = a1.atom_id AND 17: aif.atom_id_b = a2.atom_id AND 18: aif.fragment_name = fif.fragment_name) 19: OR ( 20: aif.atom_id_b = a1.atom_id AND 21: aif.atom_id_a = a2.atom_id AND 22: aif.fragment_name = fif.fragment_name); In der Sicht atom pairs in wird aus dem Joinen der Tabellen atom in fragment und atombond in fragment (11. bis 13. Zeile) eine ungerichtete Version der Atombindungen innerhalb der Fragmente erzeugt. Das Joinen dieser Tabellen geschieht über die Spalten atom id der Tabelle atom in fragment und atom id a sowie atom id b der Tabelle atombond in fragment (16. und 17. sowie 20. und 21. Zeile ), die vom gleichen Typ sind. In KAPITEL 7. EVALUIERUNG 61 der 16. Zeile wird der erste Bindungspartner atom id a aus der Tabelle atombond in fragment mit dem Atom atom id der Tabelle atom in fragment gleich gesetzt. Das so gefundene Atom sowie dessen Element werden dann in den Zeilen 3 und 4 als atom id a und atom element a zur Verfügung gestellt. Der andere Bindugspartner - also atom id b (17. Zeile) - wird zusammen mit seinem Element nach demselben Prinzip in den 5. und 6. Zeilen als atom id b und atom element b repräsentiert. Umgekehrte geschieht es in den Zeilen 20 und 21. Dort wird der zweite Bindungspartner - atom id b aus der Tabelle atombond in fragment - mit dem Atom atom id der Tabelle atom in fragment und der erste Bindungspartner - atom id a aus der Tabelle atombond in fragment - mit dem Atom atom id der Tabelle atom in fragment gleich gesetzt. Diese werden dann jeweils zusammen mit ihren Elementen in den Zeilen 3 bis 6 als atom id a und atom element a sowie atom id b und atom element b repräsentiert. Damit ist eine gerichtete Atombindung der Form A → B in der Tabelle Atombond in Fragment über die Sicht atom pairs in sowohl als A → B als auch als B → A repräsentiert. Von den gesamten Atomattributen werden hier zwar nur atom id und atom element aus der Tabelle atom in fragment selektiert, jedoch sind die übrigen Atomttribute genauso erreichbar. In der Sicht atom pairs in ist ein weiteres Join zwischen den Tabellen atombond in fragment und fragment in fragment list (18. sowie 22. Zeile) über die in beiden Tabellen gleichnamigen Spalten fragment name vorgesehen. Damit kann man für die Atome der Atombindungen feststellen, in welcher R-Gruppe diese enthalten sind (Zeile 8.). Diese Information wird später bei der Realisierung der Suchalgorithmen benötigt, was weiter unten näher erläutert wird. Die Informationen über die Atombindungen zwischen den Fragmenten kann man ähnlich wie bei der atom pairs in-Sicht über die Sicht atom pairs between erhalten. 1: CREATE OR REPLACE VIEW atom_pairs_between AS 2: SELECT 3: a1.atom_id AS atom_id_a, 4: a1.atom_element AS atom_element_a, 5: a2.atom_id AS atom_id_b, 6: a2.atom_element AS atom_element_b, 7: abf.predec_fragment_name AS fragment_name_a, 8: abf.succec_fragment_name AS fragment_name_b, 9: fif1.fragment_list_name AS fragment_list_name_a, 10: fif2.fragment_list_name AS fragment_list_name_b, 11: abf.type AS bond_type 12:FROM 13: atom_in_fragment a1, 14: atom_in_fragment a2, 15: atombond_between_fragments abf, 16: fragment_in_fragment_list fif1, 17: fragment_in_fragment_list fif2 18:WHERE ( 19: abf.atom_id_a = a1.atom_id AND 20: abf.atom_id_b = a2.atom_id AND KAPITEL 7. EVALUIERUNG 62 Abbildung 7.2: Die Kombination der beiden Sichten atom pairs in und atom pairs between in der atom pairs-Sicht. 21: abf.predec_fragment_name 22: abf.succec_fragment_name 23: OR( 24: abf.atom_id_b 25: abf.atom_id_a 26: abf.succec_fragment_name 27: abf.predec_fragment_name = fif1.fragment_name AND = fif2.fragment_name) = = = = a1.atom_id AND a2.atom_id AND fif1.fragment_name DAND fif2.fragment_name); Die Vorgehensweise ist genau dieselbe wie bei der Sicht atom pairs in. Aus dem Joinen der zwei Tabellen atom in fragment und atombond between fragments über die Spalten atom id der Tabelle atom in fragment und atom id a sowie atom id b der Tabelle atombond between fragments (19. und 20. sowie 24. und 25. Zeilen) kann man wiederum erreichen, daß eine Atombindung der Form A → B in der Tabelle Atombond between fragments über die Sicht atom pairs between sowohl als A → B als auch als B → A dargestellt wird. Die Fragmente der Atome werden in den 7. und 8. Zeilen repräsentiert. Es ist sogar möglich, die beiden Sichten über den UNION-Operator in Form einer einzigen atom pairs-Sicht miteinander zu kombinieren. Damit erhält man einen einzigen Suchraum, in dem alle Bindungspaare enthalten sind, egal KAPITEL 7. EVALUIERUNG 63 ob sie sich in oder zwischen den Fragmenten befinden. Dies hat den großen Vorteil, daß man sich bei der Suche nicht in jedem Suchschritt darum kümmern muß, ob die Suche innerhalb des aktuellen Fragmentes oder in einer der benachbarten R-Gruppen fortgesetzt werden soll. 1: CREATE OR REPLACE VIEW atom_pairs AS 2: SELECT 3: atom_id_a, 4: atom_element_a, 5: atom_id_b, 6: atom_element_b, 7: fragment_name AS fragment_name_b, 8: fragment_list_name AS fragment_list_name_b, 9: bond_type 10:FROM atom_pairs_in 11:UNION 12:SELECT 13: atom_id_a, 14: atom_element_a, 15: atom_id_b, 16: atom_element_b, 17: fragment_name_b, 18: fragment_list_name_b, 19: bond_type 20:FROM atom_pairs_between; In der atom pairs-Sicht werden aus den beiden Sichten nur diejenigen Attribute ausgewählt, die für die weiteren Anwendungen relevant sind. Nach diesen ersten Vorbereitungen kann jetzt die Suche mit der folgenden PL/SQL-Prozedur beginnen: 1: CREATE OR REPLACE PROCEDURE search IS 2: MIN_BOND_NR INTEGER; 3: MAX_BOND_NR INTEGER; 4: BEGIN 5: MIN_BOND_NR := 1; 6: SELECT MAX (bond_nr) INTO MAX_BOND_NR FROM subgraph; 7: INSERT INTO results SELECT * FROM first_match; 8: INSERT INTO seen_fragment_lists SELECT * FROM seen_first_frag_lists; 9: FOR l_bond_step in MIN_BOND_NR..MAX_BOND_NR LOOP 10: INSERT INTO results 11: SELECT * 12: FROM next_match 13: WHERE step = l_bond_step; 14: INSERT INTO seen_fragment_lists 15: SELECT * 16: FROM seen_next_frag_lists 17: WHERE step = l_bond_step; KAPITEL 7. EVALUIERUNG 64 Abbildung 7.3: Der Ablauf des ersten Suchschrittes. 18: END LOOP; 19:END; Nach der Prozedur-Definition in der 1. Zeile werden in den Zeilen 2 und 3 zwei Parameter - MIN BOND NR und MAX BOND NR - definiert, die für die Suchschritte als Unter- bzw. Obergrenze gelten. Diese Grenzwerte entsprechen den Werten der ersten und der letzten Zeile der bond nr -Spalte der Tabelle subgraph. Diese Werte werden dann in den Zeilen 5 und 6 den o.g. Parametern zugewiesen. Die Suche beginnt in der 7. Zeile mit dem Aufrufen der Sicht first match, die wie folgt definiert wird (Abbildung 7.3): 1: CREATE OR REPLACE VIEW first_match AS 2: SELECT 3: 0 AS step, 4: api.atom_element_a AS atom_element, 5: api.atom_id_a AS atom_id, 6: ’NONE’ AS predec_atom_id, 7: api.fragment_name AS fragment_name, 8: api.fragment_list_name AS fragment_list_name, 9: api.atom_id_a AS list_id KAPITEL 7. EVALUIERUNG 10:FROM 11: subgraph 12: atom_pairs_in 13:WHERE 14: sg.bond_nr 15: api.atom_element_a 65 sg, api = 1 AND = sg.element_a; Hier wird aus der Tabelle subgraph das element a der ersten Zeile gelesen (Zeile 14). Ausgehend von diesem Element wird über die Sicht atom pairs in innerhalb der Fragmente der Bibliothek nach denjenigen Atomen gesucht, die vom selben Element sind wie das element a(Zeile 15). Hat man solche Atome bzw. Teillösungen gefunden, werden für jede Teillösung die Informationen im SELECT-Teil der first match-Sicht zur Verfügung gestellt. Für jede Teillösung wird dann eine Liste erstellt, die mit dem Identifikator list id eindeutig markiert wird. Nun werden die übrigen Schritte der Prozedur searchdargestellt. Nachdem die Ergebnisse der first match-Sicht in der Tabelle results geschrieben (materialisiert) sind, fährt das Programm mit der 8. Zeile fort, wo die Ergebnisse der Sicht seen first frag lists in die Tabelle seen fragment lists geschrieben werden. 1: CREATE OR REPLACE VIEW seen_first_frag_lists AS 2: SELECT 3: res.step, 4: res.list_id, 5: aif.fragment_name, 6: fif.fragment_list_name 7: FROM 8: results res, 9: atom_in_fragment aif, 10: fragment_in_fragment_list fif 11:WHERE 12: res.atom_id = aif.atom_id AND 13: aif.fragment_name = fif.fragment_name; Die Sicht seen first frag lists findet für jedes Atom in der results-Tabelle das Fragment und die R-Gruppe, in der das Atom sich befindet (Abbildung: 7.3). Auf den Grund der Markierung des Fragmentes und der R-Gruppe für jedes Atom wird weiter unten näher eingegangen. Die Suche wird in den Zeilen 9 bis 18 der Prozedur search weiter fortgesetzt. Dort wird die subgraph-Tabelle von der ersten bis zur letzten Zeile in einer Schleife durchlaufen. In jedem Durchlauf wird in der 12. Zeile die Sicht next match aufgerufen (Abbildung 7.4): 1: CREATE OR REPLACE VIEW next_match AS 2: SELECT 3: sg.bond_nr AS step, 4: ap.atom_element_b AS atom_element, 5: ap.atom_id_b AS atom_id, KAPITEL 7. EVALUIERUNG 66 Abbildung 7.4: Der Ablauf der nächsten Suchschritte. 6: ap.atom_id_a 7: ap.fragment_name_b 8: ap.fragment_list_name_b 9: res.list_id 10: FROM 11: subgraph sg, 12: atom_pairs ap, 13: results res 14: WHERE 15: sg.bond_nr = 16: ap.atom_element_b = 17: ap.atom_id_a = 18: ap.bond_type = 19: NOT EXISTS( 20: SELECT * 21: FROM results 22: WHERE list_id = 23: ap.atom_id_b= 24: NOT EXISTS( 25: SELECT * AS AS AS AS predec_atom_id, fragment_name, fragment_list_name, list_id res.step+1 sg.element_b res.atom_id sg.bond_type AND AND AND AND res.list_id atom_id) AND AND KAPITEL 7. EVALUIERUNG 67 Abbildung 7.5: Bei der Suche der Kette 1-...-6 im Suchraum soll die rot gekennzeichnete Verbindung 5-6 von Fragment List 2 zu Fragmen List 1 vermieden werden. 26: 27: 29: 30: FROM WHERE seen_fragment_lists sfl list_id = sfl.solution_id AND ap.fragment_list_name_b = sfl.fragment_list_name AND ap.fragment_name_b != sfl.fragment_name); Hier wird zunächst aus der subgraph-Tabelle (11. Zeile) das element b der aktuellen Zeile gelesen. Welche Zeile der Tabelle subgraph als aktuelle Zeile betrachtet werden soll, wird in Zeile 13 der search-Prozedur und danach in Zeile 15 der next match-Sicht festgelegt. Dann werden in der Sicht next match (12. Zeile) über die atom pairs-Sicht diejenigen Atome im Suchraum gesucht, die drei Kriterien erfüllen: erstens müssen sie vom selben Element sein wie das aktuell gesuchte Atom aus der subgraph-Tabelle (16. Zeile), Zweitens muss im Suchraum eine Atombindung zwischen dem gefundenen Atom und einem Atom der letzten Stufe in der Liste der jeweiligen Teilösung bestehen (17. Zeile), Drittens dürfen die gefundenen Atome nicht bereits in der Liste der jeweiligen Teillösung enthalten sein. Das zweite Kriterium stellt sicher, daß nicht jedes Atom des gesuchten Elements im Suchraum erfasst wird, sondern nur jene, deren direktes Nachbaratom bereits in der Liste der jeweiligen Teillösung vorhanden ist. Die letzte Bedingung gewährleistet, daß die Suche immer in einer Richtung voran geht und damit die bereits betrachteten Atome jeder Liste nicht noch einmal abgesucht werden. Diese Bedingung wird in der next match-Sicht über die erste NOT-EXISTS-Einschränkung erfüllt (18. bis 22. Zeile). Eine weitere Einschränkung kann sich noch aus dem spezifischen Aufbaumechanismus der kombinatorischen Bibliotheken ergeben. Bereits in (2.3.1) wurde deutlich, daß bei der Konstruktion eines Bibliotheksmoleküls in einer Bibliothek aus jeder R-Gruppe nicht mehr als ein Fragment benutzt werden darf. Es kann aber durchaus vorkommen, daß man bei der Suche nach dem nächsten Atom für eine Teillösung die bereits durchsuchte R-Gruppe im Suchraum in Richtung einer neuen R-Gruppe verlässt und dann im nächsten Suchschritt über das dann aktuelle Atom im Suchraum wieder zu einem anderen Fragment der vorherigen R-Gruppe zurückkehrt (Abbildung 7.5). Dieses kann vermieden werden, indem in jeder Teillösung für jedes Atom das Fragment und die R-Gruppe bzw. Fragment List des jeweiligen Atoms gespeichert wird. Dafür schreibt man sie in der 8. und in den Zeilen 14 bis 18 der search-Prozedur über die Sichten seen first frag lists und seen next frag lists in die Tabelle seen fragment listes. KAPITEL 7. EVALUIERUNG 68 1: CREATE OR REPLACE VIEW seen_next_frag_lists AS 2: SELECT 3: res.step, 4: res.list_id, 5: aif.fragment_name, 6: fif.fragment_list_name 7: FROM 8: results res, 9: atom_in_fragment aif, 10: fragment_in_fragment_list fif 11: WHERE 12: res.atom_id = aif.atom_id AND 13: aif.fragment_name = fif.fragment_name; Stehen diese Informationen nun zur Verfügung, kann man in der Sicht next match über die zweite NOT EXISTS-Bedingung testen, ob das neue Atom entweder immer noch demselben Fragment dieser R-Gruppe oder einer neuen, noch nicht besuchten R-Gruppe angehört. Wenn ein neu gefundenes Atom diese Bedingungen erfüllt, wird es in der Liste der jeweiligen Teillösung der results-Tabelle gespeichert. Mit dem Erreichen des Endes der subgraph-Tabelle ist auch der Suchprozess beendet. Die results-Tabelle enthält jetzt die Listen aller Teillösungen, die im Laufe des Suchprozesses gefunden wurden. Von diesen Teillösungen sind aber nur diejenigen interessant, die die komplette Substruktur enthalten. Das trifft auf solche zu, in deren Listen in der results-Tabelle es mindestens einen Eintrag auf der letzten Stufe der Tabelle gibt (Abbildung 7.6). Um die vollständigen Teillösungen bzw. die Fragmente, in denen sie enthalten sind aus der results-Tabelle herauszuholen, muss man die Liste jeder dieser Teillösungen voim Suchraum n der letzten Stufe bis zu ihrem Anfang zurückverfolgen. Der hier vorgestellte Suchalgorithmus ist ein Breitensuche-Algorithmus, der in jedem Suchschritt eine Menge von Atomen als Ergebnis zurückliefert. Da hier keine Möglichkeit besteht, für jedes Atom einer Teillösung das VorgängerAtom zu bestimmen, muss man selber für jedes Atom solche Referenzen setzen, über die dann die Listen der Teillösungen von den Blättern zur Wurzel durchlaufen werden können. Eine mögliche Lösung hierfür ist, daß man im Suchprozess ebenfalls das Vorgänger-Atom für jedes gefundene Atom in der results-Tabelle speichert. So kann man - ausgehend von jedem Atom (außer den Anfangsknoten) - das jeweilige Vorgänger-Atom erreichen. 7.2 Vergleich von Suchergebnissen mit und ohne Datenbank Das Ziel dieses Testes ist es, bestimmte Substrukturen innerhalb derselben kombinatorischen Bibliothek einerseits in FlexX und andererseits - mit Hilfe der oben beschriebenen Implementierungen - innerhalb der Datenbank zu suchen und somit die Vor- und Nachteile der beiden Ansätze miteinander zu vergleichen. Als Datensatz zum Testen der oben beschriebenen Algorithmen wurde die CSLN-Bibliothek Methotrexate Analoga ausgewählt. Methotrexat ist ein Medikament zur Behandlung von Tumoren und Rheumatischen Erkrankungen [H.J96]. Der Grund zur Auswahl dieser Bibliothek KAPITEL 7. EVALUIERUNG No. subgraph 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 O=C-O C-N=N O=S=O O=S-N Cl-C-C-C=O C=C=O C-O O-C-O O-C-C-O O-C-C-C-O O=P-C O=P-O-P=O N-C-C-O-S=O O=S-N-C=O O=C-N-C O=C-O-C C-C≡N C-S-C≡N C=C-C=C-C=C O=C-C-S=O 69 vorwärts [m:s]/gefunden 0:31/OK >5/0:14/OK 0:14/OK 0:21/OK 0:21/(0,1) 2:24/OK 0:29/OK 0:51/OK 1:32/OK 0:22/OK 0:22/(0,1,2) >5/0:27/OK 0:48/(0,1,2) 0:42/OK >5/1:09/(0,1,2) >5/0:41/(0,1,2,3) rückwärts [m:s] [m:s]/gefunden 0:38/OK 0:14/OK 0:14/OK 0:14/OK 0:55/OK 0:55/(0,1) 0:21/OK 0:29/OK 0:51/OK 1:32/OK 0:22/OK 0:22/(0,1,2) 0:27/(0,1,2,3,4) 0:39/(0,1,2) >5/>5/1:14/OK 0:19/(0,1) >5/0:24/(0,1,2,3) Tabelle 7.1: Die Tabelle enthält in den Spalten vorwärts und rückwärts Informationen über die Suchzeit und darüber, ob die Kette gefunden wurde. Gefundene Ketten werden mit ”OK” bezeichnet, wurden sie nicht gefunden repräsentiert ein Tupel die gefundenen Atome. Die Suchezeiten länger als Min. werden mit >5 gezeigt. liegt in ihrer typischen Größe im Bereich Wirkstoffdesign. Diese Bibliothek besteht aus drei R-Gruppen R0, R1 und R2 mit jeweils 1, 775 und 1748 Fragmenten, aus deren Kombinationen bis zu 1354700-Bibliotheksmoleküle kombinierbar sind. Als gesuchte Substrukturen wurden 20 verschiedenen Ketten von unterschiedlicher Länge ausgewählt (Tabelle 7.1). Die Tests wurden auf einer ”Intel(R) Pentium(R) 4 CPU 2.53 GHz” Maschine durchgeführt. Bereits in (2.y) wurde erwähnt, daß FlexX zur Substruktursuche innerhalb kombinatorischer Bibliotheken die Bibliotheksmoleküle eines nach dem anderen zusammensetzt und dann unter diesen Molekülen - unabhängig voneinander - nach der gewünschten Struktur sucht. Bei der Suche der hier verwendeten Substrukturen hat man festgestellt, daß die Suche für fast alle Substrukturen konstant um 1 Stunde und 25 Minuten dauert. Die Suchzeit für dieselben Substrukturen innerhalb der Datenbank dauert dagegen lediglich 14 Sekunden bis 2:25 Minuten. Somit ist die Suche auf der Datenbank bei der Betrachtung der Laufzeit bis zu gut 300-mal schneller. Die Ursache für diesen Unterschied kann man folgendermaßen darstellen: FlexX braucht den größten Teil der Zeit dafür, alle Bibliotheksmoleküle der R-Gruppenfragmente zusammenzusetzen. Die Suche innerhalb der Bibliotheksmoleküle verläuft für alle Substrukturen gleich lang und mit akzeptabler Geschwindigkeit. In der Datenbank dagegen findet die Suche nicht in allen Bibliotheksmolekülen statt, sondern in einer kompakten Menge von nur 2524 Bibliotheksfragmenten statt, daher ist der Suchraum wesentlich kleiner als in FlexX. KAPITEL 7. EVALUIERUNG 70 Element # atom in fragment # atom pairs in # atom pairs C O N S Cl P 19669 4517 4050 254 195 37 68806 6672 9002 657 195 146 71329 6672 11521 657 195 146 Tabelle 7.2: Häufigkeitsverteilung von Substruktur-Atomen innerhalb atom in fragment und Sichten atom pairs in sowie atom pairs. der Tabelle Wie weiter oben erwähnt, ist die Suchzeit innerhalb der Datenbank von einer Substruktur zu anderer unterschiedlich. Es wurde festgestellt, daß die Suche bei denjenigen Substrukturen schneller ist, deren erstes Atom-Elemente weniger häufig in der Bibliothek vorkommen als andere Atom-Elemente (Tabelle 7.2). Zum Beispiel dauert die Suche bei der 7. Substruktur der Tabelle (7.1) - angefangen vom C-Atom - 2:24 Minuten. Dieselbe Substruktur kann man nur dann innerhalb von 23 Sekunden finden, hätte man die Suche vom anderen Ende, dem O-Atom der Kette begonnen. Bei einigen Substrukturen ist dieser Unterscheid sogar noch wesentlich größer. Ein solches Beispiel ist die 2. Substruktur der Tabelle (7.2). Für die Suche nach dieser Kette ausgehend von C - bräuchte man länger als 5 Minuten. Dieselbe Kette kann man um ein Faktor von mind. 20 schneller finden, wenn man die Suche aus dem anderen Ende der Kette beginnt. Ein zweiter Faktor, die bei der Suchzeit eine entscheidende Rolle spielt ist die Häufigkeit einer Atombindung im Suchraum (Tabelle 7.3). Als Beispiel werden wieder die 2. und 7. Substruktur der Tabelle (7.1) betrachtet. Für die Suche nach N ausgehend von C in der Atombindung C-N der 2. Substruktur wird mehr als 5-Minuten gebraucht (Die Suchzeit für die N=N Atombindung ist im Vergleich zu C-N sehr gering). Bei der 7. Substruktur wird dagegen die Atombindung C-O innerhalb von 2:24 Min. gefunden. Bei dem Vergleich der Häufigkeit beider Atombindungen in der Tabelle (7.3) stellt man fest, daß die Atombindung C-N im Suchraum doppelt vorkommt wie der Atombindung C-O (Spalte atom pairs). Der Grund Für diese Laufzeitunterschiede wird über die Art und Weise der Suche innerhalb der Datenbank ersichtlich. Im letzten Abschnitt dieses Kapitels wurde deutlich, daß die Suche nach einer Substruktur mit der Suche nach Atomen innerhalb des Suchraumes beginnt, deren Element dem ersten Element der Substruktur gleichen. Wurden solche Atome gefunden, wird für jedes Ergebnis eine Liste reserviert. In den nächsten Suchschritten wird dann für jede Liste ausgehend vom letzten Element der Liste - die Suche fortgesetzt. Dabei wird für dieses Atom im Suchraum nach allen nach allen seiner Nachbaratome gesucht. Es ist naheliegend festzustellen, je kleiner die Menge der gefundenen Atome im ersten Suchschritt und je kleiner die Menge der Nachbaratome, desto es weniger Listen zur weiteren Suche gibt es. Ein weiterer, großer Vorteil des im Rahmen dieser Arbeit entwickelten Suchalgorithmus liegt in der Art und Weise, wie die gefundenen Substrukturen repräsentiert werden. In FlexX hat man lediglich die Möglichkeit, diejenigen Bibliotheksmoleküle zurückzugeben, in denen die Substruktur gefunden wurde. Informationen darüber, in welchen Fragmenten des jeweiligen Bibliotheksmolekül die Substruktur enthalten ist, sind nicht zugänglich. Ein Beispiel hier wäre der Fall, in dem KAPITEL 7. EVALUIERUNG Atombindung O-C C-O O=C C=O C-N N-C C≡N N≡C C-S S-C C-C C=C N=N O-S S-O O=S S=O S-N N-S Cl-C C-Cl O-P P-O O=P P=O P-C C-P # atombond in fragment 1004 2049 0 1974 1263 3532 86 0 204 199 8850 325 8 0 8 0 155 21 39 0 195 6 61 0 36 11 31 71 # atombond between fragments 0 0 0 0 2519 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 # atom pairs 3053 3053 1974 1974 7314 7314 86 86 403 403 17770 650 16 8 0 155 155 60 60 195 195 67 67 36 36 42 42 Tabelle 7.3: Häufigkeitsverteilung von Substruktur-Atombindungen innerhalb der Tabellen atombond in fragment und atombond between fragments sowie der Sicht atom pairs. eine Substruktur nur innerhalb des Core-Fragmentes gefunden wird. Da FlexX nicht erkennen kann, in welchem Fragment des Bibliotheksmoleküls die Substruktur enthalten ist, werden alle Bibliotheksmoleküle als Ergebnis zurückgegeben, die das Core-Fragment enthalten, also die gesamten Bibliotheksmoleküle. Dagegen werden die Resultate des Suchalgorithmus in der Datenbank in der results-Tabelle in getrennten Listen gespeichert. Diese enthalten die komplette Information über den Pfad der jeweiligen Teillösung innerhalb der gesamten Bibliothek. Damit kann man - ohne die Bibliotheksmoleküle komplett zu betrachten - sehr leicht erkennen, in welchen Fragmenten einzelner Moleküle die Substrukturen enthalten sind. Somit würden im obigen Beispiel nur die Listen als Ergebnis zurückgeliefert, die den Pfad der gefundenen Substruktur innerhalb des Core-Fragmentes beschreiben. KAPITEL 7. EVALUIERUNG 72 Abbildung 7.6: Exemplarische Darstellung der Suche nach der Kette A-B-C. Das Ergebnis im Dritten Schritt ist grau unterlegt. Kapitel 8 Zusammenfassung und Aussichten Im Rahmen der vorliegenden Arbeit wurde ein Datenbank-Schema für kombinatorische Bibliotheken in der Biochemie entwickelt, das eine kompakte Repräsentation dieser Bibliotheken mit minimaler Redundanz ermöglicht. Eine Anwendung für die entwickelte Datenbank wurde für die Suche nach spezifischen chemischen Substrukturen in Form von einfachen Ketten innerhalb einer bestimmten kombinatorischen Bibliothek vorgestellt. Diese wurden mit Hilfe eines (PL/)SQL-Programms realisiert. Die Effizienz der entwickelten Suchalgorithmen wurde mit den Suchalgorithmen für Substrukturen im Tool FlexX verglichen. Es gelang, die Ketten innerhalb einer kombinatorischen Bibliothek unter den Fragmenten und über die Fragmentgrenzen hinweg zu suchen. Basis für die Evaluierung waren eine kombinatorische Bibliothek mit einer im Bereich Wirkstoffdesign typischen Größe und 20 ausgewählten Substrukturen, die von Chemikern ausgewählt wurden. Die erzielten Ergebnisse bei der Suche nach den Substrukturen belegen, daß diese Suche in den meisten Fällen in der Datenbank sehr viel schneller als in FlexX abläuft. Es wurde jedoch ebenfalls deutlich, daß die Suchzeit - abhängig von der Substruktur - unterschiedlich ist. Dabei wurde festgestellt, daß diese Laufzeitunterschiede von der Häufigkeit der gesuchten Substruktur in der Bibliothek abhängt. In einigen Fällen konnte beobachtet werden, daß die Suche nach derselben Kette sehr viel schneller werden kann, wenn man von dem Ende der Kette zu suchen beginnt, dessen Atom weniger häufig in der Bibliothek vorkommt. Derartige Atomstatistiken können daher für eine effizientere Suche genutzt werden. Eine weitere Effizienzsteigerung kann mit Hilfe von Indexierungen erreicht werden. Dabei können häufig benutzten Datensätze, wie zum Beispiel Atom-Daten mit Zusatzinformationen gespeichert werden, mit deren Hilfe die Suche erheblich schneller werden kann. Die Suche nach Ringsysteme kann mit einer leichten Modifikation auf die Suche nach einfachen Ketten zurückgeführt werden. Dazu muß in der Subgraph-Tabelle das letzte Atom der Kette ebenfalls als Anfangsatom abgelegt werden. Somit ist gewährleisten, daß die Anfangs- und Endknoten der Substruktur gleich sind. Die Suche nach den Ringsystemen kann ebenfalls durch eine Art Indexierung beschleunigt werden. Dazu kann man in einem preprocessing alle Ringsysteme einer kombinatorischen Bibliothek absuchen und sie in Form einer Tabelle physisch ablegen. Dann kann für die weitere Suche - anstatt jedes Mal die Ringe innerhalb der Bibliothek 73 KAPITEL 8. ZUSAMMENFASSUNG UND AUSSICHTEN 74 zu durchsuchen - auf die soeben definierte Tabelle zugegriffen werden. Eine weitere Möglichkeit bietet das Modul FlexXC über seine Datenstruktur ringsystem, in der die Informationen über die Ringsysteme der kombinatorischen Bibliothek enthalten sind. Diese kann man nutzen, um die o.g. Tabelle mit den jeweiligen Informationen zu füllen. Für die Suche nach allgemeinen Substrukturen, die aus der Kombination von einfachen Ketten und Ringsystemen entstehen, müssen sie zuerst in geeignter Weise in der Datenbank repräsentiert werden. Eine Lösungsmöglichkeit bietet sich durch die Nested Tables in PL/SQL ([OrP02]). Damit ist es möglich, die Zeilen der Nested Tables als eindimensionale Arrays zu definieren, deren Länge dynamisch wachsen kann. Somit läßt sich für jedes Atom der Substruktur eine Adjazenzliste in einer Zeile dieser Tabellen ablegen. Die Suchalgorithmen können dann mit Hilfe von PL/SQL Konstrukten realisiert werden. Literaturverzeichnis [Alb90] B. Alberts. Molekularbiologie der Zelle. VCH, Basel;Cambridge;New York, 2. Auflage, 1990. [A.S02] S.Sudarshan A.Silberschatz, H.Korth. Database System Concepts. Mc Graw Hill, New York, 7th ed., 2002. [BK97] Ulrich Epperlein Bernhard Koppenhoefer. Chemie und Informatik. Shaker Verlag, Aachen, 1997. [Blu01] Norbert Blum. Theoretische Informatik: eine anwendungsprientierte Einführung. Oldenburg, München; Wien: Oldenburg, 2. überarb. Auflage, 2001. [Cla01] Holger Claußen. Effizientes Protein-Ligand-Docking mit flexiblen Proteinstrukturen, disseration, rheinische friedrich-wilhelms-universität bonn, 2001. [Cla04] Holger Claußen. persönliche mitteilung, 2004. [Gas03] Johann Gasteiger. Handbook of Chemoinformatics. WILEY-VCH Verlag GmbH, Weinheim, 2003. [G.K96] M. Rarey B. Kramer T. Lengauer G.Klebe. A fast flexible docking method using an incremental construction algorithm, j. mol. biol., 261(3):470-489, 1996. [H.J96] H.Kubinyi H.J.Böhm, G.Klebe. Wirkstoffdesign. Spektrum Akademischer Verlag GmbH, Heidelberg.Berlin.Oxford, 1996. [Kyt01] Thomas Kyte. Expert One-on-One Oracle. Wrox Press, Birmingham, UK, 2001. [MA02] Alex Martelli and David Ascher. Python Cookbook. O’Reilly, Sebastopol, USA, 2002. [Man] Rainer Manthey. Vorlesung Informatiossysteme, ws 03/04 , institut für informatik iii, rheinische friedrich-wilhelms-universität bonn. [Mar03] Alex Martelli. Python in a Nutshell. O’Reilly, Sebastopol, USA, 2003. [McC96] David McClanahan. Oracle Developer’s Guide. McGraw-Hill, Berkley, USA, 1996. [Mel03a] Jim Melton. Advanced SQL:1999. Morgan Kaufmann Publishers, San Francisco, CA 94104-3205, 2003. [Mel03b] Jim Melton. SQL:1999. Morgan Kaufmann Publishers, San Francisco, CA 94104-3205, 2003. 75 LITERATURVERZEICHNIS [MR00] 76 Thomas Lengauer Mathias Rarey. A recursive algorithm for efficient combinatorial library docking, perspectives in drug discovery and design 20, 63?81, 2000. [OrA02] Oracle9i application developer’s guide-fundamentals, release 2 (9.2), 2002. [OrC02] Oracle9i data cartridge developer’s guide, release 2 (9.2), 2002. [OrP02] Pl/sql user’s guide and reference, release 2 (9.2), 2002. [OrS01a] Oracle9i sql reference, release 1 (9.0.1), 2001. [OrS01b] Sql*plus user’s guide and reference, release 9.0.1, 2001. [PK94] Jan Koolman Peter Karlson, Detlef Doenecke. Kurzes Lehrbuch der Biochemie für Mediziner und Naturwissenschaftler. Georg Thieme Veralg, Stuttgart.New York, 14. Auflage, 1994. [Rar01] Mathias Rarey. Algorithmen für den computergestützten Wirkstoffentwurf, habilitationsschrift , gmd-forschungszentrum informationstechnik gmbh, 2001. [SD02] Thomay Kyte Sean Dillon, Christopher Beck. Beginning Oracle Programming. Wrox Press, Birmingham, UK, 2002. [Sed91] Robert Sedgewick. Algorithmen. Addison-Wesley Verlag, Bonn;München, 1. Nachdruck, 1991. [THC99] Ronal L. Rivest Thomas H. Cormen, Charles E. Leiserson. Introduntion to Algorithms. The MIT Press, Cambridge, Massachusetts, 1999. [Tri99] SLN Manual, tripos inc. http://www.tripos.com, 1999. [uA01] A. Kemper und A.Eickler. Datenbanksysteme: eine Einführung. Oldenburg, München; Wien: Oldenburg, 4. überarb. und erw. Auflage, 2001. [Ull76] J. R. Ullmann. An Algorithm for Sungraph Isomorphismus, journal of the association for computer machinery, vol.23:31-43, 1976. [Vos00] Gottfried Vossen. Datenmodelle, Datenbanksprachen und Datenbankmanagementsysteme. Oldenburg, München; Wien: Oldenburg, 4. korrigierte und erg. Auflage, 2000. [Zop] http://www.zope.org/members/matt/dco2. LITERATURVERZEICHNIS 77 Hiermit versichere ich, daß ich meine Diplomarbeit selbständig durchgeführt und keine anderen als die angegebenen Quellen und Hilfsmittel benutzt sowie Zitate kenntlich gemacht habe. Bonn, den 20.09.2004