2016-12-13 13 views
0

У меня есть много больших 1-D HDF5 наборов данных со следующими свойствами:Переход от HDF5 к PostgreSQL

  • инициализации размер = (5201,),
  • maxshape = (6000000,),
  • DTYPE = 'float32'
  • кусками = (10000,)
  • сжатия = "GZIP"
  • пример Путь: файл [ "Группа"] [ "1"] [ "Группа1"] [ "2"] [» Dataset "]

Я хочу, чтобы переместить их в PostgreSQL, я съезжались со структурой базы данных и вставки данных, но каждый наполнении занимает ~ 650 секунд 72,4mb файла hdf5, может кто-то дать мне советы/рекомендации, как можно улучшить представление?

Что я сейчас:

def fill_database(self, dog): 
    if isinstance(dog, h5py.Dataset): 
     name = dog.name.split('/') 
     table_name = '{}_{}'.format(name[3], name[5]) 
     data = dog.value.astype(int).tolist() 
     self.cur.execute('CREATE TABLE IF NOT EXISTS {} (cur_id INT PRIMARY KEY , data INT[]);'.format(table_name)) 
     self.cur.execute('INSERT INTO {} VALUES (%s, %s)'.format(table_name), (name[2], data)) 

     if isinstance(dog, h5py.Group): 
      for k, v in dict(dog).items(): 
       self.fill_database(v) 

Что я пробовал:

import psycopg2 
import h5py 
from itertools import islice 


with h5py.File('full_db.hdf5') as hdf5file: 
    with psycopg2.connect(database='hdf5', user='postgres', password='pass', port=5432) as conn: 
     cur = conn.cursor() 
     cur.execute('drop table if EXISTS mytable;') 
     cur.execute('create table mytable (data INT[]);') 
     chunksize = 10000 
     t = iter(hdf5file["Group"]["1"]["Group1"]["2"]["Dataset"][:].astype(int)) 
     rows = islice(t, chunksize) 
     while rows: 
      statement = "INSERT INTO mytable(data) VALUES {}".format(rows) # I stuck here 
      cur.execute(statement) 
      rows = islice(t, chunksize) 
     conn.commit() 

Кроме того, я пытался сделать что-то с LIMIT в PostgreSQL и многими другими способами, но я не был успешным.

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

ответ

0

После почти двух недель я думаю, что могу ответить на мой собственный вопрос. В поисках ответа я наткнулся в Интернете на этой странице https://github.com/psycopg/psycopg2/issues/179 Также после прочтения документации я понял, что копирование из файла работает еще быстрее, и я попытался использовать модуль StringIO. И вот что я получаю:

import h5py 
import psycopg2 
import time 
from io import StringIO 

conn = psycopg2.connect(database='hdf5', user='postgres', password=' ') 
cur = conn.cursor() 

file = h5py.File('db.hdf5', 'r') 
data_set = file['path/to/large/data_set'].value.astype(int).tolist() 

cur.execute('DROP TABLE IF EXISTS table_test;') 
cur.execute('CREATE TABLE table_test (data INTEGER[]);') 

# ORIGINAL 
start = time.time() 
cur.execute('INSERT INTO table_test VALUES (%s);', (data_set,)) 
print('Original: {} sec'.format(round(time.time() - start, 2))) 

# STRING FORMAT 
start = time.time() 
data_str = ','.join(map(str, data_set)).replace('[', '{').replace(']', '}') 
cur.execute('INSERT INTO table_test VALUES (ARRAY[{}]);'.format(data_str)) 
print('String format: {} sec'.format(round(time.time() - start, 2))) 

# STRING IO COPY 
start = time.time() 
data_str = ','.join(map(str, data_set)).replace('[', '{').replace(']', '}') 
data_io = StringIO('{{{}}}'.format(data_str)) 
cur.copy_from(data_io, 'table_test') 
print('String IO: {} sec'.format(round(time.time() - start, 2))) 

conn.commit() 

Который дает мне следующий результат с набором данных с формой (1200201,):

Original: 1.27 sec 
String format: 0.58 sec 
String IO: 0.3 sec