Низкоуровневый столбчатый механизм хранения с Java API
Не могли бы вы предложить низкоуровневый столбчатый механизм хранения, который можно интегрировать в Java-приложение?
Причина: нам нужен столбчатый механизм хранения с Java API, чтобы интегрировать его в наше приложение для обработки данных.
Справочная информация: необработанные данные поступают из различных файлов CSV/TSV/WtfSV размером до 10 ГБ (в большинстве случаев значительно меньше). Приложение имеет предопределенный набор настраиваемых операций для очистки / преобразования / проверки данных (аналогично OpenRefine || DataWrangler || DataCleaner)
Проблема: сейчас мы используем H2 MVStore со значениями Object[] в виде строк, очевидно, он хранится как одна запись, поэтому вся строка десериализуется каждый раз, когда нам нужно обработать только один столбец.
Требования:
- Добавление / удаление столбца в любое время
- Основные классы значений Java (String, Numbers, Date), поддерживаемые из коробки
- Операция Get by index / Итерация, начиная с
- Файловое хранилище (по соображениям производительности)
- Было бы хорошо иметь возможность управления версиями данных в столбце (или даже в строке столбца).
Пример API, который нам нужен:
DataSet dataSet = Storage.dataSet('SomeName').withFilePath('C:\data\somename.dat').open(); //Open or create if not exists
//class DataSet implements List<Column>
//class Column implements List<T>
Column<String> col1 = dataSet.column('Col1').withType(String.class) //Column automatically created if not exists (only after user try to add data)
Column<Integer> col2 = dataSet.column('Col2').withType(Integer.class)
//Load data into column
for(String s : someStringList){
long idx = col1.add(s)
}
//Low priority one
Column col3 = dataSet.column('Col3').withCustomMapper(SomeClass.class,
new Mapper {
//byte[] can be InputStream, DataInputStream, etc... it does not matter
public SomeClass read(byte[] data){ /*some logic*/}
public byte[] write(SomeClass data){ /*some logic*/}
})
//Add entire row. Typechecking at runtime would be ok
long idx = dataSet.addRow(["123", 321, new SomeClass()]);
//Get by index
SomeClass foo = dataSet.column("Col1", SomeClass.class).get(idx)
//Iterator from index
Iterator<String> it = col1.iterator(startIndex)
/*
Iterator with parallel prefetching
This iterator dynamically adjusts read-ahead buffer in a way
that provides max performance for single threaded iterator,
eg there is no need to run multiple deserializing threads
if iterator itself is slow.
*/
PrefetchingIterator<DataRow> it3 = dataSet.iterator(startIndex).withMaxPerformanceParallelPrefetcher()
//Not required function, but it would be good if it is exists:
dataSet.createComputedColumn('ComputedCol', new Function<SomeOtherClass> {
SomeOtherClass apply(Long idx){
new SomeOtherClass(col1.get(index) + col2.get(index).toString())
}
}, isMaterialized) //isMaterialized flag enables storing calculated values for caching purposes
AFAIK, есть несколько полноценных решений BigData, таких как Apache Spark/Flink, которые поддерживают некоторые из перечисленных функций внутри или даже чистые механизмы хранения, такие как Apache ORC и Apache Parquet, но мне не удалось найти нужные API. Если какое-либо из этих решений отвечает нашим потребностям, дайте мне ссылку на соответствующий API или пример страницы.