lmdb неэффективно хранит данные? - PullRequest
1 голос
/ 14 июля 2020

Я ищу структуру файла данных, которая позволяет быстро читать случайные образцы данных для глубокого обучения, и сегодня экспериментировал с lmdb. Однако меня удивляет то, насколько неэффективным кажется хранение данных. У меня есть файл ASCII размером около 120 ГБ с последовательностями генов. Теперь я ожидал, что смогу уместить эти данные в базу данных lmdb примерно того же размера или, возможно, даже немного меньше, поскольку ASCII - очень неэффективный метод хранения. Однако то, что я вижу, похоже, предполагает, что мне нужно около 350 ГБ для хранения этих данных в файле lmdb, и я этого просто не понимаю. Я неправильно использую некоторые настройки, или что именно я здесь делаю не так?

import time
import lmdb
import pyarrow as pa

def dumps_pyarrow(obj):
    """
    Serialize an object.

    Returns:
        Implementation-dependent bytes-like object
    """
    return pa.serialize(obj).to_buffer()

t0 = time.time()
filepath = './../../Uniparc/uniparc_active/uniparc_active.fasta'
output_file = './../data/out_lmdb.fasta'
write_freq = 100000

start_line = 2
nprot = 0

db = lmdb.open(output_file, map_size=1e9, readonly=False,
               meminit=False, map_async=True)
txn = db.begin(write=True)
with open(filepath) as fp:
   line = fp.readline()
   cnt = 1
   protein = ''
   while line:
       if cnt >= start_line:
           if line[0] == '>': #Old protein finished, new protein starting on next line
               txn.put(u'{}'.format(nprot).encode('ascii'), dumps_pyarrow((protein)))
               nprot += 1
               if nprot % write_freq == 0:
                   t1 = time.time()
                   print("comitting... nprot={} ,time={:2.2f}".format(nprot,t1-t0))
                   txn.commit()
                   txn = db.begin(write=True)
                   line_checkpoint = cnt
               protein = ''
           else:
               protein += line.strip()
       line = fp.readline()
       cnt += 1


txn.commit()
keys = [u'{}'.format(k).encode('ascii') for k in range(nprot + 1)]
with db.begin(write=True) as txn:
    txn.put(b'__keys__', dumps_pyarrow(keys))
    txn.put(b'__len__', dumps_pyarrow(len(keys)))

print("Flushing database ...")
db.sync()
db.close()

t2 = time.time()
print("All done, time taken {:2.2f}s".format(t2-t0))

Изменить: некоторая дополнительная информация о данных:

В файле размером 120 ГБ данные структурированы вот так (здесь я показываю первые 2 белка):

>UPI00001E0F7B status=inactive
YPRSRSQQQGHHNAAQQAHHPYQLQHSASTVSHHPHAHGPPSQGGPGGPGPPHGGHPHHP
HHGGAGSGGGSGPGSHGGQPHHQKPRRTASQRIRAATAARKLHFVFDPAGRLCYYWSMVV
SMAFLYNFWVIIYRFAFQEINRRTIAIWFCLDYLSDFLYLIDILFHFRTGYLEDGVLQTD
ALKLRTHYMNSTIFYIDCLCLLPLDFLYLSIGFNSILRSFRLVKIYRFWAFMDRTERHTN
YPNLFRSTALIHYLLVIFHWNGCLYHIIHKNNGFGSRNWVYHDSESADVVKQYLQSYYWC
TLALTTIGDLPKPRSKGEYVFVILQLLFGLMLFATVLGHVANIVTSVSAARKEFQGESNL
RRQWVKVVWSAPASG
>UPI00001E0FBF status=active
MWRAQPSLWIWWIFLILVPSIRAVYEDYRLPRSVEPLHYNLRILTHLNSTDQRFEGSVTI
DLLARETTKNITLHAAYLKIDENRTSVVSGQEKFGVNRIEVNEVHNFYILHLGRELVKDQ
IYKLEMHFKAGLNDSQSGYYKSNYTDIVTKEVHHLAVTQFSPTFARQAFPCFDEPSWKAT
FNITLGYHKKYMGLSGMPVLRCQDHDSLTNYVWCDHDTLLRTSTYLVAFAVHDLENAATE
ESKTSNRVIFRNWMQPKLLGQEMISMEIAPKLLSFYENLFQINFPLAKVDQLTVPTHRFT
AMENWGLVTYNEERLPQNQGDYPQKQKDSTAFTVAHEYAHQWFGNLVTMNWWNDLWLKEG
PSTYFGYLALDSLQPEWRRGERFISRDLANFFSKDSNATVPAISKDVKNPAEVLGQFTEY
VYEKGSLTIRMLHKLVGEEAFFHGIRSFLERFSFGNVAQADLWNSLQMAALKNQVISSDF
NLSRAMDSWTLQGGYPLVTLIRNYKTGEVTLNQSRFFQEHGIEKASSCWWVPLRFVRQNL
PDFNQTTPQFWLECPLNTKVLKLPDHLSTDEWVILNPQVATIFRVNYDEHNWRLIIESLR
NDPNSGGIHKLNKAQLLDDLMALAAVRLHKYDKAFDLLEYLKKEQDFLPWQRAIGILNRL
GALLNVAEANKFKNYMQKLLLPLYNRFPKLSGIREAKPAIKDIPFAHFAYSQACRYHVAD
CTDQAKILAITHRTEGQLELPSDFQKVAYCSLLDEGGDAEFLEVFGLFQNSTNGSQRRIL
ASALGCVRNFGNFEQFLNYTLESDEKLLGDCYMLAVKSALNREPLVSPTANYIISHAKKL
GEKFKKKELTGLLLSLAQNLRSTEEIDRLKAQLEDLKEFEEPLKKALYQGKMNQKWQKDC
SSDFIEAIEKHL

Когда я сохраняю данные в базе данных, я объединяю все строки, составляющие каждый белок, и сохраняю их как одну точку данных. Я игнорирую заголовок (строка, начинающаяся с>). Причина, по которой я считаю, что данные должны быть более сжатыми при хранении в базе данных, заключается в том, что я ожидаю, что они будут храниться в некоторой двоичной форме, которая, как я ожидал, будет более сжатой, хотя я признаю, что не знаю, так ли это. как это на самом деле будет работать (для сравнения, данные составляют всего 70 ГБ в сжатом / заархивированном виде). Я был бы не против, если бы данные занимали такое же количество места в формате lmdb, но я не понимаю, почему они должны занимать почти в 3 раза больше места, чем в формате ASCII.

...