2015-08-30 2 views
2

Мне нужно найти ключевые слова в названии/описании/тегах и т. Д. Каждого документа и удалить их, если они найдены. Я новичок в Mongo, поэтому я следую аналогичному сценарию в существующей кодовой базе. Во-первых, получить MongoCursor и получить только поля мы будем проверять:Итерация над результатами Монго, не заканчивающаяся память

/** @var MongoCursor $products */ 
    $products = $collection->find(
     ['type' => ['$in' => ['PHONES', 'TABLETS']], 'supplier.is_awful' => ['$exists' => true]], 
     ['details.name' => true, 'details.description' => true] 
    ); 

Затем перебираем каждый документ, а затем проверить каждое из свойств для значений мы заинтересованы в:

/** @var \Doctrine\ODM\MongoDB\DocumentManager $manager */ 
$manager = new Manager(); 

foreach ($products as $product) { 
    // Find objectionable words in the content and remove these documents 
    foreach (["suckysucky's", "deuce", "a z z"] as $word) { 
     if (false !== strpos(mb_strtolower($product['details']['name']), $word) 
      || false !== strpos(mb_strtolower($product['details']['description']), $word)) { 
       $object = $manager->find(\App\Product::class, $product['_id']); 
       $manager->remove($object); 
     } 
    } 
} 
// Persist to DB 
$manager->flush(); 

проблема заключается в том, что база данных содержит сотни тысяч записей, и это выглядит как итерация по MongoCursor, использование памяти идет вверх и вверх, пока не закончится:

Now at (0) 20035632 
Now at (100) 24446048 
Now at (200) 32190312 
Now at (300) 36098208 
Now at (400) 42433656 
Now at (500) 45204376 
Now at (600) 50664808 
Now at (700) 54916888 
Now at (800) 59847312 
Now at (900) 65145808 
Now at (1000) 70764408 

Есть ли способ для итерации по MongoCursor без исчерпания памяти (я пытался отключить различные объекты в разных точках, но вам не повезло)? Или же это запрос, который можно запустить непосредственно в Монго? Я просмотрел документы, и я увидел некоторую надежда в $text, но похоже, что мне нужен индекс (я этого не делаю), и только один текстовый индекс для каждой коллекции.

+0

Вы когда-нибудь находили решение этого вопроса? Я также вижу ту же проблему, что и мой курсор, занимающий все больше и больше памяти, без очевидного способа ее остановить. – Boerema

+0

@Boerema, к сожалению, нет. Я просто увеличил memory_limit PHP в скрипте. Насколько я мог судить (прошло какое-то время, и это туманно), утечка реальна – charmeleon

ответ

0

Вам не нужно полнотекстовый индекс, чтобы найти подстроку: правильный путь с помощью regex, а затем возвращать только «_id» значение, что-то вроде:

$mongore = new MongoRegex("/suckysucky's|deuce|a z z/i") 
$products = $collection->find(
    ['type' => ['$in' => ['PHONES', 'TABLETS']], 
    'supplier.is_awful' => ['$exists' => true], 
    '$or': [['details.name' => $mongore], 
      ['details.description' => $mongore]]] 
    ['_id' => true] 
); 

Я не уверен, о точный синтаксис PHP, но ключ является включенным $ или фильтром с тем же регулярным выражением mongodb в двух полях.

+0

... конечно, вы затем будете обрабатывать результаты, чтобы удалить все _id из коллекции $ manager; оптимизация может быть удалена навалом, предоставив весь список $ id (или, по крайней мере, много из них, предел является обычным 16Gb BSON) с предложением «$ in», поэтому вы можете избавиться от большого количества базы данных в обе стороны. – dbra