4

ディープハッシュ(SSDEEP)http://code.google.com/p/pyssdeepを使用して130万を超えるファイルを処理しようとしています。

それがすることは、です。ハッシュを生成し(3〜6分以内に1.3 milを生成)、次に互いに比較して類似性の結果を取得します。比較は非常に高速ですが、単一のプロセスを実行するだけでは完了しません。そこで、Pythonマルチプロセッシングモジュールを組み込んで処理を実行します。

結果は、30分以内に作成された130万のテキストファイルです。18コアを使用(Quad Xeonプロセッサ、合計24 CPU)

各プロセスの仕組みは次のとおりです。

  • SSDEEP合計を生成します。
  • それらの合計のリストを5000グループのチャンクに分割します。
  • 18プロセス内の各チャンク1と5000を比較します。各反復で18の合計を比較します。
  • 類似スコアに基づいて結果をグループ化します(デフォルトは75)
  • 次の反復のためにすでにチェックされているファイルを削除しました。
  • 次のグループのスコアが75%未満の次のファイルから開始します
  • すべてのグループが完了するまで繰り返します。
  • 含まれていない(他のファイルとは異なる)ファイルがある場合、それらは残りのリストに追加されます。

すべての処理が完了すると、残りのファイルが結合され、結果がなくなるまで再帰的に相互に比較されます。

問題は、ファイルのリストがより小さな(5000)ファイルにチャンク化される場合です。最初の5000チャンクに含まれているが、別のグループには含まれていないファイルがあり、グループが不完全になっています。

チャンクなしで実行すると、ループが完了するまでに非常に長い時間がかかります。18時間以上、行われていません、。どれくらいかわからない。

アドバイスしてください。

使用されるモジュール:multiprocessing.Pool、ssdeep python

def ssdpComparer(lst, threshold):
    s = ssdeep()
    check_file = []
    result_data = []
    lst1 = lst
    set_lst = set(lst)

    print '>>>START'
    for tup1 in lst1:
        if tup1 in check_file:
            continue
        for tup2 in set_lst:
            score = s.compare(tup1[0], tup2[0])
            if score >= threshold:
                result_data.append((score, tup1[2], tup2[2])) #Score, GroupID, FileID
                check_file.append(tup2)
        set_lst = set_lst.difference(check_file)
    print """####### DONE #######"""
    remain_lst = set(lst).difference(check_file)

    return (result_data, remain_lst)



def parallelProcessing(tochunk_list, total_processes, threshold, source_path, mode, REMAINING_LEN = 0):
    result = []
    remainining = []
    pooled_lst = []
    pair = []
    chunks_toprocess = []

    print 'Total Files:', len(tochunk_list)

    if mode == MODE_INTENSIVE:
        chunks_toprocess = groupWithBlockID(tochunk_list) #blockID chunks
    elif mode == MODE_THOROUGH:
        chunks_toprocess = groupSafeLimit(tochunk_list, TOTAL_PROCESSES) #Chunks by processes
    elif mode == MODE_FAST:
        chunks_toprocess = groupSafeLimit(tochunk_list) #5000 chunks

    print 'No. of files group to process: %d' % (len(chunks_toprocess))
    pool_obj = Pool(processes = total_processes, initializer = poolInitializer, initargs = [None, threshold, source_path, mode])
    pooled_lst = pool_obj.map(matchingProcess, chunks_toprocess) #chunks_toprocess
    tmp_rs, tmp_rm = getResultAndRemainingLists(pooled_lst)
    result += tmp_rs
    remainining += tmp_rm

    print 'RESULT LEN: %s, REMAINING LEN: %s, P.R.L: %s' % (len(result), len(remainining), REMAINING_LEN)
    tmp_r_len = len(remainining)

    if tmp_r_len != REMAINING_LEN and len(result) > 0 :
        result += parallelProcessing(remainining, total_processes, threshold, source_path, mode, tmp_r_len)
    else:
        result += [('','', rf[2]) for rf in remainining]

    return result

def getResultAndRemainingLists(pooled_lst):
    g_result = []
    g_remaining = []

    for tup_result in pooled_lst:
        tmp_result, tmp_remaining = tup_result
        g_result += tmp_result
        if tmp_remaining:
            g_remaining += tmp_remaining

    return (g_result, g_remaining)
4

1 に答える 1

0

最初のアドバイス:あなたの場合、 listとしてcheck_fileを持っている必要はありません=>それをset()に変更してください-それならもっと良いはずです(最後の説明)。

チャンクが必要な場合は、そのような手順で十分です。

def split_to_chunks(wholeFileList):
    s = ssdeep()
    calculated_chunks = []
    for someFileId in wholeFileList:
        for chunk in calculated_chunks:
            if s.compare(chunk[0], someFileId) > threshold:
                chunk.append(someFileId)
                break
        else: # important: this else is on 'for ' level
            # so if there was no 'break' so someFileId is a base for new chunk:
            calculated_chunks.append( [someFileId] )
    return calculated_chunks

その後、結果をフィルタリングできます:groups = filter(lambda x:len(x)> 1、result)remains = filter(lambda x:len(x)== 1、result)

注:このアルゴリズムは、チャンクの最初の要素が一種の「ベース」であると想定しています。結果の良さはssdeepの動作に強く依存します(奇妙な質問をイメージできます:どのくらいのssdeepが推移的ですか?)この種の類似性がある場合は...

最悪のケースは、任意のペアs.compare(fileId1、fileId2)のスコアがしきい値条件を満たさない場合です(複雑さはn ^ 2であるため、この場合は1.3mln * 1.3mlnです)。

このケースを最適化する簡単な方法はありません。s.compare(file1、file2)が常に0に近い状況を想像してみてください。(私が理解しているように)s.compare(A、B)が非常に低く、s.compare(B、C)が非常に低いことがわかっていても低い場合でも、s.compare(A、C)=>については何も言えないため、n*n回の演算が必要です。

その他の注意:使用している構造とリストが多すぎるとします。例:

set_lst = set_lst.difference(check_file)

この命令は、新しいset()を作成し、set_lstとcheck_fileのすべての要素に少なくとも1回は触れる必要があります。また、check_fileはリストであるため、「difference」関数を最適化する方法がなく、複雑になります。len(check_file)* log( len(set_lst))

基本的に:これらの構造が成長している場合(1.3百万)、コンピューターはさらに多くの計算を実行する必要があります。[](list)の代わりにcheck_file = set()を使用する場合、その複雑さは次のようになります。len(set_lst)+ len(check_file)

要素がPythonのリスト(配列)にあるかどうかをチェックするのと同じです:

if tup1 in check_file:

check_fileはlist->であるため、tup1がリストにない場合、CPUはtup1をすべての要素と比較する必要があるため、その複雑さはlen(check_file)です。check_fileを設定に変更すると、その複雑さはlog2(len (check_file))違いをより視覚的にし、len(* check_file *)= 1mlnと仮定します。どのくらいの比較が必要ですか?

セット:log2(1mln)= log2(1000000)〜20

リスト:len(check_file)= 1mln

于 2012-05-22T23:53:47.227 に答える