2017-11-11 28 views
1

작은 사전을 직렬화하는 많은 솔루션이 있습니다 json.loads/json.dumps, pickle, shelve, ujson, 또는 sqlite를 사용하여이. 키 : 클라이언트/서버없이 데이터의 가능성 100기가바이트 파이썬에서 값을 저장,

그러나 데이터의 가능성 100기가바이트를 처리 할 때, 그것은 더 이상/직렬화를 닫을 때 가능한 모든 데이터를 다시 쓸 것 같은 모듈을 사용할 수 없습니다. 이 클라이언트/서버 방식을 사용하기 때문에

redis 정말 옵션이 아닙니다.

질문 : 키 : 수 값 저장, 서버리스는, 데이터의 100 + GB 작동하도록 자주 파이썬에서 사용됩니까?

import mydb 
d = mydb.mydb('myfile.db') 
d['hello'] = 17   # able to use string or int or float as key 
d[183] = [12, 14, 24] # able to store lists as values (will probably internally jsonify it?) 
d.flush()    # easy to flush on disk 

참고 :

나는 표준 "파이썬"d[key] = value 구문 솔루션을 찾고 있어요 BsdDB (버클리)가 사용되지 않는 것으로 보인다. LevelDB for Python이있는 것 같지만 잘 알려지지 않은 것 같습니다. Windows에서는 사용할 준비가 된 버전 인 haven't found입니다. 어느 것이 가장 일반적인 것입니까?

+3

SQLite는 위대한 일을해야 내 경우는이 차트를 생성합니다. 그것을 사용하는 데 문제가 있습니까? DBMS는 작지만 DB 자체가 클 수 있습니다. https://stackoverflow.com/questions/14451624/will-sqlite-performance-degrade-if-the-database-size-is-greater-than-2-gigabytes – Himanshu

+0

@Himanshu SQLite로 사용하는 것은 사실이 아닙니다. 'db [key] = value' 나'db.put ('key', 'value')'처럼 간단하지만 SQL을 대신 사용합니다 ... 그리고 TABLE이나 SELECT에 INSERT하는 것을 피하고 싶습니다. 그냥 간단한 키 : 값'db [key] = value' set/get. – Basj

+0

데이터를 더 자세히 설명 할 수 있습니까? 100GB 무엇? 최소/중간/최대 값은 얼마나 큽니까? 얼마나 많은 키/값 쌍이 100GB를 구성합니까? –

답변

4

당신은 SQLite 데이터베이스에 키 - 값 인터페이스를 제공 sqlitedict를 사용할 수 있습니다.

SQLite limits pagepage_sizemax_page_count에 따라 이론적 인 최대 값은 140TB입니다. 그러나 파이썬 3.5.2-2ubuntu0 ~ 16.04.4 (sqlite3 2.6.0)의 기본값은 page_size=1024max_page_count=1073741823입니다. 이것은 귀하의 요구 사항에 맞는 ~ 1100GB의 최대 데이터베이스 크기를 제공합니다. 메모리 사용에 대한

from sqlitedict import SqliteDict 

mydict = SqliteDict('./my_db.sqlite', autocommit=True) 
mydict['some_key'] = any_picklable_object 
print(mydict['some_key']) 
for key, value in mydict.items(): 
    print(key, value) 
print(len(mydict)) 
mydict.close() 

업데이트

:

당신은 같은 패키지를 사용할 수 있습니다. SQLite는 데이터 세트가 RAM에 들어 가지 않아도됩니다.기본적으로 최대 cache_size 페이지를 캐시합니다. 이는 겨우 2MiB입니다 (위와 동일한 Python). 데이터로 확인하는 데 사용할 수있는 스크립트는 다음과 같습니다.

pip install lipsum psutil matplotlib psrecord sqlitedict 

sqlitedct.py ./sqlitedct.py & psrecord --plot=plot.png --interval=0.1 $! 같은

#!/usr/bin/env python3 

import os 
import random 
from contextlib import closing 

import lipsum 
from sqlitedict import SqliteDict 

