Eine Transkriptions-Datenbank

Ich habe mir in den letzten Tagen das »Vergnügen« gegönnt, die Transkriptionen aus Jorge Stolfis Interlinear-Archiv in ein etwas anderes Format zu bringen. Das Ergebnis ist eine weit gehend normalisierte SQL-Datenbank, die des Wortzählers Herz erfreuen kann. Einen SQL-Dump dieser Datenbank stelle ich hier zum Download zur Verfügung.

Download-Link: SQL-Dump der Transkriptionsdatenbank

Wer sich die Datenbank anschaut, wird bemerken, dass sie nicht in der dritten Normalform steht. Einige Denormalisierungen habe ich eingefügt, um gewisse Analysen mit größerer Leichtigkeit und Performance ausführen zu können – zum Beispiel enthält jede Zeile die an sich überflüssige Angabe, aus wie vielen Wörtern sie besteht, damit ich Zeilen gleicher Wortlänge untersuchen kann, ohne einen Subselect verwenden zu müssen.

Um eine Verwendung dieser Datenbank mit »kleinen« Systemen wie mSQL zu vereinfachen, wurde auf explizite referenzielle Integrität verzichtet. Da sich dieser Datenbestand nicht verändert (im besten Fall kommt einmal eine neue Transkription hinzu), sollte dies kein Problem darstellen. Erstellt habe ich die Datenbank in MySQL, der Dump ist kompatibel zu ANSI-SQL und sollte so in jedem RDBMS verwendbar sein. Wer ebenfalls eine MySQL verwendet, wird wohl eher einen speziellen Dump für MySQL bevorzugen, auch dieser steht hier zum Download zur Verfügung.

Download-Link: SQL-Dump der Transkriptionsdatenbank für MySQL

Die gesamte Datenbank ist in englischer Sprache kommentiert. Die einzelnen »Wörter« sind in allen gängigen Transkriptionssystemen abgelegt, damit eine Anwendung nach jedem beliebigen System arbeiten kann. Natürlich wurden die anderen Systeme von einem Programm erzeugt, und ich kann nicht ausschließen, dass mir dabei ein Fehler unterlaufen ist, da ich selbst vorwiegend in EVA »lese« und analysiere, wenn ich mich nicht direkt mit Bildern des Manuskriptes beschäftige.

Die Datenbank enthält nur fünf Tabellen, die hier kurz in deutscher Sprache erläutert werden.

Tabelle voy_page

Informationen zu einer Seite.

  • page_id INTEGER
    Primärschlüssel für die Seite
  • fnumber VARCHAR(8)
    Alternativer Schlüssel, die »F-Number« der Seite ohne führendes »f«
  • illustration_type CHAR(1)
    Angabe des Typs der Illustration, entweder »T«, »H«, »A«, »Z«, »B«, »C«, »P« oder »S«
    Dieses Feld ist für MySQL als ENUM definiert
  • quire CHAR(1)
    Das Bündel, in dem die Seite liegt
  • page_in_quire CHAR(1)
    Die Position, welche die Seite im Bündel einnimmt
  • currier_lang CHAR(1)
    Angabe der Currier-Sprache, entweder »A« oder »B«
    Dieses Feld ist für MySQL als ENUM definiert
  • currier_hand CHAR(1)
    Angabe der Handschrift nach Currier, entweder »1″, »2″, »3″, »4″, »5″, »X« oder »Y«
    Dieses Feld ist für MySQL als ENUM definiert
  • has_non_voynich CHAR(1)
    Angabe, ob die Seite Text enthält, der nicht im Schriftsystem des Manuskriptes verfasst wurde, entweder »Y« oder »N«
    Dieses Feld ist für MySQL als ENUM definiert
  • has_key_like CHAR(1)
    Angabe, ob schlüsselartige Texte auf der Seite stehen, entweder »Y« oder »N«
    Dieses Feld ist für MySQL als ENUM definiert
  • has_extraneous CHAR(1)
    Angabe, ob die Seite zusätzliche Schrift enthält, entweder »Y« oder »N«
    Dieses Feld ist für MySQL als ENUM definiert
  • description TEXT
    Aus den Kommentaren extrahierte Seitenbeschreibung

Tabelle voy_trans

Informationen zu einer Transkription.

  • trans_code CHAR(1)
    Transkriptionscode aus dem Interlinear-Archiv
  • second_code CHAR(1)
    Code für die zweite Lesart einer Transkription aus dem Interlinear-Archiv
  • sortkey CHAR(2)
    Ein Sortierungsschlüssel, um die verschiedenen Transkriptionen in Anwendungen in nicht-alphabetischer Reihenfolge präsentieren zu können. (Bei mir stehen Currier und Takeshi Takahashi an den ersten Stellen, und das hat einen guten Grund. Takahashi ist vollständig, und Currier war recht gründlich.)
  • name VARCHAR(64)
    Ein Anzeigename für die Transkription
  • description TEXT
    Weitere Angaben zur Transkription

