2017-05-06 18 views
0

私は2つのコレクションを持っています:単語とフレーズ 各単語文書にはフレーズIDの配列があります。また、各フレーズをアクティブまたは非アクティブにすることができます。

言葉:例えば文書の配列数を調べる


{ "単語" => "こんにちは"、フレーズ=> [1,2]} {
"単語" => "テーブル"、フレーズ=> [2]}

フレーズ:
{"id" => 1 "フレーズ" => "hello world!"、 "active" => 1}
{"id" => 2、 "phrase" => "hello、i既に新しいテーブルを購入しました "、"アクティブ "=> 0)

各単語のアクティブフレーズの数を取得する必要があります。

私はこのようにそれを行うPHPで


1.各単語のすべての単語
2.条件でアクティブなフレーズのカウントを取得する取得[「アクティブ」=> 1]

質問:どのようにすることができます1回のリクエストでアクティブなフレーズを含む単語が得られますか?私はMapReduceを使用しようとしましたが、アクティブなフレーズの数を得るために各単語をリクエストする必要があります。

UPD: 私のテストコレクションには、92 000フレーズと23000ワードがあります。

私はすでに、句の数とmongoのaggreagation関数を取得する各単語のphpループで両方のバリエーションをテストしました。

しかし、私はphrases_dataのために以下のコミットで集約パイプラインを変更しました。それは配列なので、$ matchを使用することはできません。 $ lookupの後に$ unwindを使用します。

[ '$unwind' => '$5'], 
    [ 
     '$lookup' => [ 
     'from' => 'phrases_926ee3bc9fa72b029e028ec90e282072ea0721d1', 
      'localField' => '5', 
      'foreignField' => '0', 
      'as' => 'phrases_data' 
     ] 
    ], 
    [ '$unwind' => '$phrases_data'], 
    [ '$match' => [ 'phrases_data.3' => 77] ], //phrases_data.3 => 77 it is similar to phrases_data.active => 1 
    [ '$group' => 
     [ 
      '_id' => ['word' => '$1', 'id' => '$0'], 
      'active_count' => [ '$sum' => 1] 
     ] 
    ], 
    [ '$match' => [ 'active_count' => ['$gt' => 0]] ], 
    [ '$sort' => 
     [ 
      'active_count' => -1 
     ] 
    ] 


問題は、$ groupコマンドは、処理時間の80%を取るということです。そして、それはPHPのループよりもはるかに遅いです。ここではテストコレクションのための私の結果です:
あなたはアグリゲーションパイプラインの上に使用することができます

1. Php loop (get words-> get phrases count for each word): 10 seconds 
2. Aggregation function : 20 seconds 
+0

あなたのmongoサーバのバージョンとphp mongoドライバのバージョンは何ですか? – Veeram

+0

Mongo 3.2。、php mongoドライバがv1と思われる、わからないよ –

答えて

0
db.words.aggregate([ 
    { "$unwind" : "$phrases"}, 
    { 
     "$lookup": { 
      "from": "phrases", 
      "localField": "phrases", 
      "foreignField": "id", 
      "as": "phrases_data" 
     } 
    }, 
    { "$match" : { "phrases_data.active" : 1} }, 
    { "$group" : { 
     "_id" : "$word", 
     "active_count" : { $sum : 1 } 
     } 
    } 
]); 

  1. 別の文書としての単語集documenからフレーズ配列をリラックス検索を行います(参加する)フレーズコレクションで巻き戻しフレーズを使用して
  2. フレーズをフィルタリングし、$ matchを使用してアクティブをチェックする
  3. 最後に$ sumを使用して単語とカウントでグループフレーズを設定する:1
+0

ありがとう!私は集約フレームワークと "$ unwind"のような機能について知っていますが、それは非常に遅くなる恐れがあります。しかし、変更のあるveriantsがない場合、私はそれを使用しようとします。 –

+0

単語コレクションからの主な参照は配列になっています。だから、解くのが最善の方法です。 –

0

3.4では、以下の集計パイプラインを使用できます。

$unwindアレイIDは3.3.4以降のバージョンでは必要ありません。

https://stackoverflow.com/a/36647133/2683814

以下のクエリは、アクティブな行をカウントする$filter + $size続いwordsphrasesでコレクションに参加します。

<?php 

    $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017"); 

    $pipeline = 
     [ 
      [ 
      '$lookup' => [ 
       'from' => 'phrases', 
       'localField' => 'phrases', 
       'foreignField' => 'id', 
       'as' => 'phrases' 
      ] 
      ], 
      [ 
      '$addFields' => 
      [ 
       'phrases' => 
       [ 
        '$size'=> [ 
         [ 
          '$filter' => [ 
          'input' => '$phrases', 
          'as' => 'phrase', 
          'cond' => [ 
           '$eq' => [ 
            '$$phrase.active', 1, 
            ] 
           ], 
          ], 
         ], 
        ], 
       ], 
       '_id' => 0 
      ], 
     ], 
    ]; 

    $command = new \MongoDB\Driver\Command([ 
     'aggregate' => 'words', 
     'pipeline' => $pipeline 
     ]); 

    $cursor = $manager->executeCommand('test', $command); 

    foreach($cursor as $key => $document) { 
     var_dump($document); 
    } 
?> 
+0

私はそれを使用することはできません、私はmongo 3.2を持っています –

関連する問題