19

ArangoDB を使用して、友達のリストを取得しようとしています。基本的な友達の友達リストだけでなく、ユーザーと友達の友達に共通の友達が何人いるかを知り、結果を並べ替えたいと思っています。最高のパフォーマンスを発揮する AQL クエリを (再) 記述しようと何度か試みた結果、次のようになりました。

LET friends = (
  FOR f IN GRAPH_NEIGHBORS('graph', @user, {"direction": "any", "includeData": true, "edgeExamples": { name: "FRIENDS_WITH"}})
  RETURN f._id
)

LET foafs = (FOR friend IN friends
  FOR foaf in GRAPH_NEIGHBORS('graph', friend, {"direction": "any", "includeData": true, "edgeExamples": { name: "FRIENDS_WITH"}})
    FILTER foaf._id != @user AND foaf._id NOT IN friends
    COLLECT foaf_result = foaf WITH COUNT INTO common_friend_count
    RETURN {
      user: foaf_result,
      common_friend_count: common_friend_count
    }
)
FOR foaf IN foafs
  SORT foaf.common_friend_count DESC
  RETURN foaf

残念ながら、パフォーマンスは私が望んでいたほど良くありません。同じクエリ (およびデータ) の Neo4j バージョンと比較すると、AQL はかなり遅いようです (5 ~ 10 倍)。

私が知りたいのは...クエリを改善してパフォーマンスを向上させるにはどうすればよいですか?

4

1 に答える 1

22

私は のコア開発者の 1 人であり、ArangoDBクエリの最適化を試みました。私はあなたを持っていないので、dataset私は自分のテストについてしか話すことができずdataset、私の結果を検証していただければ幸いです.

まず、ArangoDB2.7 で実行している場合ですが、この特定のケースでは、2.6 との大きなパフォーマンスの違いは期待できません。

私のdataset場合、クエリをそのまま 7 秒以内に実行できました。最初の修正: あなたの友人のステートメントではincludeData: true_id. をincludeData: false GRAPH_NEIGHBORS直接返す_idと、ここでサブクエリを取り除くこともできます

LET friends = GRAPH_NEIGHBORS('graph', 
                              @user,
                              {"direction": "any",
                               "edgeExamples": { 
                                   name: "FRIENDS_WITH"
               }})

これにより、私のマシンでは〜1.1秒になりました。なのでNeo4Jに近い性能になると思います。

なぜこれが大きな影響を与えるのですか? 内部的には_id、ドキュメント JSON を実際にロードせずに、最初に値を見つけます。クエリでは、このデータは必要ないため、開かずに安全に続行できます。

しかし、今は本当の改善のために

あなたのクエリは「論理的な」方法で進み、最初にユーザーの隣人を取得し、隣人を見つけて、 afoafが見つかった頻度を数えて並べ替えます。これは、完全な foaf ネットワークをメモリ内に構築し、全体としてソートする必要があります。

別の方法でそれを行うこともできます: 1. ユーザーのすべてfriendsを検索 ( のみ_ids) 2. すべてを検索foaf(完全なドキュメント) 3. それぞれについてfoafすべてを検索foaf_friends( のみ) 4.と_idsの交点を検索し、それらをカウントしますfriendsfoaf_friends

このクエリは次のようになります。

LET fids = GRAPH_NEIGHBORS("graph",
                           @user,
                           {
                             "direction":"any",
                             "edgeExamples": {
                               "name": "FRIENDS_WITH"
                              }
                           }
                          )
FOR foaf IN GRAPH_NEIGHBORS("graph",
                            @user,
                            {
                              "minDepth": 2,
                              "maxDepth": 2,
                              "direction": "any",
                              "includeData": true,
                              "edgeExamples": {
                                "name": "FRIENDS_WITH"
                              }
                            }
                           )
  LET commonIds = GRAPH_NEIGHBORS("graph",
                                  foaf._id, {
                                    "direction": "any",
                                    "edgeExamples": {
                                      "name": "FRIENDS_WITH"
                                     }
                                  }
                                 )
  LET common_friend_count = LENGTH(INTERSECTION(fids, commonIds))
  SORT common_friend_count DESC
  RETURN {user: foaf, common_friend_count: common_friend_count}

私のテストグラフでは、〜0.024秒で実行されました

したがって、これにより実行時間が250倍速くなり、Neo4jでの現在のクエリよりも高速になると予想されますが、持っていないdatasetので確認できません。実行して教えていただければ幸いです.

最後に一つだけ

の場合edgeExamples: {name : "FRIENDS_WITH" }は の場合と同じですがincludeData、この場合、実際のエッジを見つけて調べる必要があります。名前に基づいてエッジを別のコレクションに保存すると、これを回避できます。そして、edgeExamples も削除します。これにより、パフォーマンスがさらに向上します (特にエッジが多い場合)。

未来

次のリリースにご期待ください。現在、AQL にいくつかの機能を追加しています。これにより、ケースのクエリがはるかに簡単になり、パフォーマンスがさらに向上するはずです。

于 2015-10-23T13:55:06.633 に答える