Tabelle voy_line

Eine Transkription besteht aus transkribierten Zeilen aus Seiten, diese werden hier zugeordnet.

  • line_id INTEGER
    Primärschlüssel, wird aufsteigend vergeben und kann somit als Ordnungselement für die Reihenfolge der Zeilen dienen.
  • line_trans INTEGER
    (Halber) Fremdschlüssel. Verweist auf voy_trans, entweder Feld trans_code oder Feld second_code
  • line_page INTEGER
    Fremdschlüssel. Verweist auf voy_page, Feld page_id
  • locator VARCHAR(20)
    Roh übernommener Angabe zur Zeile, enthält schwach dokumentierte Angaben zur scheinbaren textuellen Einheit, in der diese Zeile auftritt. In dieser ersten Version habe ich das noch nicht in eine sinnvolle Struktur übertragen.
  • wordcount INTEGER
    Anzahl der Wörter in der transkribierten Zeile (wobei schwache Leerzeichen als Leerzeichen gezählt werden)

Tabelle voy_word

Die Wörter aus den Transkriptionen. Jedes eindeutig auftretende Wort ist in dieser Tabelle enthalten. Um die Verarbeitung zu vereinfachen, wurde jedes Wort in allen gängigen Transkriptionsalphabeten aufgenommen.

Darüber hinaus ist ein experimentelles Feature in diese Tabelle aufgenommen. Es existiert ein Feld fuzzy, das leicht verwechselbare oder ähnliche Glypen und Glyphenfolgen auf gleiche Zeichen abbildet, um eine bequeme Suche nach ähnlichen »Wörtern« zu ermöglichen. Dieses Verfahren habe ich mir innerhalb einer halben Stunde und nach eher flüchtigem Blick auf einige Bilder des Manuskriptes ausgedacht, es ist weit von einer brauchbaren Metrik für die Ähnlichkeit von Glyphen entfernt. Vielleicht findet es aber doch jemand anders von Nutzen, deshalb habe ich es in diese Veröffentlichung aufgenommen.

  • word_id INTEGER
    Generischer Primärschlüssel für das Wort
  • readable CHAR(1)
    Angabe, ob das Wort vollständig lesbar ist oder ein unlesbares Zeichen enthält, »Y« oder »N«
    Für die MySQL ist dieses Feld als ENUM definiert
  • eva VARCHAR (40)
    Transkription in EVA
  • frogguy VARCHAR(60)
    Transkription in Frogguy
  • currier VARCHAR(40)
    Transkription im Verfahren von Currier
  • fsg VARCHAR(40)
    Transkription im Verfahren der First Study Group
  • bennett VARCHAR(40)
    Transkription in Verfahren von Bennett
  • fuzzy VARCHAR(40)
    Experimentelle Bearbeitung, um »ähnliche Wörter« auf gleiche Zeichenfolgen abzubilden
  • count INTEGER
    Insgesamte Häufigkeit dieses »Wortes« in allen Transkriptionen, dies kann nützlich sein, wenn seltene »Wörter« in einer Analyse besonders hervorgehoben werden sollen.

Tabelle voy_lineword

Die Wörter werden in einer Reihenfolge zu einer Zeile zugeordnet.

  • lword_id INTEGER
    Generischer Primärschlüssel
  • lword_line INTEGER
    Fremdschlüssel, verweist auf voy_line, Feld line_id
  • lword_word INTEGER
    Fremdschlüssel, verweist auf voy_word, Feld word_id
  • position INTEGER
    Position des Wortes in der Zeile
  • spacing VARCHAR(6)
    Angabe, wie das Leerzeichen zum vorhergehenden Wort zu bewerten ist. Entweder »first«, wenn es das erste Wort in einer Einheit ist, oder »normal«, wenn es sich um eine sichere Leerstelle handelt, oder »weak«, wenn es eine schwache Leerstelle ist oder »big«, wenn das Wort durch eine Illustration oder einen anderen großen Zwischenraum vom vorhergehenden Wort getrennt ist.
    Dieses Feld ist in MySQL als ENUM definiert

Zur Motivation meines Hacks

Die Verwendung einer relationalen Datenbank ermöglicht es, Analysen in SQL durchzuführen und sogar darüber hinaus, die Ergebnisse mit Hilfe eines Reporting-Tools darzustellen – letzteres ist zwar nicht meine Welt, aber es ist eine Möglichkeit, schnell eine übersichtliche Darstellung eines Ergebnisses zu erzeugen. Vielen heutigen Programmierern geht SQL wesentlich leichter von der Hand als awk und sed aus dem Weg der tausend Tools (damit ist Unix gemeint). Ich hoffe, dass ich mit dieser Veröffentlichung auch solche Menschen zu eigenen Untersuchungen und Experimenten anrege, die bislang von den Formaten der Transkriptionen abgeschreckt wurden.

