Pythonでは、ファイルの行の順序不変のハッシュを、そのコンテンツを「一意に」識別する手段として、すぐに計算したいと思います。これらのファイルは、例えば、select ... from table
の出力であり、従って、線の順序はランダムである。Pythonの順序不変ハッシュ
ここでは、(hashlibのハッシャーの1つを使用して)必要なものを実現する例を示しますが、行をソートする必要はありません。 行をソートすることは、目的を達成する、つまりファイル内の行の順序に依存しないハッシュを取得することに過ぎないことに注意してください。しかし、明らかに、私はO(n * log(n))コストを避けたいと考えています。ファイルがはるかに長い場合。
def get_hexdigest(filename, hasher, blocksize=65536, order_invariant=False):
if not os.path.isfile(filename):
return None
if order_invariant:
with open(filename, 'r') as f:
for line in sorted(f):
hasher.update(line.encode())
else:
with open(filename, 'rb') as f:
while True:
buf = f.read(blocksize)
hasher.update(buf)
if len(buf) < blocksize:
break
return hasher.hexdigest()
、50K行は1メガバイトのファイル:
%%time
get_hexdigest('some_file', hashlib.sha1())
# Wall time: 1.71 ms
しかし:
%%time
get_hexdigest('some_file', hashlib.sha1(), order_invariant=True)
# Wall time: 77.4 ms
をそれを行うには良い/より高速な方法は何ですか?
in this answerと同じように、ScalaはMurmurhashに基づく順序不変のハッシュを持っていますが、私はそれが32ビットバージョンのmmh3(私の使い方では衝突が起こりやすいと思います) CやCythonで何かを実装するのではなく、Pythonで利用できます。 Murmurhash3は128ビットバージョンですが、その出力はx64とx86では異なります。私はマシンに依存しない結果を得たいと思っています。
ので、要約すると、私が希望:良好な分散と
- マシンアーキテクチャ
- 低衝突率全体で一貫性のある結果、すなわち、少なくとも128ビットを(私がするハッシュを必要はありません。暗号化)
- 合理的に高速です。つまり、1MB、50Kラインファイルの場合、少なくとも5ms未満です。
- PyPiまたはCondaのライブラリとして、可能であれば容易に利用できます。
- 繰り返し行のファイルに従うことができます(つまり、行ごとのハッシュをXORするのは非スターターです。同一の行のペアは互いに打ち消し合います)。
編集やメモ:いくつかのコメントへの おかげで、上記のコードは、メモリ内の行をソートするために更新されます。 order_invariant is True
の元のバージョンであった:
with os.popen('sort {}'.format(filename)) as f:
for line in f:
hasher.update(line.encode(encoding='utf-8'))
return hasher.hexdigest()
(上記使用されるファイルのために)関連する壁時間は、その後238ミリ秒でした。これは77ミリ秒に短縮されましたが、ラインをソートしないよりも遅くなりました。並べ替えはn行分のn * log(n)コストを追加します。
(UTF-8への)エンコード(UTF-8への)とモードの読み込み'r'
と'rb'
は、行を読み込むときに必要です。私は、ファイルにASCIIデータだけが含まれていると仮定することに頼りたくはありません。 'rb'
で読み取ると、正しく分割されない行につながる可能性があります。 order_invariant
がFalseのときは同じ懸念がありません。なぜなら、ファイルを分割する必要がないため、最も高速な方法は、バイナリデータのチャンクをスラップして、ハッシャを更新することです。
第1の改良:あなたはラインで作業している場合は、おそらく '、注意点として –
...ソートの行(F)'代わりに外部プロセスを呼び出すために '使用してPythonのラインをsort'ことができ(ファイルの行に対して_order-invariantハッシュに基づいて)_なぜordersensitiveの場合にバッファを使用していますか? 'hasher 'に' .readline() '出力を出力するだけです。 – zwer
また、ファイル全体をエンコードし、次に行を分割し、すべての行で '.encode'を呼び出す方がはるかに高速です:' open(...)as f:行のソート済み(f.read( )(.soファイル全体をメモリにロードしますが、ソートするには*これが必要です)。 – Bakuriu