2016-10-18 5 views
6

2つの大きなコレクションの間で巨大な結合を使用してグラフの一部が構築され、どちらのコレクションにドキュメントを追加するたびにも実行されます。 クエリはolder postに基づいています。ArangoDB:例文によるクエリの関数として挿入

FOR fromItem IN fromCollection 
    FOR toItem IN toCollection 
     FILTER fromItem.fromAttributeValue == toItem.toAttributeValue 
     INSERT { _from: fromItem._id, _to: toItem._id, otherAttributes: {}} INTO edgeCollection 

これは、私のデータセットの完了に約55,000秒かかります。私はそれをより速くするための提案を絶対に歓迎する。

  1. 私はアップサートを必要とする:

    は、しかし、私は2つの関連する問題があります。通常、upsertは問題ありませんが、この場合、私はキーを前もって知る方法がないので、それは私を助けません。キーを前面に出すために、私は例で照会して、そうでなければ同一で既存のエッジのキーを見つける必要があります。それは私のパフォーマンスを殺していない限り、それは合理的だと思うが、私はどのように等価なエッジがまだ存在しない場合はエッジを挿入するように条件付きでクエリを構築するAQLではわからないが、ある。これどうやってするの?

  2. データがどちらのコレクションにも追加されるたびに、これを実行する必要があります。私はコレクション全体に参加しようとしないように、これを最新のデータでのみ実行する方法が必要です。新しく挿入されたレコードだけに参加できるAQLを書くにはどうすればいいですか?彼らはArangoimpで追加されているので、どの順番でそれらが更新されるかは保証されていないので、ノードを作成するのと同時にエッジを作成することはできません。新しいデータだけにどのように参加できますか?私は、レコードが追加されるたびに55k秒を費やしたくない。

    db._explain(<your query here>);

    た番組の出力を見ることによって見ることができるよう

+1

他のデータベースでも同じ問題を抱えてクエリを実行しましたが、データセットを再リンクするときにデータセットのサイズをどのように縮小しますか。私にとっては、 'fromCollection'コレクションと' toCollection'コレクションの両方に 'linked = false'のようなフィールドを追加する方法がありました。 –

+1

...新しい文書をいずれかのコレクションに挿入すると、常に 'linked'が' false'に設定されます。ドキュメントをリンクするときには、 'link'を' true'に設定します。それをスピードアップするために、 'linked'にインデックスを付けることもできます。すべてが値 'linked = false'を持つので、これはあなたが処理を最初に行うのがまだ遅くなりますが、処理速度が大幅に向上します。 –

+1

あなたのためにそれを行うためにFoxxアプリを書くことができました、私は他の人の質問のためのFoxxアプリケーションの例を文書化しました、利用可能です[ここ](http://stackoverflow.com/questions/39897954/arangodb-aql-recursive-graph-トラバーサル)をStackOverflowに追加します。素早く素早く、完璧なユースケースであることを記述しているような機能があるので、Foxxを学ぶには時間をかけておく価値があります。この関数はパラメータを必要とせず、実行するだけで 'linked = false'でそれらのレコードをスキャンします。 –

答えて

8

すべてのインデックスせずに書かれたとして、あなたのクエリを実行する場合、それは、ネストされた2回の完全なコレクションのスキャンを行う必要があります何かのように:

1 SingletonNode    1 * ROOT 
    2 EnumerateCollectionNode  3  - FOR fromItem IN fromCollection /* full collection scan */ 
    3 EnumerateCollectionNode  9  - FOR toItem IN toCollection /* full collection scan */ 
    4 CalculationNode    9   - LET #3 = (fromItem.`fromAttributeValue` == toItem.`toAttributeValue`) /* simple expression */ /* collections used: fromItem : fromCollection, toItem : toCollection */ 
    5 FilterNode     9   - FILTER #3 
    ... 

その場合は

db.toCollection.ensureIndex({"type":"hash", fields ["toAttributeValue"], unique:false})` 

fromCollectionに完全なテーブルコレクションのスキャンが1つあり、見つかった各アイテムには、toCollectionにハッシュ検索があり、はるかに高速です。すべてがバッチで行われるため、これはすでに状況を改善するはずです。 fromCollectionにおける最近挿入されたアイテムでのみ動作するように

1 SingletonNode    1 * ROOT 
    2 EnumerateCollectionNode  3  - FOR fromItem IN fromCollection /* full collection scan */ 
    8 IndexNode     3  - FOR toItem IN toCollection /* hash index scan */ 

は比較的簡単です:単純にすべての頂点にインポート時のタイムスタンプを追加し、使用します。

FOR fromItem IN fromCollection 
    FILTER fromItem.timeStamp > @lastRun 
    FOR toItem IN toCollection 
     FILTER fromItem.fromAttributeValue == toItem.toAttributeValue 
     INSERT { _from: fromItem._id, _to: toItem._id, otherAttributes: {}} INTO edgeCollection 

とのdb._explain()はこれを表示しますもちろんtimeStamp属性のスキップ指数をfromCollectionに設定してください。

これは、fromCollectionの新しい頂点を発見するのに美しく機能するはずです。 toCollection古い頂点にリンクされている新しい頂点を「見落とし」ます。fromCollectionです。

あなたは(fromCollectionfromAttributeValueにインデックスを忘れないでください)fromCollectionの役割とクエリでtoCollectionを交換し、頂点からのように、古い場合のみ、エッジに置くに思い出すことによって、これらを発見することができます。

FOR toItem IN toCollection 
    FILTER toItem.timeStamp > @lastRun 
    FOR fromItem IN fromCollection 
     FILTER fromItem.fromAttributeValue == toItem.toAttributeValue 
     FILTER fromItem.timeStamp <= @lastRun 
     INSERT { _from: fromItem._id, _to: toItem._id, otherAttributes: {}} INTO edgeCollection 

これらの2つは一緒にしてください。完全に機能している例hereを見つけてください。

+0

ありがとうMax!タイムスタンプを使用する際の1つの潜在的な問題は、様々なコレクションが異なるレートでインポートされることです。その結果、 'fromCollection'のデータは昨夜インポートされるかもしれませんが、' toCollection'のデータは1時間前にインポートされました。さらに、新しいデータは、以前にインポートされたデータに関連する必要があることがあります。これは 'fromItem'と' toItem'の両方が以前にインポートされていても1つだけではない場合に有効です。その後私のチームはエッジのための決定論的な重要なルールを思いつきました。重複は問題ではありません - 純粋にインサートのパフォーマンスです。 –

関連する問題