什么声明式语言擅长分析树状数据?

Jim*_*ski 6 sql programming-languages declarative

我正在考虑开发一个系统来对嵌套(但树状)数据执行高度并行的查询。潜在用户是数据分析师(特别是物理学家),而不是程序员。对于用户界面,我想使用一种众所周知的查询语言来避免新语言的激增。

大多数数据的结构是这样的(想象以下数十亿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
         |
         +--- ...
Run Code Online (Sandbox Code Playgroud)

数据库是只读的,大多数查询是这样的:

  • θ 值在 -2.4 和 2.4 之间的点击次数最多的轨道的动量
  • 动量大于 10 GeV/c 的所有轨道上所有命中的平均电荷随时间在 0-10 ps
  • 具有最高动量的两条轨道的加权平均θ

等等。这些查询的共同点是,它们都解析为每个事件的一个标量,尽管它们会深入研究结构数组来做到这一点。它们跨这些数组的过滤、转换子集执行类似“reduce”的操作(通常fold在 Scala 中、aggregateSpark 中、SQL 中的 DAF 中)。我可以像这样在 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)
}
Run Code Online (Sandbox Code Playgroud)

为什么不直接使用 Scala?我的程序是用 C 实现的,可以在 GPU 上运行。我带来的任何 Scala 都将是一个重新实现的子集——换句话说,是一种发明的语言。(Haskell、Javascript 或其他大量使用函数作为参数的语言也是如此。)

此外,这些查询应该是声明性的。如果我实现了过多的通用编程语言,函数调用顺序等细节可能会变得相关。

为什么不直接使用 SQL?是否可以轻松编写上述查询以便作者以外的任何人都可以阅读它们?像上面这样的查询是常态,而不是复杂的极端。

SQL 支持嵌套的结构数组,但我能找到的所有使用该子结构的示例都非常复杂。必须将事件表分解为轨道表(或双重分解以获得命中),并且需要一些复杂的计算来解开并恢复每个事件的一个标量。

我想我可以将 SQL 与新函数一起使用,例如MAXIMAL(collection, function)从数组中返回一个结构体,类似于track[12]但使用用户提供的函数作为最大化、最小化、查找顶部/底部 N 等的目标函数。我不认为SQL 支持将函数作为参数传递。如果我写了一个这样做的 SQL,那将是非标准的。

是否有广泛使用的 SQL 方言支持将函数作为参数传递?

或者我应该考虑另一种声明性语言吗?

Pau*_*laG 2

我之前在评论中发布过此内容,但将其移至此处。

我和其他人一起讨论图形数据库的使用。我不熟悉 Neo4j 查询,但我希望它们有能力。同样,SPARQL 非常适合此类事情。

对于第一个查询,SPARQL 查询可能如下所示:

PREFIX : <http://yournamespace.com/accelerator/> .

SELECT ?momentum (MAX(?hitcount) as ?maxhits)
WHERE {
    SELECT ?momentum (COUNT(?hits) AS ?hitcount)
    WHERE ?track :momentum ?momentum .
          ?track :theta ?theta .
          FILTER (?theta > -2.4 AND ?theta < 2.4) .
          ?track :hits ?hits
    GROUP BY ?track
}
GROUP BY ?momentum;
Run Code Online (Sandbox Code Playgroud)

标识符带有 : 前缀,因为它们需要编码为 URI。但这是迁移到 RDF(SPARQL 数据库的数据格式)的内部细节。

上面的查询正在执行子查询,因为您希望聚合(根据计数),然后再次聚合(根据计数的最大值)。但你可以看到,这一切都是以类似 SQL 的方式处理的,并且不需要后处理。