wiki:UniPhi/Datenbank

Datenbank-Modell

Nach vielen Überlegungen (siehe MVC-Framework) schlag ich für UniPhi nun eine einzige MongoDB-Installation vor. Dank Indizies über beliebige Datenstrukturen im JSON-Dokument sind auch komplexe Queries performant, sodass sich alle möglichen Arten von Anfragen performant stellen lassen sollten (vgl. z.B. in der MongoDB-Dokumentation das Tutorial Indizes: Control Results of Text Search was genau unser Anwendungszweck Volltextsuche + Labelsuche ist).

UniPhi soll eine Menge Features kriegen, die nicht alle auf einmal umgesetzt werden können. Mit den Programmfeatures wird auch die Komplexität des tatsächlichen Datenschemas steigen. Dennoch kann man die Feature-Zerstückelung dafür nutzen, den "Schemas" eine Versionsnummer zu geben (Schemamigration). Ein solcher Versuch soll hier unternommen werden, wobei die Versionen einfach hochgezählt werden und die Reihenfolge und vor allem das konkrete Aussehen der Schemas bei hohen Versionen keine Rolle mehr spielt.

Version 1

Einfach nur Records, die einen Bookmark speichern. _id ist von MongoDB vorgesehen. _version ist der von mir vorgesehene Name zur Durchnummerierung der Versionen.

new Record({
  "_id":      123,
  "_version": 1,
  "title":    "Mitschriften Mathelerntag: Residuensatz",
  "url":      "http://tinypic.com/view.php?pic=95mybn&s=6&hid=0" ,
});

Version 2

Zur Umsetzung des Features Suche sollte eine Volltextsuche auf dem Title und ein Labelssuche auf den Labels ausprobiert werden. Dazu wird einfach erweitert:

new Record({
  "_id":      123,
  "_version": 2,
  "title":    "Mitschriften Mathelerntag: Residuensatz",
  "url":      "http://tinypic.com/view.php?pic=95mybn&s=6&hid=0" ,
  "tags":     ["magnitude", "charge", "potenzreihe", "residuensatz", "elektrodynamik", "theo3"],
});

Version 3

Die Darstellung von Records finde ich sehr wichtig. Zu jedem Eintrag sollte es ein Bild geben, der ein Thumbnail des verlinkten Bildes oder PDFs, ein Screenshot der verlinkten Seite (automatisch asyncron generiert: PhantomJS) oder ein Bild von der verlinkten Seite (so macht es Facebook) ist. Das muss natürlich irgendwo auf dem UniPhi-Server gecachet werden und dann im Record auftauchen

new Record({
  "_id":      123,
  "_version": 3,
  "title":    "Mitschriften Mathelerntag: Residuensatz",
  "url":      "http://tinypic.com/view.php?pic=95mybn&s=6&hid=0" ,
  "tags":     ["magnitude", "charge", "potenzreihe", "residuensatz", "elektrodynamik", "theo3"],
  "thumbnail":"http://uniphi.de/thumb/EfNVmZ924Xs.jpg"
});

Version 4

Verschiedene Typen von Records müssen andere Werte speichern. Hier entfaltet sich die Kraft von NoSQL/JSON/Schemalos, da wir beliebige Key/Value-Paare speichern können, die wir festhalten wollen. Mit Typen meine ich verschiedenartige Einträge von Records, eben nicht nur Bookmarks sondern etwa User-Uploads, klassifiziert (Fremde) Bilder/PDF-Files, Dropbox-Querverweis, Youtube-Links (ich glaube bei diesen Typen haben wir schon mal länger diskutiert, was es da alles so gibt, und in wie fern sie sich einerseits technisch, anderseits inhaltlich unterscheiden)

new Record({
  "_id":      124,
  "_version": 4,
  "title":    "Mitschrift Theo2 bei Prof. Wasmuth, Vorlesung 13 (Wegintegrale)",
  "type":     "connected-dropbox",
  "dropbox-user": "hans.dieter@web.de",
  "dropbox-path": "/Uni/SS 2014 (2. Semester)/Theo2 Wasmuth/Mitschriften/Vorlesung13.pdf",
  "local-cache": GridFsElement,
  "thumbnail":"http://uniphi.de/thumb/Kf5V2Z4A_s.jpg"
  "tags":     ["integral", "unvollständig"],
});

Version 5

Records sollten Autoren haben, die sie bearbeiten, außerdem Zeitstempel von wann sie sind. Außerdem sollten zu Records Diskussionsbeiträge passieren können, ähnlich wie bei StackOverflow.

