我一直在努力使用Neo4J 3.0.3为我的应用程序实现可接受的性能。以下是一些背景知识:
我正在尝试用Neo4j取代Apache Solr,以扩展其功能,同时保持或提高性能。
在Solr中,我的文档基本上是这样的:
{
"time": "2015-08-05T00:16:00Z",
"point": "45.8300018311,-129.759994507",
"sea_water_temperature": 18.49,
"sea_water_temperature_depth": 4,
"wind_speed": 6.48144,
"eastward_wind": 5.567876,
"northward_wind": -3.3178043,
"wind_depth": -15,
"sea_water_salinity": 32.19,
"sea_water_salinity_depth": 4,
"platform": 1,
"mission": 1,
"metadata": "KTDQ_20150805v20001_0016"
}
由于Solr是一个键值数据存储,我对Neo4J的初始翻译很简单,因此我可以感受到使用API。
我的方法基本上是让每个Solr记录等同于Neo4J节点,其中每个键值都将成为节点属性。
显然需要进行一些调整(将None改为' None'(python),将ISO时间更改为纪元时间(neo4j不支持索引日期时间),将点更改为lat / lon(neo4j空间索引)等等。)
我的目标是使用这个模型加载Neo4J,无论它有多天真。
以下是我在单个记录中加载时进行的休息调用的示例(使用http:localhost:7474 / db / data / cypher作为我的端点):
{
"query" :
"CREATE (r:record {lat : {lat}, SST : {SST}, meta : {meta}, lon : {lon}, time : {time}}) RETURN id(r);",
"params": {
"lat": 40.1021614075,
"SST": 6.521100044250488,
"meta": "KCEJ_20140418v20001_1430",
"lon": -70.8780212402,
"time": 1397883480
}
}
请注意,我实际上删除了很多用于测试neo4j的参数。
目前我有严重的性能问题。将这样的文档加载到Solr中需要大约2秒钟。对于Neo4J,它需要:
使用REST API约20秒
使用BOLT约45秒
使用py2neo <〜> 70秒我需要加载~50,000,000条记录。在Solr中执行此操作通常需要24小时,因此Neo4J可能需要将近一个月的时间!
我记录了这些时间而没有在我的元素上使用唯一性约束。属性,而不将每个节点添加到空间索引中。这种情况导致的时间非常糟糕。
遇到这个问题,我尝试在线搜索性能调整。以下事情并没有改善我的情况:
- 将打开文件限制从1024增加到40000
- 使用ext4,并按照记录here
进行调整- 将页面缓存大小增加到16 GB(我的系统有32个)
到目前为止,我只解决了加载时间问题。在我一夜之间加载了大约50,000个节点后,我尝试查询我的空间索引,如下所示:
CALL spatial.withinDistance('my_layer', lon : 34.0, lat : 20.0, 1000)
以及我的时间指数如此:
MATCH (r:record) WHERE r.time > {} AND r.time < {} RETURN r;
这些简单的查询几分钟就可以返回几个节点。
在Apache Solr中,空间索引非常快,并且在5秒内响应(即使加载了所有50000000个文档)。
此时,我担心这种性能滞后是否是由于我的数据模型的性质,服务器的配置等等。
我的目标是从这个模型中推断,并将几种测量类型移动到他们自己的Node类,并创建从我的基本记录节点到这些模型的关系。
我是否有可能滥用Neo4j,并且需要重新创建此模型以使用关系和几种不同的Node类型?我是否应该期待看到显着的改进?
作为旁注,我最初计划使用三重商店(特别是议会)来存储这些数据,并且在努力与RDF合作之后,决定Neo4J看起来很有前途并且更容易起床和运行。回到RDF是否值得一试?
欢迎任何建议,提示和评论。提前谢谢。
编辑:
正如评论中所建议的那样,我改变了加载脚本的行为。
以前我以这种方式使用python:
from neo4j.v1 import GraphDatabase
driver = GraphDatabase('http://localhost:7474/db/data')
session = driver.session()
for tuple in mydata:
statement = build_statement(tuple)
session.run(statement)
session.close()
使用这种方法,实际的.run()语句几乎没有时间运行。 .close()语句是所有运行时间发生的地方。
我的修改方法:
transaction = ''
for tuple in mydata:
statement = build_statement(tuple)
transaction += ('\n' + statement)
with session.begin_transaction() as tx:
tx.run(transaction)
session.close()
我有点困惑,因为这种行为几乎是一样的。 .close()仍然需要大约45秒,除非它没有提交。因为我在每个语句中重用相同的标识符(CREATE(r:record {...}).... CREATE(r:record {...})...),我得到关于这个的CypherError行为。我现在还不知道如何避免这个问题,此外,运行时间似乎没有改善(我希望错误实际上使得终止更快)。