GraphGists

引言

由于算法交易,现代金融市场运行速度非常快。从本质上讲,计算机根据信息输入和巧妙的算法自动执行交易。所有这一切都发生得非常迅速。事实上,计算机执行交易的速度非常快,以至于信息从一个城市到另一个城市移动的速度实际上是一个限制因素。例如,如果华盛顿特区发布了影响金融市场的消息,纽约州的交易员可能会比例如华盛顿州西雅图的交易员更早“听到”这个消息。

由于信息传播速度不能超过光速(实际上,由于沿途必须进行各种处理,因此其传播速度要慢得多),因此我们可以计算特定信息从一个城市发布到到达其他城市所需时间的下限。正如您可能预期的那样,此问题涉及网络中的流量,因此在Neo4j(或任何图数据库中)中建模都相当简单。

数据模型

我们的数据模型由一组城市组成,每个城市都有经度和纬度,我们将使用这些经度和纬度来计算距离(我们可以将距离作为数据输入,但使用Neo4j完成此任务更有趣,并且在更通用的情况下,您可能希望节点能够移动)。每个城市都通过:BACKBONE_TO关系链接到一个或多个其他城市。这表示参与关系的两个城市之间有互联网骨干网。在此示例中,我们大多是编造了骨干网,尽管考虑到实际的海底电缆拓扑结构,到东京的骨干网是准确的。

Information network data model
图1. 信息网络数据模型

距离计算

在确定信息在城市之间流动所需时间的下限之前,我们必须确定通过互联网骨干网链接的城市之间的距离。我们假设连接城市的电缆位于大圆上,换句话说,每条电缆都位于城市之间最短的可能的线上。

// Find the great circle distance from Tokyo to Seattle
MATCH (c1:City { name: "Tokyo" })
MATCH (c2:City { name: "Seattle" })
RETURN 2 * 6371 * asin(sqrt(haversin(radians(c1.lat - c2.lat)) + cos(radians(c1.lat)) * cos(radians(c2.lat)) * haversin(radians(c1.lon - c2.lon)))) AS Distance

在我们的例子中,我们希望记录通过互联网骨干网连接的城市之间的距离。我们可以在:BACKBONE_TO边上存储此数据。请注意,我们不必担心重复计算,因为我们已指定了关系方向,因此每个距离只会计算一次。如果我们省略了方向,则每个距离将计算两次,尽管最终结果将完全相同。

// Add distance to backbone edges
MATCH (c1:City)-[r:BACKBONE_TO]->(c2:City)
WITH 2 * 6371 * asin(sqrt(haversin(radians(c1.lat - c2.lat))+ cos(radians(c1.lat))* cos(radians(c2.lat))* haversin(radians(c1.lon - c2.lon)))) AS dist, r, c1, c2
SET r.dist = dist
RETURN c1.name, c2.name, r.dist

信息流映射

我们的下一步是查找从一个城市到另一个城市的候选路径。一旦我们有了这些路径,我们就可以计算信息沿着每条路径移动所需的最小时间,并找到它们之间的最短路径。首先,我们可以找到从一个城市到另一个城市的所有唯一、简单的(没有重复的城市)路径。以下是东京和芝加哥的示例

// Find all unique, simple paths from one city to another
MATCH p=(:City { name: "Tokyo" })-[:BACKBONE_TO*]-(:City { name: "Chicago" })
WHERE all(c IN nodes(p) WHERE 1=size([m IN nodes(p) WHERE m=c]))
RETURN DISTINCT [ n IN nodes(p) | n.name] AS Path, length(p) AS Length

接下来,我们希望找到距离最短的路径。

// Find the shortest distance path from one city to another
MATCH p=(:City { name: "Tokyo" })-[:BACKBONE_TO*]-(:City { name: "Chicago" })
WHERE all(c IN nodes(p) WHERE 1=size([m IN nodes(p) WHERE m=c]))
WITH reduce(s = 0, hop IN relationships(p) | s + hop.dist) AS distance, p
ORDER BY distance LIMIT 1
RETURN DISTINCT [n IN nodes(p) | n.name] AS Path, length(p) AS Length, distance AS Distance

下一步是将距离更改为时间量。我们假设信息以光速在城市之间传播。如前所述,这并不完全正确,但由于我们正在寻找信息从一个城市移动到另一个城市所需时间的下限,因此使用信息流本身可能达到的最快速度是有意义的。

顺便说一句,我们可以使此模型更复杂,并且可能更准确,方法是考虑沿途每个连接点的处理时间。当信息到达网络中的特定节点时,它必须路由到其路径上的下一个节点,这需要一定量的非零时间。因此,我们可能实际上希望最大程度地减少信息需要传播的距离,但要受到每个“跃点”都有成本的约束。在这种情况下,我们倾向于更喜欢不太复杂的路径,即使它们略长一些。

我们可以使用下面的查询计算信息在城市之间传播所需的时间(毫秒)。请注意,我们只需将距离除以300即可获得毫秒,因为光速为300,000公里/秒。

// Find the shortest distance path from one city to another
MATCH p=(:City { name: "Tokyo" })-[:BACKBONE_TO*]-(:City { name: "Chicago" })
WHERE all(c IN nodes(p) WHERE 1=size([m IN nodes(p) WHERE m=c]))
WITH reduce(s = 0, hop IN relationships(p) | s + hop.dist) AS distance, p
ORDER BY distance LIMIT 1
RETURN DISTINCT [n IN nodes(p) | n.name] AS Path, length(p) AS Length, distance AS Distance

然后,我们可以将此查询泛化,以计算信息在任意两个城市之间传播所需的时间。

// Compute the minimum travel time between all pairs of cities
MATCH p=(c1:City)-[:BACKBONE_TO*]-(c2:City)
WHERE c1.name <> c2.name and all(c IN nodes(p) WHERE 1=size([m IN nodes(p) WHERE m=c]))
WITH reduce(s = 0, hop IN relationships(p) | s + hop.dist) AS distance, p, c1, c2
ORDER BY distance
RETURN c1.name AS `Start City`, c2.name AS `End City`, collect(distance / 300)[0] AS ms
ORDER BY c2.name

关于

由George Lesica(@glesica)和William Lyon(@lyonwj)创建。