Эффективное постоянное хранилище для простого идентификатора в таблицу значений отображается для Java - PullRequest
5 голосов
/ 12 марта 2009

Мне нужно хранить некоторые данные, которые следуют простому шаблону отображения «идентификатора» в полную таблицу (с несколькими строками) из нескольких столбцов (то есть некоторых целочисленных значений [u, v, w]). Размер одной из этих таблиц составит пару КБ. По сути, мне нужно хранить постоянный кеш некоторых промежуточных результатов.

Это может быть легко реализовано как простой sql, но есть пара проблем, а именно мне нужно максимально сжать размер этой структуры на диске. (из-за количества значений, которые я храню) Кроме того, это не транзакция, мне просто нужно написать один раз и просто прочитать содержимое всей таблицы, поэтому реляционная БД на самом деле не очень подходит.

Мне было интересно, есть ли у кого-нибудь хорошие предложения? По некоторым причинам я не могу придумать что-то приличное. Особенно было бы неплохо что-то с API в Java.

Ответы [ 7 ]

3 голосов
/ 12 марта 2009

Звучит как работа для .... new ObjectOutputStream(new FileOutputStream(STORAGE_DIR + "/" + key + ".dat"); !!

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

В приличной файловой системе записи могут быть сделаны атомарными (путем записи во временный файл и затем переименованием файла); скорость чтения / записи измеряется в 10 с Мбит / с; поиск можно сделать очень эффективным, создав простое дерево каталогов, подобное STORAGE_DIR + "/" + key.substring(0,2) + "/" + key.substring(0,4) + "/" + key, которое должно быть эффективным с миллионами записей и даже более эффективным, если ваша файловая система использует индексированные каталоги; и, наконец, тривиально реализовать кэш-память LRU на основе памяти для еще более быстрого поиска.

Относительно сжатия - вы можете использовать обыкновенное сжатие Джакарты, чтобы повлиять на сжатие gzip или даже bzip2 на данные перед их сохранением. Но это проблема оптимизации, и в зависимости от вашего приложения и доступного дискового пространства вам может быть выгоднее инвестировать циклы ЦП в другом месте.

Вот пример реализации, который я сделал: http://geek.co.il/articles/geek-storage.zip. Он использует простой интерфейс (который далеко не чистый - это просто демонстрация концепции), который предлагает методы для хранения и извлечения объектов из кэша. с установленным максимальным размером. Промах кэша передается пользовательской реализации для обработки, и кэш будет периодически проверять, не превышает ли он требования к хранилищу, и удаляет старые данные.

Я также включил реализацию с поддержкой MySQL для завершения и бенчмарк для сравнения реализаций на основе дисков и MySQL. На моей домашней машине (старый Athlon 64) тест производительности диска показал результаты, которые в два раза быстрее, чем реализация MySQL в прилагаемом тесте (9,01 секунды против 18,17 секунды). Несмотря на то, что реализация БД, возможно, может быть слегка улучшена, я считаю, что она достаточно хорошо демонстрирует проблему.

Не стесняйтесь использовать это по своему усмотрению.

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

Я бы использовал EHCache , он используется Hibernate и другими библиотеками Java EE, и действительно прост и эффективен:

Чтобы добавить таблицу:

List<List<Integer>> myTable = new(...)
cache.put(new Element("myId", myTable));

Читать:

List<List<Integer>> myTable = (List<List<Integer>>) cache.get("myId").getObjectValue();
1 голос
/ 12 марта 2009

Apache Derby может подойти, если вы хотите что-то встроить (не отдельный сервер).

Есть список других опций в Облегченные базы данных в Java

1 голос
/ 12 марта 2009

Вы смотрели на Беркли DB ? Звучит так, будто это может соответствовать всем требованиям.


Edit:

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

0 голосов
/ 04 апреля 2009

Если у вас есть пара КБ, я не понимаю, почему вам нужно «максимально сжать размер этой структуры на диске». Учитывая, что 181 МБ дискового пространства стоит 1 цент, я бы предложил что-нибудь меньше этого не стоит тратить слишком много времени на беспокойство.

Однако, чтобы ответить на ваш вопрос, вы можете сжать файл при его записи. Как и ObjectOutputStream, вы можете использовать XMLExcoder для сериализации вашей карты. Это будет более компактно, чем просто использование ObjectOutputStream, и если вы распакуете файл, вы сможете читать или редактировать данные.

XMLEncoder xe = new XMLEncoder(
    new GZIPOutputStream(
        new FileOutputStream(filename+".xml.gz")));
xe.writeObject(map);
xe.close();
0 голосов
/ 04 апреля 2009

Вы можете использовать JOAFIP http://joafip.sourceforge.net/ Это позволяет вам поместить всю вашу модель данных в файл, и вы можете получить к ней доступ, обновить ее, не перезагружая все в памяти.

0 голосов
/ 12 марта 2009

Кажется, что Key => Базы данных значений - это то, что вы ищете.

Может быть, SuperCSV - это лучший фреймворк для вас!

Если вы не хотите использовать реляционную базу данных, вы можете использовать JAXB для хранения ваших объектов в виде файлов XML!

Существует также способ с другими библиотеками, такими как XStream

Если вы предпочитаете XML, используйте JAXB или XStream. В противном случае вы должны взглянуть на библиотеки CSV, такие как SuperCSV. Люди, которые могут работать с сериализованными файлами Java, могут использовать механизм персистентности по умолчанию, как сказал Гусс. Прямое сохранение Java может быть самым быстрым способом.

...