4

かなり大きなコーパスで作業したい。これは、web 1T-gram の名前で呼ばれます。約3兆のトークンがあります。redis を使用するのはこれが初めてで、すべてのキーと値のペアを書き込もうとしていますが、時間がかかりすぎます。私の最終目標は、複数の redis インスタンスを使用してコーパスを保存することですが、今のところ、すべてを単一のインスタンスに書き込むことに固執しています。

よくわかりませんが、書き込みプロセスを加速する方法はありますか? 今のところ、64G の RAM を搭載したマシンで単一の redis インスタンスにのみ書き込みを行っています。redisに使用するために最大化できるキャッシュサイズ設定があるかどうかを考えていました。またはそれらの行に何か?

ありがとう。

参考までに、以下のコードを書きました。

import gzip
import redis
import sys
import os
import time
import gzip
r = redis.StrictRedis(host='localhost',port=6379,db=0)
startTime = time.time()
for l in os.listdir(sys.argv[1]):
        infile = gzip.open(os.path.join(sys.argv[1],l),'rb')
        print l
        for line in infile:
                parts = line.split('\t')
                #print parts[0],' ',parts[1]
                r.set(parts[0],int(parts[1].rstrip('\n')))
r.bgsave()
print time.time() - startTime, ' seconds '

アップデート :

私は大量挿入について読み、それをやろうとしましたが、それも失敗し続けています. スクリプトの変更は次のとおりです。

def gen_redis_proto(*args):
    proto = ''
    proto += '*' + str(len(args)) + '\r\n'
    for arg in args:
        proto += '$' + str(len(arg)) + '\r\n'
        proto += str(arg) + '\r\n'
    return proto
import sys
import os
import gzip
outputFile = open(sys.argv[2],'w')



for l in os.listdir(sys.argv[1]):
        infile = gzip.open(os.path.join(sys.argv[1],l),'rb')
        for line in infile:
                parts = line.split('\t')
                key = parts[0]
                value = parts[1].rstrip('\n')
                #outputFile.write(gen_redis_proto('SET',key,value))
                print gen_redis_proto('SET',key,value)

        infile.close()
        print 'done with file ',l

生成方法の功績は github ユーザーにあります。私はそれを書いていません。

これを実行すると、

ERR wrong number of arguments for 'set' command
ERR unknown command '$18'
ERR unknown command 'ESSPrivacyMark'
ERR unknown command '$3'
ERR unknown command '225'
ERR unknown command ' *3'
ERR unknown command '$3'
ERR wrong number of arguments for 'set' command
ERR unknown command '$25'
ERR unknown command 'ESSPrivacyMark'
ERR unknown command '$3'
ERR unknown command '157'
ERR unknown command ' *3'
ERR unknown command '$3'

これは延々と続きます。入力は次の形式です

"文字列" \t カウント .

ありがとう。

2回目の更新:

私はパイプラインを使用しましたが、それは私を後押ししました。しかし、すぐにメモリが不足しました。参考までに、64ギガのRAMを搭載したシステムを使用しています。そして、メモリが不足しないと思いました。コードは以下のとおりです。

import redis
import gzip
import os
import sys
r = redis.Redis(host='localhost',port=6379,db=0)
pipe = r.pipeline(transaction=False)
i = 0
MAX = 10000
ignore = ['3gm-0030.gz','3gm-0063.gz','2gm-0008.gz','3gm-0004.gz','3gm-0022.gz','2gm-0019.gz']
for l in os.listdir(sys.argv[1]):
        if(l in ignore):
                continue
        infile = gzip.open(os.path.join(sys.argv[1],l),'rb')
        print 'doing it for file ',l
        for line in infile:
                parts = line.split('\t')
                key = parts[0]
                value = parts[1].rstrip('\n')
                if(i<MAX):
                        pipe.set(key,value)
                        i=i+1
                else:   
                        pipe.execute()
                        i=0
                        pipe.set(key,value)
                        i=i+1
        infile.close()

ハッシュは行くべき道ですか?64ギガで十分だと思いました。そして、20 億個のキーと値のペアの小さなサブセットのみを指定し、すべてを指定したわけではありません。

4

3 に答える 3

2

あなたが望むことは、あなたの状況ではおそらく不可能です。

このページによると、データセットは で圧縮された24 GBgzipです。これらのファイルには、辞書などの類似したテキストが多数含まれている可能性があります。

wordsプログラムからのファイルを使用した簡単なテストでは、dict3.12x の圧縮率が得られます。

> gzip -k -c /usr/share/dict/web2 > words.gz
> du /usr/share/dict/web2  words.gz
2496    /usr/share/dict/web2
800 words.gz
> calc '2496/800'
3.12 /* 3.12 */
> calc '3.12*24'
74.88 /* 7.488e1 */

したがって、圧縮されていないデータのサイズは簡単に 64 GB を超える可能性があります。したがって、Redis のオーバーヘッドがなくも、16 ビットの符号なし整数を使用してカウントを格納したとしても、RAM に収まりません。

例を見ると、ほとんどのキーは比較的短いです。

serve as the incoming   92
serve as the incubator  99
serve as the independent    794
serve as the index  223
serve as the indication 72
serve as the indicator  120
serve as the indicators 45
serve as the indispensable  111
serve as the indispensible  40
serve as the individual 234
serve as the industrial 52

キーをハッシュすることはできますが、平均してあまり節約できない可能性があります。

In [1]: from hashlib import md5

In [2]: data = '''serve as the incoming 92
serve as the incubator 99
serve as the independent 794
serve as the index 223
serve as the indication 72
serve as the indicator 120
serve as the indicators 45
serve as the indispensable 111
serve as the indispensible 40
serve as the individual 234
serve as the industrial 52'''

In [3]: lines = data.splitlines()

In [4]: kv = [s.rsplit(None, 1) for s in lines]

In [5]: kv[0:2]
Out[5]: [['serve as the incoming', '92'], ['serve as the incubator', '99']]

In [6]: [len(s[0]) for s in kv]
Out[6]: [21, 22, 24, 18, 23, 22, 23, 26, 26, 23, 23]

In [7]: [len(md5(s[0]).digest()) for s in kv]
Out[7]: [16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16]

16 バイトより短いキーの場合、実際にはハッシュするためにより多くのスペースが必要になります

通常、ヘッダーを無視しても、文字列を圧縮してもスペースは節約されません。

In [1]: import zlib

In [2]: zlib.compress('foo')[:3]
Out[2]: 'x\x9cK'

In [3]: zlib.compress('bar')[:3]
Out[3]: 'x\x9cK'

In [4]: s = 'serve as the indispensable'

In [5]: len(s)
Out[5]: 26

In [6]: len(zlib.compress(s))-3
Out[6]: 31
于 2013-04-07T13:53:25.543 に答える
0

トップレベルのキーには、必要のない追加のデータ (TTL など) が保存されるため、オーバーヘッドがあるため、ハッシュを使用することは間違いありません。

また、redis.io サイトにはいくつかのパフォーマンス トリックがあり、Jerremy Zawodny は少し前に 12 億のキーと値のペアを保存しました。

于 2013-04-05T08:53:41.933 に答える