Создание карты из большого файла
У меня есть очень большой файл (10^8 строк) с количеством событий следующим образом,
A 10
B 11
C 23
A 11
Мне нужно накапливать количество для каждого события, чтобы моя карта содержала
A 21
B 11
C 23
Мой текущий подход:
Читайте линии, ведите карту и обновляйте счетчики на карте следующим образом.
updateCount(Map<String, Long> countMap, String key,
Long c) {
if (countMap.containsKey(key)) {
Long val = countMap.get(key);
countMap.put(key, val + c);
} else {
countMap.put(key, c);
}
}
В настоящее время это самая медленная часть кода (занимает около 25 мс). Обратите внимание, что карта основана на MapDB, но я сомневаюсь, что обновления происходят медленно из-за этого (не так ли?)
Это конфиги mapdb для карты,
DBMaker.newFileDB(dbFile).freeSpaceReclaimQ(3)
.mmapFileEnablePartial()
.transactionDisable()
.cacheLRUEnable()
.closeOnJvmShutdown();
Есть ли способы ускорить это?
РЕДАКТИРОВАТЬ:
Количество уникальных ключей имеет порядок страниц в википедии. Данные на самом деле данные трафика страницы отсюда.
3 ответа
В качестве отправной точки я бы предложил подумать о:
- Каков критерий, по которому вы говорите, что 25 мс - это на самом деле неоправданное количество времени для объема задействованных данных и для реализации общей карты? если вы подсчитаете это, это может помочь вам разобраться, если что-то не так.
- Сколько времени тратится на повторное хэширование карты по сравнению с другими операциями (например, вычисление хеш-кодов для каждого пута)?
- Из чего состоят ваши "события", как вы их называете? Сколько уникальных событий - и, следовательно, уникальных ключей - есть? Как генерируются ключи к карте, и есть ли более эффективный способ сделать это? (Например, в стандартной хэш-карте вы создаете дополнительные объекты для каждой ассоциации и фактически сохраняете ключевые объекты, увеличивая объем памяти.)
- В зависимости от ответов на предыдущий, вы можете самостоятельно развернуть более эффективную структуру карты (см. Этот пример, который вы можете адаптировать). По сути, вам нужно конкретно посмотреть, на что уходит время (например, вычисление хеш-кода на один пут / стоимость перефразирования) и попытаться оптимизировать эту часть.
Вы можете попробовать
class Counter {
long count;
}
void updateCount(Map<String, Counter> countMap, String key, int c) {
Counter counter = countMap.get(key);
if (counter == null) {
counter = new Counter();
countMap.put(key, counter);
counter.count = c;
} else {
counter.count += c;
}
}
Это не создает много длинных оболочек, а просто распределяет счетчики по количеству ключей.
Примечание: не создавайте Лонга. Выше я сделал c
Int, чтобы не контролировать долго /Long.
Если вы используете TreeMap, есть варианты настройки производительности, такие как
- Количество записей в каждом узле.
- Вы также можете использовать специальный сериализатор ключей и значений, который ускорит сериализацию и десерилизацию.
- Вы можете использовать режим насоса, чтобы построить дерево, которое очень очень быстро. Но одно предостережение в том, что это полезно, когда вы строите новую карту с нуля. Вы можете найти полный пример здесь
https://github.com/jankotek/MapDB/blob/master/src/test/java/examples/Huge_Insert.java