Ich denke über die Entwicklung eines Systems zur Durchführung hochparalleler Abfragen auf verschachtelten (aber Baum-ähnlichen) Daten. Die potenziellen Benutzer sind Datenanalytiker (insbesondere Physiker), keine Programmierer. Für die Benutzeroberfläche möchte ich eine bekannte Abfragesprache verwenden, um neue Sprachen zu vermeiden.Welche deklarative Sprache ist gut für die Analyse von baumartigen Daten?
Die meisten der Daten wie folgt strukturiert sein würden (für Milliarden von event
Strukturen das folgende Schema vorstellen):
event: struct
|
+--- timestamp: bigint
+--- missing energy: float
+--- tracks: array of struct
| |
| +--- momentum: float
| +--- theta angle: float
| +--- hits: array of struct
| |
| +--- detector id: int
| +--- charge: float
| +--- time: float
| +--- ...
+--- showers: array of struct
|
+--- ...
Die Datenbank würde, nur gelesen werden und die meisten Abfragen wären Dinge wie:
- Dynamik der Strecke mit den meisten Hits mit Theta zwischen -2,4 und 2,4
- durchschnittliche Ladung aller Treffer mit der Zeit in 0-10 ps auf allen Spuren mit dem Impulse größer als 10 GeV/c
- gewichteter Durchschnitt Theta der beiden Spuren mit höchster Dynamik
et cetera. Gemeinsam ist diesen Abfragen, dass sie alle zu einem Skalar pro Ereignis aufgelöst werden, obwohl sie in die Arrays von Strukturen eintauchen, um dies zu tun. Sie führen "reduce" -ähnliche Operationen (allgemein fold
in Scala, aggregate
in Spark, DAF in SQL) über gefilterte, transformierte Teilmengen dieser Arrays durch. Ich konnte sie in Scala wie folgt schreiben:
// missing check for when zero tracks passed filter!
{event => event.tracks // get list of tracks
.filter(abs(_.theta) < 2.4) // in theta range
.maxBy(_.hits.size) // take the one with the most hits
.momentum // return its momentum
}
{event => mean(
event.tracks // get list of tracks
.filter(_.momentum > 10) // in momentum range
.flatMap(_.hits) // explode to hits
.filter(_.time < 10) // in time range
.map(_.charge) // return their charges
)} // ... to the mean function
// again missing check for less than two tracks!
{event => val List(one, two) = // unpack and assign "one" and "two"
event.tracks // get list of tracks
.sortBy(_.momentum) // sort by momentum
.take(2) // take the first two
// now compute the weighted mean of structs "one" and "two"
(one.theta*one.momentum + two.theta*two.momentum)/
(one.momentum + two.momentum)
}
Warum nicht einfach Scala benutzen? Mein Programm ist in C implementiert und wird auf GPUs laufen. Was auch immer Scala mir bringen würde, wäre eine neu implementierte Untermenge - mit anderen Worten eine erfundene Sprache. (Das gleiche könnte für Haskell, Javascript oder eine andere Sprache gesagt werden, die Funktionen als Argumente verwendet.)
Diese Abfragen sollten auch deklarativ sein. Wenn ich zu viel von einer allgemeinen Programmiersprache implementiere, könnten Details wie die Reihenfolge von Funktionsaufrufen relevant werden.
Warum nicht einfach SQL verwenden? Ist es möglich, Abfragen wie die obigen einfach, so zu schreiben, dass sie für alle anderen als den Autor lesbar sind? Abfragen wie die oben genannten sind die Norm, keine komplexen Extreme.
SQL unterstützt geschachtelte Arrays von Strukturen, aber alle Beispiele, die ich von unter Verwendung dieser Unterstruktur finden kann, sind horrend kompliziert. Man muss die Ereignistabelle in eine Tabelle von Spuren auflösen (oder doppelt explodieren, um Treffer zu erhalten), und eine komplexe Buchhaltung wäre erforderlich, um nicht explodieren zu müssen und zu einem Skalar pro Ereignis zurückzukehren.
Ich glaube, ich SQL mit neuen Funktionen wie MAXIMAL(collection, function)
verwenden könnte, die eine Struktur aus einem Array, ähnlich wie track[12]
jedoch unter Verwendung der vom Benutzer bereitgestellten Funktion als eine Zielfunktion für die Maximierung zurückzukehren, minimiert, zu finden, mit dem oberen/unteren N, etc Ich glaube nicht, dass SQL unterstützt, Funktionen als Argumente zu übergeben. Wenn ich eine SQL schreibe, die das tut, wäre das nicht Standard.
Gibt es einen weit verbreiteten Dialekt von SQL, der Passing-Funktionen als Argumente unterstützt?
Oder gibt es eine andere deklarative Sprache, die ich berücksichtigen sollte?
Ihre verschachtelten Strukturen sind nur zusätzliche Tabellen. Sie haben eine Prinzip-Tabelle "Ereignis" mit einer eindeutigen Kennung. Dann hat eine 'track'-Tabelle einen Fremdschlüssel für den eindeutigen Bezeichner in 'event'. Das erlaubt eine Beziehung, in der *** eine "Ereignis" -Reihe mit *** null bis vielen "Spur" -Reihen verknüpft ist. Das selbe gilt für 'event':' shows' und 'track':' hit', etc, etc. Die SQL wird dann im Allgemeinen ein Fall, zwei Tabellen zu verbinden, dann zu aggregieren, dieses Ergebnis mit einer anderen Tabelle zu verbinden und erneut zu aggregieren, usw. – MatBailie
In Bezug auf "Funktionen als Argumente" wird das in keinem Dialekt von SQL "normal" sein. Einige haben ihre eigene CLR und erlauben Ihnen, einige magische Dinge zu tun, aber selbst wenn Sie es geschafft haben, wäre es nichts, was ein Standard-SQL-Entwickler * erkennen würde (relevant für Sie in Bezug auf Unterstützung) *. Aber MS SQL Server hat "APPLY", mit dem Sie Funktionen auf eine andere Art kapseln können, die für Sie relevant sein könnte. – MatBailie
Wäre es einfach zu schreiben/einfach zu lesen, wenn jede Anfrage eine Join + Aggregation ist? Wenn Sie zeigen können, wie die SQL-Abfragen aussehen würden (z. B. meine drei Beispiele), und es ist nicht schrecklich, das ist die Art von Antwort, nach der ich suche. (Sorry wegen der Subjektivität von "horrend", aber ich denke du weißt warum das mein Kriterium ist.) –