def main(): 
    with closing(SqliteDict('./my_db.sqlite', autocommit=True)) as d: 
     for _ in range(100000): 
      v = lipsum.generate_paragraphs(2)[0:random.randint(200, 1000)] 
      d[os.urandom(10)] = v 

if __name__ == '__main__': 
    main() 

실행이 : 실행하기 전에. chart

그리고 데이터베이스 파일 :

$ du -h my_db.sqlite 
84M my_db.sqlite 
+0

아주 좋은 벤치 마크, @ saaj 감사합니다! 호기심에 사로 잡힌 것 : '닫는 것 (...)으로 무엇이 ...: 할거야? – Basj

+0

그래프의 CPU y 축은 0 ~ 200 %, 평균 150 %는 y 축이 맞습니까? – Basj

+0

@Basj 1) ['contextlib.closing'] (https://docs.python.org/3/library/contextlib.html#contextlib.closing). 2)'sqlite3'은'_sqlite3' 바이너리로 동작 할 때 GIL을 해제하는 자신의 쓰레드를 생성하기 때문에 생각합니다. 그래서 100 %가 넘습니다. – saaj

3

나는 이것에 대한 HDF5을 고려할 것입니다. 여기에는 몇 가지 장점이 있습니다.

  • 많은 프로그래밍 언어에서 사용할 수 있습니다.
  • 우수한 h5py 패키지를 통해 파이썬에서 사용할 수 있습니다.
  • 대용량 데이터 세트를 포함하여 전투 테스트를 거쳤습니다.
  • 가변 길이 문자열 값을 지원합니다.
  • 값은 파일 시스템과 같은 "경로"(/foo/bar)로 주소 지정할 수 있습니다.
  • 값은 배열 일 수 있지만 대개는 그럴 수 있습니다.
  • 선택적 내장 압축.
  • 선택적으로 청크를 점진적으로 작성할 수있는 "청킹".
  • 전체 데이터 세트를 메모리에 한 번에로드 할 필요는 없습니다. 힘든 하나의 접근 방식을 정의하기 위해 만드는 점에

    • 매우 유연한 :

    는 너무 몇 가지 단점이 가지고있다.

  • 복잡한 형식은 가능하지가 공식 HDF5 C 라이브러리없이 사용하는 (그러나 많은 래퍼 h5py 예를 들어이있다).
  • 바로크 C/C++ API (Python은 그렇지 않습니다).
  • 동시 작성자 (또는 작성자 + 독자)를 거의 지원하지 않습니다. 쓰기는 거친 입도로 잠글 필요가 있습니다.
당신은 (참 또는 여러 개의 같은 파일) 값 (스칼라 또는 N 차원 배열) 계층 내 하나의 파일 내부에 저장하는 방법으로 HDF5 생각할 수

.단일 디스크 파일에 값을 저장하는 것의 가장 큰 문제점은 일부 파일 시스템을 압도한다는 것입니다. 하나의 "디렉토리"에 백만 개의 값을 넣었을 때 떨어지지 않는 파일 내에서 HDF5를 파일 시스템으로 생각할 수 있습니다.

+1

HDF5는 데이터베이스가 아니며 직렬화 형식입니다. 전체를 메모리에로드해야합니다. – amirouche

+0

감사합니다. (편집 된) 질문에서와 같이 그것을 사용하는 방법을 보여주는 3 줄 또는 4 줄의 코드를 포함 할 수 있습니까? 즉,'import ...'다음에 DB를 생성 한 후'd [key] = value'를 작성한 다음 디스크로 플러시합니다. – Basj

+0

@amirouche : 분명히 HDF5는 데이터베이스가 아닙니다. 질문은 데이터베이스를 요구하지 않았습니다. HDF5는 모든 것을 메모리에로드 할 필요가 없습니다. 조각, "하이퍼 슬라브", 계층 적 파일의 단일 배열 또는 속성 등을로드 할 수 있습니다. 원하는 것 이상으로 메모리에로드 할 필요가 없습니다. 어쨌든 OP의 데이터는 100GB 정도이며, 요즘에는 범용 서버 및 일부 데스크톱에서도 100GB의 메인 메모리를 쉽게 찾을 수 있습니다. –

0

먼저 bsddb (또는 새 이름 Oracle BerkeleyDB)는 더 이상 사용되지 않습니다.

LevelDB/RocksDB/bsddb의 경험이 wiredtiger보다 느리다는 이유로 나는 wiredtiger를 추천합니다.

wiredtiger는 mongodb의 저장소 엔진이므로 실제 프로덕션 환경에서 테스트되었습니다. 내 AjguDB 프로젝트 외부에는 파이썬에서 wiredtiger를 거의 사용하지 않거나 사용하지 않습니다. 나는 약 80GB의 wikidata와 개념을 저장하고 쿼리하기 위해 wiredtiger (AjguDB를 통해)를 사용한다.

다음은 python2 shelve 모듈을 모방 할 수있는 예제 클래스입니다. 여기

import json 

from wiredtiger import wiredtiger_open 


WT_NOT_FOUND = -31803 


class WTDict: 
    """Create a wiredtiger backed dictionary""" 

    def __init__(self, path, config='create'): 
     self._cnx = wiredtiger_open(path, config) 
     self._session = self._cnx.open_session() 
     # define key value table 
     self._session.create('table:keyvalue', 'key_format=S,value_format=S') 
     self._keyvalue = self._session.open_cursor('table:keyvalue') 

    def __enter__(self): 
     return self 

    def close(self): 
     self._cnx.close() 

    def __exit__(self, *args, **kwargs): 
     self.close() 

    def _loads(self, value): 
     return json.loads(value) 

    def _dumps(self, value): 
     return json.dumps(value) 

    def __getitem__(self, key): 
     self._session.begin_transaction() 
     self._keyvalue.set_key(key) 
     if self._keyvalue.search() == WT_NOT_FOUND: 
      raise KeyError() 
     out = self._loads(self._keyvalue.get_value()) 
     self._session.commit_transaction() 
     return out 

    def __setitem__(self, key, value): 
     self._session.begin_transaction() 
     self._keyvalue.set_key(key) 
     self._keyvalue.set_value(self._dumps(value)) 
     self._keyvalue.insert() 
     self._session.commit_transaction() 

@saaj 대답에서 적응 테스트 프로그램 :

python test-wtdict.py & psrecord --plot=plot.png --interval=0.1 $! 
다음 명령 줄을 사용하여

#!/usr/bin/env python3 

import os 
import random 

import lipsum 
from wtdict import WTDict 


def main(): 
    with WTDict('wt') as wt: 
     for _ in range(100000): 
      v = lipsum.generate_paragraphs(2)[0:random.randint(200, 1000)] 
      wt[os.urandom(10)] = v 

if __name__ == '__main__': 
    main() 

기본적으로, 이 키는 문자열이 될 수 wiredtiger 백엔드 사전입니다

다음 다이어그램을 생성했습니다.

$ du -h wt 
60M wt 

미리 쓰기 로그가 활성 wt performance without wal는 :

wt performance with wal

$ du -h wt 
260M wt 

이것은 성능 튜닝없이 압축된다.

WiredTiger는 페타 바이트 테이블을 지원 최대 4GB 기록하고, 64 비트까지의 기록 번호 :

Wiredtiger는 알려진 제한 최근까지 문서는 다음에 업데이트 된이 없습니다.

http://source.wiredtiger.com/1.6.4/architecture.html

+0

감사합니다. 'wiredtiger'를 사용하여 코드 예제를 줄 수 있습니까? 'import wiretiger'와 같은 간단한 API로 사용할 수 있습니까? wt [ 'hello'] = 17' wt [183] ​​= [12, 14, 24]''wt.flush() 즉, 주요 요구 사항은 다음과 같다. 1)'wt [key] = value' 구문 2) 문자열이나 int 또는 float을 키로 사용할 수있다. 3)리스트를 값으로 저장할 수있다. 4) 쉽다. 디스크에 플러시하기 – Basj

+0

파이썬 2 또는 파이썬 3 용입니까? – amirouche

+0

저는 Python 2 @amirouche를 사용합니다. – Basj