内容简介:就在前几天,我和一位投资风险经理谈了他的团队正在研究的一个数据问题,他想知道为了简单起见,假设我们只想追踪一个度量,这个度量是$r^2$。当我们比较共同基金和基准的价值变化时,变化轨迹有多近?$r^2$总是在0和1之间。0值意味着基准与共同基金无关,而1值意味着有关。那么我们怎么来建立模型呢?
就在前几天,我和一位投资风险经理谈了他的团队正在研究的一个数据问题,他想知道 Neo4j
是否能提供帮助。假设你有大约20,000个共同基金和ETFs,你想要追踪他们是如何衡量基准的,例如标准普尔500指数的回报率。比如说,2000个不同的基准,你想要跟踪它五年内的每一天的情况。这就有$20000 5 252 * 2000$ 共500亿数据点。如果我们使用关系数据库的话,这是一个很大的连接表。我们如何使用 neo4j
建立一个有效模型?
为了简单起见,假设我们只想追踪一个度量,这个度量是$r^2$。当我们比较共同基金和基准的价值变化时,变化轨迹有多近?$r^2$总是在0和1之间。0值意味着基准与共同基金无关,而1值意味着有关。那么我们怎么来建立模型呢?
我们的第一个选项是将该基金作为一个节点建模,基准作为一个节点,并通过他们对应的日期进行关系连接,其中日期和$r^2$作为关系的属性,如上所示。我们将有20,000个基金节点,2000个基准节点,以及500亿条关系。这是一个非常稠密的图。
首先我们尝试一个查询,看看我们的模型是怎么做的。我想知道在2017年10月31日(万圣节)X基金和基准Y的$r^2$情况。
MATCH (f:Fund {name: $fund_name})-[r:HAS_DATA]->(b:Benchmark {name: $benchmark_name}) WHERE r.date = $date RETURN r.r_squared
首先对 :Fund(name)
建立索引,这样可以直接快速的定位到我们所需要查询的 Found
,但是这个模型在性能上很糟糕,主要是我必须遍历$2000 5年 252天= 250万$个关系,以找到我想要的。
让我们试试另一种方法,使用日期关系类型:
为了找到基金和基准之间的$r^2$,可以这样写查询语句:
MATCH (f:Fund {name: $fund_name})-[r:ON_2017_10_31]->(b:Benchmark {name: $benchmark_name}) RETURN r.r_squared
现在,我只需要遍历2000个关系,而不是遍历250万个关系,这要快得多。另一个好处是,如果我想在指定的一个日期内得到所有基金的基准,这很容易得到:
MATCH (f:Fund {name: $fund_name})-[r:ON_2017_10_31]->(b:Benchmark) RETURN b.name, r.r_squared
但是让我们尝试另一个查询。比方说,我们想看看自今年初以来,一个基金与一个基准的$r^2$是如何变化的。
MATCH (f:Fund {name: $fund_name})-[r]->(b:Benchmark {name: $benchmark_name}) WHERE TYPE(r) STARTS WITH "ON_2017" RETURN TYPE(r) AS day, r.r_squared
首先,我们可以快速地从索引中一次遍历找到指定的基金节点,然后我们再遍历250万的关系来找到我们想要的。现在,遍历2-4百万的关系并不是极限。Neo4j可以在大约一秒钟内做到这一点。但我们可以做得更好。让我们尝试将基准名称移动到关系中。
使用这个模型,我们将从我们的基金节点开始,遍历5年* 252天= 1,260个关系,并检查日期属性满足条件得到想要的结果。
MATCH (f:Fund {name: $fund_name})-[r:FOR_BENCHMARK_X]->(b:Benchmark {name: $benchmark_name}) WHERE r.date > $date RETURN r.date, r.r_squared
好吧…如果想要得到一个基金与所有基准之间的$r^2$?
MATCH (f:Fund {name: $fund_name})-[r]->(b:Benchmark) WHERE r.date = $date RETURN b.name, r.r_squared
从上面查询语句看我们又要遍历$5年 252天 2000$个基准或250万个关系。我们不能同时使用日期和基准名称作为关系类型。 Neo4j
只能处理大约32k的关系类型,而不是我们需要的250万。那么我们能做什么呢?
这是正确的。我们可以创建一个新类型的节点- FundDay
,所以有20,000个基金 5年 252天大约是2500万个节点。然后我们将这些节点与我们的基金和基准联系起来。我们的查询是想得到所有的$r^2$值,:
MATCH (f:Fund {name: $fund_name})-[:ON_2017_10_31]->()-[r]->(b:Benchmark) RETURN b.name, r.r_squared
我们从基金节点开始,首先遍历 FundDay
(我们将忽略它),然后再遍历这个 FundDay
关联的所有基准。因此,我们的查询将遍历一段关系,再加上2000个基准。遍历2,001个关系要比遍历250万个关系快得多。
还有一个小问题。我们现在的图是有20000年基金节点,2000年基准节点,和250万 FundDay
节点组成.但我们仍然有25 m FundDay
节点和2000年基准之间的关系,大约500亿条关系。我们可以削减这个数据库的大小吗?我们记住Neo4j可以处理像整数、字符串、浮点数等标量值,以及它们的数组。因此,如果我们将$r^2$存储在数组中,而不是分别存储每个$r^2$,如何存储在一个列表中?
我们现在存储了一个5年* 252天$r^2$值的数组,而不是在$r^2$属性中存储一个值。2017年万圣节这天的$r^2$位于列表中的1218位。
MATCH (f:Fund {name: $fund_name})-[r:FOR_BENCHMARK_X]->(b:Benchmark {name: $benchmark_name}) RETURN r.r_squared[1218]
从2017年第一个交易日到万圣节这天,所有的$r^2$值,首先我们计算开始的index:4年* 252 = 1008,在加上2017年时间段,所以我们现在的查询是:
MATCH (f:Fund {name: $fund_name})-[r:FOR_BENCHMARK_X]->(b:Benchmark {name: $benchmark_name}) RETURN r.r_squared[1009..1218]
首先从基金节点开始,遍历一次关系,并将$r^2$属性数组的一部分作为值。那么对于许多基准测试呢?
MATCH (f:Fund {name: $fund_name})-[r]->(b:Benchmark) RETURN b.name, r.r_squared[1009..1218]
上面的查询成本只需遍历2000个关系(每个基准测试一个)和2000个属性查找,而且我们降低数据库的大小,只有20000个基金节点,2000个基准节点和4000万(一个为每个组合)个关系。
还有一个小问题:默认情况下,Neo4j将数组属性存储在120字节的块中。8-10字节的开销会留下112字节的存储空间。由于每个$r^2$值是一个需要8个字节的浮点数,每个块每次只需要使用14个$r^2$值,这相当于需要从一个block跳转到另外一个block,会降低一点查询速度。
但是,由于我们提前知道了要存储的数量,我们可以将这个参数(array_block_size)更改为10080(5年* 252天(8个字节)的值。Neo4j将使用这个值加上8-10字节的开销。每一页有8192个字节,所以我们可以预留一页半(12878)或两页(16,374),留下10个字节的开销。我们的数据库大小约为700 GB,所以我们需要使用x1.16xlarge或x1e。8xlarge每月预付一笔3年的预付费用,每月约1,365美元。另一种选择是,我们可以花2万美元买一个大的RAM服务器,然后自己托管它。
记住,在图数据库中没有“第三范式”来建模数据。这是一个疯狂的前沿。使用你所拥有的数据和你想要回答的问题作为指南,但一定要让你的想象力和创造力帮助你前进。
来源: https://dzone.com/articles/mutual-fund-benchmarks-with-neo4j
以上所述就是小编给大家介绍的《使用Neo4j对共同基金进行分析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Node.js 基金会与 JS 基金会合并为 OpenJS 基金会
- Linux 基金会成立持续交付基金会
- GraphQL 基金会成立,将交由 Linux 基金会管理
- Ceph 基金会正式成立!接受 Linux 基金会的管理
- Linux基金会陈泽辉:Linux基金会的开源指南
- Kodi 基金会加入 Linux 基金会,帮助发展开源运动
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。