Подтвердить что ты не робот

Как я могу анализировать ~ 13 ГБ данных?

У меня есть ~ 300 текстовых файлов, содержащих данные о трекерах, торрентах и ​​сверстниках. Каждый файл организован следующим образом:

tracker.txt

time torrent
    time peer
    time peer
    ...
time torrent
...

У меня есть несколько файлов на трекер, и большая часть информации повторяется (такая же информация, разное время).

Я бы хотел проанализировать, что у меня есть, и сообщить статистику о таких вещах, как

  • Сколько торрентов на каждом трекере
  • Сколько трекеров торренты указаны на
  • Сколько ровесников торрентов имеют
  • Сколько торрентов для сверстников имеет

Огромное количество данных затрудняет мне это. Вот что я пробовал.

MySQL

Я помещаю все в базу данных; одна таблица для типа сущности и таблицы для хранения отношений (например, этот торрент находится на этом трекере).

Добавление информации в базу данных было медленным (и у меня не было 13 ГБ, когда я это пробовал), но анализ отношений впоследствии был нехорошим. Для каждого мягко сложного запроса потребовалось более 24 часов (если вообще).

Пример запроса:

SELECT COUNT(DISTINCT torrent) 
    FROM TorrentAtPeer, Peer 
    WHERE TorrentAtPeer.peer = Peer.id 
    GROUP BY Peer.ip;

Я попытался поднять выделение памяти в моем файле my.cnf, но, похоже, это не помогло. Я использовал файл настроек my-innodb-heavy-4G.cnf.

EDIT: добавление данных таблицы

Вот что я использовал:

Peer         Torrent                  Tracker        
-----------  -----------------------  ------------------  
id (bigint)  id (bigint)              id (bigint)
ip* (int)    infohash* (varchar(40))  url (varchar(255))
port (int)

TorrentAtPeer      TorrentAtTracker
-----------------  ----------------
id (bigint)        id (bigint)
torrent* (bigint)  torrent* (bigint)
peer* (bigint)     tracker* (bigint)
time (int)         time (int)

*indexed field. Navicat reports them as being of normal type and Btree method.
id - Always the primary key

Нет внешних ключей. Я был уверен в своей способности использовать только идентификаторы, соответствующие существующим объектам, добавив, что проверка внешнего ключа выглядела как ненужная задержка. Это наивно?

Matlab

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

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

Java

Моя самая успешная попытка. Я нашел реализацию Patricia Tries, предоставленную людьми в Лимлеере. Используя это, я смог прочитать данные и подсчитать количество уникальных объектов, которые у меня были:

  • 13 трекеров
  • 1.7mil торренты
  • 32-мильные сверстники

Я все еще слишком усердно разбираюсь в частотах числа торрентов у сверстников. Я пытаюсь сделать это, создавая такие попытки:

Trie<String, Trie<String, Object>> peers = new Trie<String, Trie<String, Object>>(...);
for (String line : file) {
    if (containsTorrent(line)) {
        infohash = getInfohash(line);
    }
    else if (containsPeer(line)) {
        Trie<String, Object> torrents = peers.get(getPeer(line));
        torrents.put(infohash, null);
    }
}

Из того, что я смог сделать до сих пор, если я смогу получить этот peers trie built, то я могу легко узнать, сколько торрентов у каждого партнера. Я запустил все это вчера, и когда я вернулся, я заметил, что файл журнала не записывается, я ^Z приложение и time сообщили следующее:

real 565m41.479s
user 0m0.001s
sys  0m0.019s

Это не выглядит правильным, если пользователь и sys будут настолько низкими? Я должен упомянуть, что я также увеличил размер кучи JVM до 7 ГБ (макс и начальный), без этого я довольно быстро получаю ошибку из памяти.

Я не возражаю ждать несколько часов/дней, но похоже, что вещь перестает останавливаться примерно через 10 часов.

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

4b9b3361

Ответ 1

