Проблема: у меня есть существующие файлы netCDF4 (их около 5000), (обычно в форме 96x3712x3712) точки данных (float32). Это файлы с первым измерением времени (1 файл в день), вторым и третьим пространственными измерениями. В настоящее время создание среза по первому измерению (даже частичного) может занять много времени по следующим причинам:
- файлы netCDF разбиты на блоки размером 1x3712x3712. Нарезка по временному измерению в основном прочитает весь файл.
- цикл (даже в нескольких процессах) по всем файлам меньшего размера также займет много времени.
Моя цель:
- создавать ежемесячные файлы (около 2900x3712x3712) точек данных
- оптимизировать их для разрезания во времени (размер фрагментов 2900x1x1 или немного больше в пространственных измерениях)
Другие требования:
- файлы должны быть добавлены одной временной меткой (1x3712x3712), и этот процесс обновления должен занять менее 15 минут.
- запрос должен быть достаточно быстрым: полный срез менее чем за одну секунду (то есть 2900x1x1) ==> на самом деле не так много данных ...
- желательно, чтобы файлы были доступны для чтения несколькими процессами во время обновления.
- Обработка исторических данных (других 5000 ежедневных файлов) должна занять менее пары недель.
Я пробовал уже несколько подходов:
- объединение файлов netcdf и их повторное объединение ==> занимает слишком много памяти и слишком много времени ...
- запись их из pandas в файл hdf (с использованием pytables) ==> создает широкую таблицу с огромным индексом. Это, в конечном итоге, также займет слишком много времени для чтения и потребует разбиения набора данных по пространственным измерениям из-за ограничений метаданных.
- мой последний подход заключался в записи их в файл hdf5 с помощью h5py:
Вот код для создания одного ежемесячного файла:
import h5py
import pandas as pd
import numpy as np
def create_h5(fps):
timestamps=pd.date_range("20050101",periods=31*96,freq='15T') #Reference time period
output_fp = r'/data/test.h5'
try:
f = h5py.File(output_fp, 'a',libver='latest')
shape = 96*nodays, 3712, 3712
d = f.create_dataset('variable', shape=(1,3712,3712), maxshape=(None,3712,3712),dtype='f', compression='gzip', compression_opts=9,chunks=(1,29,29))
f.swmr_mode = True
for fp in fps:
try:
nc=Dataset(fp)
times = num2date(nc.variables['time'][:], nc.variables['time'].units)
indices=np.searchsorted(timestamps, times)
for j,time in enumerate(times):
logger.debug("File: {}, timestamp: {:%Y%m%d %H:%M}, pos: {}, new_pos: {}".format(os.path.basename(fp),time,j,indices[j]))
d.resize((indices[j]+1,shape[1],shape[2]))
d[indices[j]]=nc.variables['variable'][j:j+1]
f.flush()
finally:
nc.close()
finally:
f.close()
return output_fp
Я использую последнюю версию HDF5, чтобы иметь возможность SWMR. Аргумент fps - это список путей к файлам ежедневного netCDF4. Он создает файл (на ssd, но я вижу, что создание файла в основном связано с процессором) примерно за 2 часа, что приемлемо.
Я настроил сжатие, чтобы сохранить размер файла в определенных пределах. Я провел более ранние тесты без него и увидел, что создание без него немного быстрее, но нарезка занимает не так много времени со сжатием. H5py автоматически разбивает набор данных на блоки размером 1x116x116.
Теперь проблема: разрезание на NAS с настройкой RAID 6 занимает около 20 секунд, чтобы разрезать измерение времени, даже если оно находится в одном фрагменте ...
Я полагаю, что даже если он находится в одном фрагменте файла, поскольку я записал все значения в цикле, он должен быть каким-то образом фрагментирован (хотя не знаю, как этот процесс работает). Вот почему я попытался сделать h5repack, используя инструменты CML HDF5 в новый файл, с теми же фрагментами, но, надеюсь, переупорядочив значения, чтобы запрос мог читать значения в более последовательном порядке, но безуспешно. Несмотря на то, что для выполнения этого процесса потребовалось 6 часов, он не повлиял на скорость запроса.
Если я правильно делаю свои вычисления, чтение одного фрагмента (2976x32x32) занимает всего несколько МБ (11 МБ без сжатия, только немного больше, чем 1 МБ со сжатием, я думаю). Как это может длиться так долго? Что я делаю неправильно? Я был бы рад, если бы кто-нибудь пролил свет на то, что на самом деле происходит за кулисами ...