HashSet of Strings занимает слишком много памяти, предложения ...? - PullRequest
14 голосов
/ 12 июля 2010

В настоящее время я храню список слов (около 120 000) в HashSet с целью использования в качестве списка для проверки введенных слов на предмет правильности написания и просто возврата да или нет.

Мне было интересно, есть ли способ сделать это, который занимает меньше памяти. В настоящее время 120 000 слов составляют около 12 мг, а реальный файл, из которого читаются слова, составляет около 900 КБ.

Есть предложения?

Заранее спасибо

Ответы [ 8 ]

10 голосов
/ 12 июля 2010

Вы можете использовать префиксное дерево или три: http://en.wikipedia.org/wiki/Trie

6 голосов
/ 12 июля 2010

Проверьте фильтры Блума или хеширование кукушки. Фильтр Блума или хеширование кукушки?

Я не уверен, что это ответ на ваш вопрос, но стоит рассмотреть эти альтернативы.Фильтры Блума в основном используются для случаев, связанных с проверкой орфографии.

4 голосов
/ 12 июля 2010

HashSet, вероятно, не подходит для этого.Вместо этого используйте Trie .

2 голосов
/ 12 марта 2012

12 МБ для хранения 120000 слов - это около 100 байт на слово.Вероятно, по крайней мере 32 байта из этого являются строковыми издержками.Если слова в среднем состоят из 10 букв и они хранятся в виде 2-байтовых символов, это составляет еще 20 байтов.Затем есть ссылка на каждую строку в вашем HashSet, которая, вероятно, составляет еще 4 байта.Остальные 44 байта, вероятно, являются издержками на вход и индексирование HashSet, или чем-то, что я не рассмотрел выше.

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

Вы можете создать свою собственную реализацию в виде массива типа int с одним элементом для каждого слова.Каждый из этих элементов int будет разбит на подполя, которые содержат длину и смещение, указывающее на отдельный резервный массив типа char.Поместите оба из них в класс, который управляет ими, и который поддерживает публичные методы, позволяющие вам извлекать и / или преобразовывать ваши данные и отдельные символы с учетом строкового индекса и необязательного индекса символов, а также выполнять простой поиск в списке словкоторые необходимы для вашей функции проверки орфографии.

Если у вас есть не более 16777216 символов базовых строковых данных (например, 120 000 строк, умноженных на среднюю длину 10 символов = 1,2 миллиона символов), вы можете взять низкий-упорядочить 24 бита каждого целого и сохранить начальное смещение каждой строки в массиве вспомогательных данных char, взять 8 старших бит каждого целого и сохранить там размер соответствующей строки.

Ваши данные char будут содержать ваши прежние строки без каких-либо разделителей, полностью полагаясь на массив int, чтобы знать, где начинается и заканчивается каждая строка.

Используя вышеупомянутый подход, ваши 120000 слов (в среднем 10 буквкаждый) потребует• 2 400 000 байтов данных массива резервных копий и 480 000 байтов данных целочисленного индекса (120 000 x 4 байта), что в сумме составляет 2 880 000 байтов, что примерно на 75 процентов меньше по сравнению с нынешним объемом в 12 МБ, который вы указали выше.* Слова в массивах будут отсортированы по алфавиту, и ваш процесс поиска может быть простым двоичным поиском в массиве int (извлечение соответствующих слов из массива char для каждого теста), что должно быть очень эффективным.

Если ваши слова оказываются полностью данными ASCII, вы можете сэкономить дополнительно 1 200 000 байтов, сохранив вспомогательные данные как байты, а не как символы.

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

2 голосов
/ 03 сентября 2010

Это может быть немного поздно, но с помощью Google вы можете легко найти расследование DAWG и код C, который я недавно опубликовал.

http://www.pathcom.com/~vadco/dawg.html

TWL06 - 178 691 слово - подходитв 494 676 байт

Недостатком структуры сжатого общего узла является то, что она не работает как хэш-функция для слов в вашем списке.Другими словами, он сообщит вам, существует ли слово, но не вернет индекс связанных данных для слова, которое существует.

Если вы хотите, чтобы в процессоре была идеальная и полная функциональность хеширования- структура размера кэша, вам придется читать, понимать и изменять структуру данных, называемую ADTDAWG.Он будет немного больше, чем традиционная DAWG, но он быстрее и полезнее.

http://www.pathcom.com/~vadco/adtdawg.html

Всего наилучшего,

JohnPaul Adamovsky

1 голос
/ 12 июля 2010

Одним из способов сохранения памяти для сохранения памяти является использование radix tree . Это лучше, чем trie , так как префиксы не сохраняются избыточно.

Поскольку ваш словарь исправлен, другой способ - создать для него идеальную хеш-функцию. Вашему хэш-набору не нужны сегменты (и связанные с ними издержки), поскольку не может быть коллизий. Для этого можно использовать любую реализацию хеш-таблицы / хеш-набора, которая использует открытую адресацию (например, ImmutableSet ) из коллекции Google.

0 голосов
/ 03 августа 2010

Вы также можете попробовать Radix Tree ( Wiki , Реализация ). Это что-то вроде trie , но более эффективное использование памяти.1009 *

0 голосов
/ 12 июля 2010

Проблема заключается в том, что хранить такое огромное количество слов в HashSet по причинам, связанным с проверкой орфографии, не очень хорошая идея:

Вы можете либо использовать проверку орфографии (пример: http://softcorporation.com/products/spellcheck/), либо вы можете создать «автозаполнение» с помощью дерева префиксов (описание: http://en.wikipedia.org/wiki/Trie).

В этом проекте нет способа уменьшить использование памяти.

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