Opções para armazenamento de arquivo simples binário somente leitura usando Python
-
20-09-2019 - |
Pergunta
Recebi a tarefa de configurar um banco de dados SKU de arquivo simples para uso em dispositivos incorporados com armazenamento e velocidade de processador limitados.
Basicamente, os dados que preciso armazenar consistem no seguinte:
SKU Descrição Preço de localização Qty
O arquivo consistirá em vários milhões de registros.
As considerações mais importantes são o espaço de armazenamento e o tempo de recuperação.Os registros só precisarão ser recuperados por SKU e serão somente leitura, para que o arquivo possa ser classificado por SKU.
Gostaria de acessar esses dados com Python.Então minhas perguntas se resumem a isso.
Existem bibliotecas Python que podem fornecer essa funcionalidade para mim ou preciso criar a minha própria?
Se a resposta for minha, alguém tem sugestões ou boas referências para fazê-lo?
Solução
Que tal Sqlite com ligações de Python? Tem um pouco mais do que você precisa, mas é software padrão e bem testado.
Outras dicas
A maneira antiga seria usar uma tabela de dados de chave/valor simples, como o módulo GDBM. O Python vem com suporte para isso, mas não está incorporado à instalação padrão do Python na minha máquina.
Em geral, use SQLite. Como outros escreveram, ele é padrão com o Python e já é usado em muitos sistemas incorporados.
Se os registros forem fixo, você poderá usar o módulo Bisect. O tamanho do arquivo / o tamanho do registro fornece o número de registros no arquivo. A pesquisa Bisect fará uma pesquisa O (log (n)) no arquivo e você precisará escrever um adaptador para testar a igualdade. Embora eu não tenha testado, aqui está um esboço:
import bisect
RECORD_SIZE = 50
class MatchFirst10Chars(object):
def __init__(self, word):
self.word = word
def __lt__(self, other):
return self.word < other[:10]
class FileLookup(object):
def __init__(self, f):
self.f = f
f.seek(0, 2)
self.size = f.tell() // RECORD_SIZE
def __len__(self):
return self.size
def __getitem__(self, i):
self.f.seek(i*RECORD_SIZE)
return self.f.read(RECORD_SIZE)
SKU = "123-56-89 "
f = open("data_file")
fl = FileLookup(f)
i = bisect.bisect(fl, MatchFirst10Chars(SKU))
Além disso, você pode obter o arquivo e procurar em um arquivo GZIP ', mas isso é uma troca de espaço e tempo que você terá que testar.
Posso sugerir CDB? (Python Bindings: Python-CDB.)
É um formato usado para dados somente leitura, como você tem; São basicamente 256 mesas de hash gigantes, cada uma capaz de ter um número diferente de baldes. O legal do CDB é que o arquivo não precisa ser carregado na memória; é estruturado de uma maneira que você pode fazer pesquisas apenas mmap
nos bits que você precisa.
o CDB Spec é uma boa leitura, principalmente porque as linhas são formatadas para criar uma margem direita uniforme. :-D
Que tal HDF?Se você não precisa de SQL e precisa de acesso rápido aos seus dados, não há nada mais rápido...em Python...para dados numéricos ou estruturados.
Dê uma olhada no Interfaces de banco de dados seção sobre o Pitão wiki.É abrangente.Existem algumas opções "puras" do Python listadas (como SnakeSQL), que são um pouco mais agradáveis de implantar.E, claro, sempre há Banco de dados de Berkeley e similares, que são super magros e crus.
Honestamente, o SQLite provavelmente funcionará bem para você.Se você realmente precisa de mais desempenho, então você deve procurar um formato baseado em registro como o BDB.
Uma solução simples é Cpickle. Você também pode encontrar perguntas semelhantes SO.
Uma variação da resposta de Andrew Dalke (para que você ainda possa usar a pesquisa binária para localizar o SKU rapidamente), o que pode reduzir os requisitos de espaço seria ter registros de tamanho fixo no início do arquivo (um por sku) e, em seguida, todas as descrições e Locais (como dizem as cordas nulas)
Você economiza espaço por não precisar de eliminar os locais e as descrições para o comprimento fixo. Além disso, você pode economizar espaço se houver muitos locais duplicados
Aqui está um exemplo: diga que você tem
SKU 16 bytes
Description Variable length
Location Variable length
Price 4 bytes (up to $42949672.95)
Quantity 4 bytes (up to 4294967295)
offset SKU desc_off loc_off Price Quantity
0x00000000 SKU0000000000001 0x01f78a40 0x01f78a47 0x000003e8 0x000f4240
0x00000020 SKU0000000000002 0x01f78a53 0x01f78a59 ...
...
... # 999998 more records
...
0x01f78a40 Widget\x00
0x01f78a47 Head office\x00
0x01f78a53 Table\x00
0x01f78a59 Warehouse\x00