Я бы дал MySQL другую попытку, но с другой схемой:

  • здесь не используются id-столбцы.
  • используйте натуральные первичные ключи здесь:

    Peer: ip, порт
    Торрент: infohash
    Трекер: URL-адрес TorrentPeer: peer_ip, torrent_infohash, peer_port, время
    TorrentTracker: tracker_url, torrent_infohash, время

  • использовать механизм innoDB для всех таблиц

Это имеет ряд преимуществ:

  • InnoDB использует кластерные индексы для первичного ключа. Это означает, что все данные могут быть получены непосредственно из индекса без дополнительного поиска, когда вы запрашиваете данные только из столбцов первичного ключа. Таким образом, таблицы InnoDB представляют собой несколько индексированных таблиц.
  • Меньший размер, так как вам не нужно хранить суррогатные ключи. → Скорость, потому что меньше IO для тех же результатов.
  • Теперь вы можете выполнять некоторые запросы без использования (дорогостоящих) объединений, потому что вы используете естественные первичные и внешние ключи. Например, таблица ссылок TorrentAtPeer непосредственно содержит peer ip как внешний ключ для таблицы одноранговых узлов. Если вам нужно запросить торренты, используемые одноранговыми узлами в подсети, вы можете сделать это без использования соединения, потому что все соответствующие данные находятся в таблице связывания.

Если вы хотите, чтобы количество торрентов за одноранговое соединение, и вы хотите, чтобы peer ip в результатах тоже, мы снова имеем преимущество при использовании естественных первичных/внешних ключей здесь.

С вашей схемой вы должны присоединиться, чтобы получить ip:

SELECT Peer.ip, COUNT(DISTINCT torrent) 
    FROM TorrentAtPeer, Peer 
    WHERE TorrentAtPeer.peer = Peer.id 
    GROUP BY Peer.ip;

С естественными первичными/внешними ключами:

SELECT peer_ip, COUNT(DISTINCT torrent) 
    FROM TorrentAtPeer 
    GROUP BY peer_ip;

ИЗМЕНИТЬ Ну, оригинальная размещенная схема не была реальной. Теперь таблица Peer имеет поле port. Я бы предложил использовать первичный ключ (ip, port) здесь и все равно оставить столбец id. Это также означает, что таблица ссылок должна иметь многоколоночные внешние ключи. Скорректированный ответ...

Ответ 2

Вы заявляете, что ваши запросы MySQL заняли слишком много времени. Обеспечили ли вы наличие надлежащих индексов для поддержки вашего запроса? В вашем примере это будет индекс для Peer.ip (или даже вложенный индекс (Peer.ip,Peer.id)) и индекс для TorrentAtPeer.peer.

Насколько я понимаю вас, результаты Java, у вас много данных, но не так много разных строк. Таким образом, вы могли бы сэкономить некоторое время, назначив уникальный номер каждому трекеру, торренту и сверстнику. Использование одной таблицы для каждого, с некоторым индексированным значением, содержащим строку и числовой первичный ключ в качестве идентификатора. Таким образом, все таблицы, относящиеся к этим объектам, будут иметь дело только с этими числами, что может сэкономить много места и сделать ваши операции намного быстрее.

Ответ 3

Если вы можете использовать С++, вы должны взглянуть на Boost flyweight.

Используя flyweight, вы можете написать свой код так, как если бы у вас были строки, но каждый экземпляр строки (ваше имя трекера и т.д.) использует только размер указателя.

Независимо от языка, вы должны преобразовать IP-адрес в int (посмотрите этот вопрос), чтобы сохранить еще немного памяти.

Ответ 4

У вас, скорее всего, есть проблема, которая может быть решена NOSQL и распределенными технологиями.

i) Я бы написал распределенную систему, используя Hadoop/HBase.

ii) Аренда нескольких десятков/сотен AWS машин, но только на несколько секунд (это будет стоить вам меньше, чем $0,50)

iii) Прибыль!!!