new Record({
  "_id":      123,
  "_version": 5,
  /* erweitert die Felder von oben */
  "author":   "Hannes Bambel",
  "date":     Date(...), // nativer Datentyp (ist _id eigentlich auch)
});

new Comment({
  "_id":       456,
  "_version":  5,
  "record_id": 123,
  "author":    "Ulrike Huber",
  "date":      Date,
  "text":      "Ihr habt einen Fehler bei den Vorfaktoren. Blubb..."
});

Version 6

Und das ganze sollte bewertbar werden (Reddit/StackOverflow):

new Record({
  "_id":      123,
  "_version": 6,
  /* erweitert die Felder von oben */
  "votes":    { 'up': 3 },
});

new Comment({
  "_id":       456,
  "_version":  6,
  "record_id": 123,
  /* erweitert die Felder von oben Ü/
  "votes":    { 'up': 1, 'down': 2 },
});

(Hier kann man zB über Details streiten: StackOverflow erlaubt bei Kommentaren nur das Upvoten, nicht downvoten). Ebenso: Will man verschachtelte Kommentare?

Version 7

Dann kommt der Wiki-Gedanke, den man verschiedentlich modellieren kann. Es geht darum, dass etwa Records durch alle verbessert werden können (als "Wikiseite", wie StackOverflow), Comments nur durch ihre Autoren bearbeitbar sind (wie Facebook/StackOverflow). Es gibt verschiedene Methoden, Diffs zu speichern - in den Objekten oder außerhalb. Auch gibt es Frameworks, die das abnehmen. Achtung, wir haben schon _version als Programmversionsnummer (möglicherweise sollte man dies sinnvoller benennen).

In der Regel würde man die Diffs/alten Objekte in einer getrennten Collection speichern. Ein generischer Ansatz, hier als Skizze, könnte das ganze z.B. so umändern:

new Record({
  "_id":      123,
  "_version": 7,
  /* erweitert; die aktuellen Belegungen stellen die aktuellen Werte wieder */
  "history":  [ 372, 283 ], // Diff-ObjectIds
});

new Comment({
  "_id":       456,
  "_version":  7,
  "record_id": 123,
   /* erweitert; die aktuellen Belegungen stellen die aktuellen Werte wieder */
  "history":  [Diff]   // verbreitete Kurznotation für obiges
});

new Diff({
  "_id":      372,
  "_version":  7,
  "old":      { /* altes Objekt oder nur die Key-Value-Paare die sich geaendert haben */ },
  "date":     Date,
  "user":     "Hans Dieter",
});

Es ist klar, dass man ebenso Benutzerobjekte und so braucht, wir sind hier also im vollen relationalen Bedarf.

Version 8

Records sollten untereinander in einfachen, nicht weiter typisierten Relationen stehen, so hatten wir das mal am Whiteboard besprochen (wo sind dazu die Whiteboard-Fotos?). Auch hier gibt es verschiedene Möglichkeiten, Graphen zu speichern. Mir gefällt am besten der Triplestore (Subjekt-Prädikat-Objekt), weil er die Verbindung darstellt und sich damit kommentieren, bewerten und erweitern ließe.

new Link({
   "_id":      12345,
   "_version": 8,
   "s":        "http://uniphi.de/r/Kf5V2Z4A",
   "p":        "PART_OF",
   "o":        "http://uniphi.de/r/da7Ca9da",
});

Meine Notation suggeriert jetzt RDF, in der Realität ständen da eher Record-IDs. Aber man sieht wo die Reise hingeht: Jedes Objekt in der Datenbank sollte durch eine URL repräsentierbar sein und so auch von außen eindeutig. Tatsächlich könnte man die gesamte Datenbank nur mit derartigen Links (N-Tupeln) aufbauen und simulierte damit eine relationale Datenbank. Das ist immer die Frage, welchen Zwischenweg man da geht. Ich könnte mir aber vorstellen, in dem man Versionsattribute an den Daten hat, kann man auch Programme aufheben, die mit verschiedenen Versionen umgehen können (falls man das wirklich will - sinnvoller ist es vielleicht, alte Daten zu löschen). Hauptsache, die Datenbank fängt nicht irgendwann wild zu wuchern an mit esoterischen Schlüsselnamen, die sich niemand merken kann.

Last modified 3 years ago Last modified on Jun 1, 2014 8:28:26 AM