Java: оптимизированные альтернативы хранилищ больших объемов - PullRequest
0 голосов
/ 12 октября 2019

Я работаю над веб-сканером / пауком, и мне нужен какой-то способ эффективного массового хранения строк в качестве ссылки для (1) уже сохраненных сайтов и (2) очереди для моего сканера. Эти структуры хранения данных должны быть в состоянии хранить намного больше миллионов строковых значений. Я начну с исследования, которое я исследовал, и того, что я сделал соответственно.

Первый метод, который я попробовал, был связан с этим потоком

Java: оптимизировать хэш-сет для большихобнаружение дублирования в масштабе

В этой теме OP рассказывает об оптимизации HashSet и получил много хороших отзывов и предупреждений. HashSet был очень дорогим в использовании и вызывал очень быстрый сбой моей программы. В ответах были предложены альтернативы, такие как Trove, однако с тех пор проект был прекращен, и я считаю, что есть более лучшие альтернативы.

Второй метод, который я попробовал, состоял в том, чтобы создать очередь с использованием MongoDB. Я явно создал коллекцию для очереди, в которой следовал FIFO, так как Mongo использует блокировки, поэтому она должна быть поточно-ориентированной. И из того, что я мог сказать, это работало очень хорошо. Мой сканер работал очень хорошо и в среднем занимал очень мало памяти (12 ~ 42 МБ). Однако этот метод вскоре оказался очень плохим, так как MongoDB имеет скорость поиска o (n). Создание итератора, который проверяет две коллекции (коллекцию веб-сайтов и коллекцию очередей) для каждого веб-сайта, подлежащего кэшированию, оказалось очень вредным.

Следуя этой теме

Стратегии быстрого поиска миллиардов небольших документов в MongoDB

Это действительно улучшило поискКачество немного, но это было мягкое возмещение. Ниже приведен простой псевдокод моего веб-сканера.

while(true){
    parse();
}

public void parse(){
    String next = // next url in queue to be parsed
    Document document = // get HTML dom from next url

    // store document inside of site storage (mongo collection)
    // grab links from document

    for( all links found ) {
        if(next doesn't exist in website collection and next isn't already in queue){
            add to queue 
        }
    }

}

Проверка "next не существует в коллекции веб-сайтов, а next еще не находится в очереди", мне нужно создать итератор или использоватьmongo.collection.find (). limit (1) (который также является итератором, за кулисами), чтобы проверить, существует ли следующий элемент внутри текущих сохраненных веб-сайтов или очереди. Итак, как вы можете видеть, по мере роста двух коллекций, в настоящее время насчитывающих более 100 000 записей в обеих, процессор может постоянно и медленно проверять обе коллекции.

Что возвращает меня к моему первомуметод, который удерживает потенциально до миллиардов URL-адресов в памяти для быстрого поиска дубликатов в обоих хранилищах. Большинство вещей, которые я прочитал, были очень полезны, но устарели, и мне было интересно, что вы, ребята, считаете лучшим способом для этого?

1 Ответ

0 голосов
/ 12 октября 2019

содержит потенциально до миллиардов URL-адресов в памяти

Это, безусловно, то, что вам не нужно и не следует делать.

Мне нужно создатьитератор

Это, безусловно, то, что вы не должны делать (если только итератор работает только с небольшой частью ваших данных).


далее не существуетв коллекции сайтов, а следующий еще не в очереди

Подумайте о представлении данных. Для поиска списки слишком медленные, поэтому вам нужен индексированный поиск. Что-то вроде HashMap или TreeMap, но на диске.

Я почти ничего не знаю о MongoDB, но каждая база данных, достойная своего имени, может это сделать. Я думаю, это работает уже с вашей коллекцией , просто проблема является проблемой. Очередь сложнее, так как вам нужен как быстрый поиск, так и очередь.

Эту проблему можно легко устранить, поместив каждый новый элемент в очередь и . collection , так что вам нужно только проверить коллекцию на наличие дубликатов (что IIUYC вы можете сделать довольно быстро). Очевидно, вам нужен маркер, чтобы различать элементы, которые еще не извлечены.


Следующая оптимизация будет хранить в памяти кэш нескольких недавно использованных элементов, чтобы можно было исключить некоторые повторяющиеся запросы к БД. Держу пари, что Bloom Filter тоже может помочь.


Вы также можете использовать реальное Map на диске: https://github.com/OpenHFT/Chronicle-Map

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...