Natürlich ist es nun auch recht bequem, sich sinnvolle Views zu erzeugen, mit denen die Analyse dieser vielleicht nun etwas überstrukturierten Daten vereinfacht werden kann. Ich habe bewusst keine Views aufgenommen, da doch sehr vom Kontext einer Untersuchung abhängt, was man für sinnvoll erachtet.

Ein Beispiel für die Anwendung

Bei einer flüchtigen Unterschung stellt sich heraus, dass die durchschnittliche Länge des zweiten Wortes einer Zeile auffällig ist. Diese durchschnittliche Länge kann man zum Beispiel mit folgendem Statement aus der Transkription von Takeshi Takahashi ermitteln:

SELECT AVG(LENGTH(eva))
FROM voy_lineword
JOIN voy_word ON word_id = lword_word
JOIN voy_line ON line_id = lword_line
WHERE line_trans = 'H'
AND position =2

Mein hier verwendeter Pentium III mit 450 MHz brauchte zur Verarbeitung dieser Abfrage 1,4 Sekunden und lieferte eine durchschnittliche Wortlänge von 5,0011. (Es ist ein wirklich lahmer Computer, den ich hier benutze. Auf einer zeitgemäßen Maschine sollte so ein Ergebnis wesentlich schneller erscheinen.)

Diese Abfrage lässt sich nun sehr einfach so umformulieren, dass eine andere Transkription verwendet wird, ohne dass hierzu ein besonderes Programm in einer Unix-Pipe verwendet werden muss.

Und das ist keineswegs alles, denn es ist auch mit einer kleinen Änderung möglich, alle durchschnittlichen Wortlängen für alle Position zu ermitteln, ich nehme hier aber nur die ersten 19 Positionen auf, um diese Beschreibung nicht mit unnötigen, rohen Daten zu fluten:

SELECT position, AVG(LENGTH(eva))
FROM voy_lineword
JOIN voy_word ON word_id = lword_word
JOIN voy_line ON line_id = lword_line
WHERE line_trans = 'H'
GROUP BY position
HAVING position < 20

Nachdem sich mein armer Computer 4,15 Sekunden von dieser Eingabe erholen musste, erfreute er mich mit dem folgenden Ergebnis (hier als rohe Ausgabe des MySQL-Monitors wiedergegeben):

+----------+------------------+
| position | avg(length(eva)) |
+----------+------------------+
|        1 |           5.4888 |
|        2 |           5.0011 |
|        3 |           5.1632 |
|        4 |           5.1163 |
|        5 |           5.0970 |
|        6 |           5.0959 |
|        7 |           5.0594 |
|        8 |           5.0211 |
|        9 |           4.8615 |
|       10 |           4.6762 |
|       11 |           4.4971 |
|       12 |           4.2664 |
|       13 |           4.2667 |
|       14 |           4.5282 |
|       15 |           5.0309 |
|       16 |           5.1548 |
|       17 |           5.0959 |
|       18 |           5.0286 |
|       19 |           4.9851 |
+----------+------------------+

Eine geplante Beispielanwendung

Ich werde wohl in den nächsten Wochen eine Beispielanwendung für diese Datenbank veröffentlichen. Es handelt sich um ein in Python geschriebenes CGI-Skript, das neben der bequemen Durchsicht der Transkription auch mit erweiterten Möglichkeiten wie einer Konkordanz und einer guten Suchfunktion dienen kann. Natürlich wird es auch über weit gehende Möglichkeiten zum Export von Transkriptionen oder Teilen daraus verfügen. Dass man so etwas nicht eben in einer Viertelstunde »runterhackt«, sollte einleuchten.

Wenn sich das etwas länger als ein »paar« Wochen hinzieht, bitte ich schon einmal um Entschuldigung.

Tags »

Autor:
Datum: Sonntag, 9. März 2008 16:15
Trackback: Trackback-URL Themengebiet: Hacking, Hilfsmittel

Feed zum Beitrag: RSS 2.0 Diesen Artikel kommentieren

3 Kommentare

  1. 1

    […] Meine Datenbank mit Transkriptionen des Voynich-MS scheint so weit fehlerfrei zu sein. Ich habe wirklich lange nichts »dickes« mehr […]

  2. 2

    […] Untersuchung dieser Erscheinung ist relativ einfach mit meiner Datenbank der Transkriptionen möglich. Ich habe heute ein kleines Python-Skript geschrieben, das solche Zählungen […]

  3. 3

    […] nützlich es auch ist, die Transkriptionen in einer relationalen Datenbank zu haben, so sehr wünscht man sich doch manchmal, dass diese als gewöhnlicher Text […]

Kommentar abgeben