Должен ли я использовать «HashSet» или «TreeSet» для очень большого набора данных?

У меня есть требование хранить от 2 до 15 миллионов учетных записей (которые представляют собой String длины 15) в структуре данных для целей поиска и проверки уникальности. Первоначально я планировал хранить их в HashSet, но я сомневаюсь, что скорость поиска будет медленной из-за коллизий хэшей и в конечном итоге будет медленнее, чем TreeMap (с использованием двоичного поиска).

Нет требований к сортировке данных. Я использую Java 7. У меня есть система 64G с 48G, выделенными для этого приложения.

Этот вопрос не дублирует тест производительности HashSet и TreeSet, потому что этот вопрос касается производительности добавления элементов в a Set, и этот вопрос касается производительности проверки существующего Set на наличие повторяющихся значений.


person Mohan    schedule 04.08.2015    source источник
comment
также см. это   -  person Ankur Singhal    schedule 04.08.2015
comment
Привет, Анкуар, спасибо. Тест производительности в ссылке основан на 500 000 целых чисел в уже отсортированном порядке. У меня 10 миллионов строк, и я хотел понять возможность столкновения хешей. Во второй ссылке есть подсказка, которая была ужасной. Я постараюсь отписаться о своих наблюдениях.   -  person Mohan    schedule 04.08.2015
comment
Поиск предназначен для проверки наличия определенной строки в наборе строк. Это автономная Java-программа, и она не может позволить себе использовать что-то вроде Redis для хранения данных.   -  person Mohan    schedule 04.08.2015


Ответы (2)


Если у вас есть 48 ГБ выделенной памяти для ваших 2-15 миллионов записей, лучше всего использовать HashMap<Key, Record>, где ваш ключ — Integer или String в зависимости от ваших требований.

С коллизиями хэшей все будет в порядке, если вы предоставите достаточно памяти для Map и имеете соответствующий коэффициент загрузки.

Я рекомендую использовать следующий конструктор: new HashMap<>(13_000_000); (на 30% больше ожидаемого количества записей, которое будет автоматически расширено реализацией HashMap до 2^24 ячеек). Сообщите своему приложению, что этот Map будет очень большим с самого начала, поэтому ему не нужно автоматически увеличиваться по мере его заполнения.

HashMap использует время доступа O(1) для своих членов, тогда как TreeMap использует время поиска O(log n), но может быть более эффективным с памятью и не нуждается в умной функции хеширования. Однако, если вы используете ключи String или Integer, вам не нужно беспокоиться о разработке хэш-функции, и поиск с постоянным временем будет огромным улучшением. Кроме того, еще одним преимуществом TreeMap/TreeSet является отсортированный порядок, который, как вы заявили, вас не волнует; используйте HashMap.

Если единственной целью списка является проверка уникальных номеров счетов, то все, что я сказал выше, по-прежнему верно, но, как вы указали в своем вопросе, вы должны использовать HashSet<String>, а не HashMap . Рекомендации по производительности и аргумент конструктора по-прежнему применимы.

Дополнительная литература: тест производительности HashSet и TreeSet

person durron597    schedule 04.08.2015
comment
Большое тебе спасибо. В случае динамически растущего набора данных, где я не знаю точного количества элементов, могу ли я узнать, что было бы лучше. Набор данных может содержать от 2 миллионов до 15 миллионов (точный размер неизвестен) - person Mohan; 04.08.2015
comment
@Mohan Нет никакой разницы, если у вас так много памяти. Если ваша верхняя граница настолько мала по сравнению с вашим объемом памяти, просто сделайте максимальное разумное HashMap - 2 ^ 24 бита - и все будет в порядке. - person durron597; 04.08.2015

Когда мы попытались сохранить 50 миллионов записей в HashMap с правильными параметрами инициализации, вставка стала тормозить, особенно после 35 миллионов записей. Переход на TreeMap дал постоянную производительность вставки и извлечения.

Наблюдение: TreeMap даст лучшую производительность, чем HashMap для большого набора входных данных. Для меньшего набора, конечно, HashMap даст лучшую производительность.

person Mohan    schedule 17.11.2015
comment
Вы не спрашивали о 50 миллионах записей, вы спрашивали о 15 миллионах записей. В какой-то момент вам нужно подумать о вашей хеш-функции и вероятности коллизий, если вы используете ключ String. Реализация по умолчанию хороша для большинства целей, но может не подойти для 50 миллионов строк. - person durron597; 19.05.2016