Я думаю о разработке системы для выполнения высокопараллельных запросов на вложенных (но древовидных) данных. Потенциальными пользователями являются аналитики данных (физики, в частности), а не программисты. Для пользовательского интерфейса я хочу использовать хорошо известный язык запросов, чтобы избежать распространения новых языков.Какой декларативный язык хорош при анализе древовидных данных?
Большая часть данных будет структурирована следующим образом (представьте себе следующую схему для миллиардов event
структур):
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
|
+--- ...
база данных будет доступен только для чтения, и большинство запросов было бы что-то вроде:
- импульс дорожки с наибольшим количеством хитов с тета между -2.4 и 2.4
- средний заряд всех обращений со временем в 0-10 пс на всех направлениях с импульсом больше, чем 10 ГэВ/с
- средневзвешенная теты из двух дорожек с самым высоким импульсом
и так далее. Что общего у этих запросов, так это то, что все они решаются на один скаляр для каждого события, хотя они вникают в массивы структур, чтобы сделать это. Они выполняют «сокращение» как операции (обычно fold
в Scala, aggregate
в Spark, DAF в SQL) через фильтрованные, преобразованные подмножества этих массивов. Я мог бы написать их в Scala, как это:
// 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)
}
Почему бы просто не использовать Scala? Моя программа реализована на C и будет работать на графических процессорах. Независимо от того, что я приношу в Scala, это переопределенное подмножество - другими словами, изобретенный язык. (То же самое можно сказать и для Haskell, Javascript или другого языка, который сильно использует функции в качестве аргументов.)
Кроме того, эти запросы должны быть декларативными. Если я реализую слишком много общего языка программирования, такие детали, как порядок вызовов функций, могут стать актуальными.
Почему бы просто не использовать SQL? Можно ли легко написать такие запросы, как выше, ,, чтобы они были прочитаны кем-либо, кроме автора? Запросы, подобные приведенным выше, являются нормой, а не сложными крайностями.
SQL поддерживает вложенные массивы структур, но все примеры, которые я могу найти из , используя, что подструктура ужасно сложна. Нужно взорвать таблицу событий в таблицу треков (или дважды взорвать, чтобы получить хиты), и потребуется некоторая сложная учетная информация для нераспределения и возврата к одному скаляру на событие.
Я полагаю, я мог бы использовать SQL с новыми функциями, как MAXIMAL(collection, function)
, которые возвращают на структуру из массива, похожий на track[12]
, но с использованием функции предоставленного пользователем в качестве целевой функции для максимизации, минимизации, находя верх/низ N, и т.д. Я не думаю, что SQL поддерживает передачу функций в качестве аргументов. Если я напишу SQL, то это будет нестандартным.
Существует ли широко используемый диалект SQL, который поддерживает функции передачи в качестве аргументов?
Или есть другой декларативный язык, который я должен рассмотреть?
Ваши вложенные структуры - это просто дополнительные таблицы. У вас есть таблица «event» с уникальным идентификатором. Затем таблица 'track', чем внешний ключ к уникальному идентификатору в' event'. Допустим, что *** одна *** строка 'event' связана с *** нулем для многих строк ***' track'. То же самое относится к 'event':' shower 'и 'track':' hit' и т. Д. И т. Д. Затем SQL обычно становится примером объединения двух таблиц, затем объединения, объединения этого результата в другую таблицу и повторного объединения, и т. д. и т. д. – MatBailie
Что касается 'функций как аргументов', это не будет« нормальным »в любом диалекте SQL. У некоторых есть своя собственная среда CLR и позволяет вам делать какие-то магические вещи, но даже если вы ее заработаете, это будет не стандартный разработчик SQL, который бы узнал * (что касается вас с точки зрения поддержки) *. Но у MS SQL Server есть 'APPLY', который позволяет вам инкапсулировать функции по-другому, которые могут иметь отношение к вам. – MatBailie
Было бы легко написать/легко прочитать, если каждый запрос является объединением + агрегацией? Если вы можете показать, как будут выглядеть SQL-запросы (например, мои три примера), и это не ужасно, это тот ответ, который я ищу. (Извините за субъективность «ужасающего», но я думаю, вы знаете, почему это мой критерий.) –