Neo4J 3.0.3 を使用して、自分のアプリケーションで許容できるパフォーマンスを達成するのに本当に苦労しています。ここにいくつかの背景があります:
パフォーマンスを維持または向上させながら、アプリケーションの機能を拡張するために、Apache Solr を Neo4j に置き換えようとしています。
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 ではほぼ 1 か月かかります!!
「メタ」属性に一意性制約を使用せず、各ノードを空間インデックスに追加せずに、これらの時間を記録しました。このシナリオでの時間の結果は非常にひどいものでした。
この問題が発生したため、オンラインでパフォーマンスの調整を検索してみました。次のことは私の状況を改善しませんでした:
- 開いているファイルの制限を 1024 から 40000 に増やします
- ext4 を使用し、ここに記載されているように微調整します
-ページキャッシュサイズを 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 個のドキュメントがすべて読み込まれた場合でも)。
この時点で、このパフォーマンスの遅れがデータ モデルの性質やサーバーの構成などによるものかどうかが気になります。
私の目標は、このモデルから外挿し、いくつかの測定タイプをノードの独自のクラスに移動し、ベース レコード ノードからこれらへの関係を作成することでした。
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 が発生します。行動。現時点では、この問題を回避する方法がよくわかりません。さらに、実行時間はまったく改善されていないようです (エラーが発生すると、実際にはこれがはるかに速く終了すると予想されます)。