1

私はPythonを使用して、ファイル(20000を超える)ファイルの膨大なリストをニアデュープしています。合計約300MB

現在の方法は、difflibのSequenceMatcherを使用してほぼ重複チェックを行い、QuickRatioを使用して結果を取得することです。

4人の労働者のプロセスでは、仕事を完了するのに25時間かかりますが、これは非常に遅いです。

また、Cベースのニアデュープチェックを提供するLivenstheineも試しましたが、difflibよりもさらに低速で精度が低くなります。

チェックは次のように行う必要があります。フォルダ内に20000個のファイルがあります。各ファイルは、反復ごとにフォルダー内の20000ファイルと比較する必要があります。したがって、20000*20000回の反復があります。

私が考えているのは、すべてのファイルにインデックスを付けてインデックスを比較することですが、インデックスを作成するのは初めてで、うまくいくかどうかはわかりません。その場合、最良のインデックス作成オプションは何ですか?

ありがとう。

以下はコードです:

import os,sys,chardet, csv,operator,time,subprocess
from difflib import SequenceMatcher
import threading
#from threading import Timer
import multiprocessing
from multiprocessing import Pool

OrgFile = ""
mark = int(sys.argv[2])

def init_logger():
    print "Starting %s" % multiprocessing.current_process().name

#----Get_Near_DupeStatus--------#
def Get_Near_DupeStatus(score):
    if score > 30 and score <= 50:
        return "Low Inclusive"
    elif score > 50 and score <= 75:
        return "Inclusive"
    elif score > 75 and score <= 85:
        return "Most Inclusive"
    elif score > 85 and score <= 99:
        return "Near-Dupe"
    elif score == 100:
        return "Unique"
    else: return "No Inclusive"

#----Write_To_CSV --- ALL-------#
def Write_To_CSV_All(List):
    writer = csv.writer(open('./TableList.csv','wb'),delimiter=';', quotechar=' ', quoting=csv.QUOTE_MINIMAL)
    writer.writerow(['Path/FileName(Source);'+'ID;'+'NearDupeID;'+'Similarity Score;'+'Near_DupeStatus;'+'NearDupeProcess(Y/N);'+'Encoding'])
    for i,li in enumerate(sorted(List, key=operator.itemgetter("NearDupeID"))):
        writer.writerow([li['Path/FileName(Source)']+";"+'ID00'+str(i+1)+";"+str(li['NearDupeID'])+";"+str(li['Similarity Score'])+";"+li['Near_DupeStatus']+";"+li['NearDupeProcess(Y/N)']+";"+li['Encoding']])

#Get Finish File List
def Finish_Files(List,count,id):
    finish_files = []
    for i,li in enumerate(sorted(List, key=operator.itemgetter("Similarity Score"), reverse=True)):
        if i < count:
            li['NearDupeID'] = id
            finish_files.append(li)
        if count == 0:
            li['NearDupeID'] = id
#            if li['Similarity Score'] > 50:
            finish_files.append(li)
    return finish_files

#----Search Files in Dir--------#
def GetFileListFrom_Dir(dir):
    FileList = []
    for root,dirs,filenames in os.walk(dir):
        for filename in filenames:
            realpath = os.path.join(root, filename)
            FileList.append(realpath)
    return FileList

#----Matcher--------#
def Matcher(realpath):
    junk = ["\t","\n","\r"]
    score = 0
    dict = {}
    MatchFile = ""
    dupe_Process = 'N'
    if os.path.isfile(realpath):
        MatchFile =  open(realpath).read()
        matcher = SequenceMatcher(lambda x: x in junk,OrgFile, MatchFile)
        score = int(matcher.ratio()*100)
        if score >= mark:
            encoding = chardet.detect(MatchFile)['encoding']
            if encoding == None: encoding = 'None'
            if score > 85: dupe_Process = 'Y'
            dict = {'Path/FileName(Source)':realpath,'Similarity Score':score,'Near_DupeStatus':Get_Near_DupeStatus(score),'NearDupeProcess(Y/N)':dupe_Process,'Encoding':encoding}
            return dict

#-------------Pooling--------------------#
def MatcherPooling(FileList,orgFile,process):
    global OrgFile
    OrgFile = open(orgFile).read()
    pool_obj = Pool(processes=process)
    #pool_obj = Pool(processes=process,initializer=init_logger)
    dict = {}
    DictList = []
    dict = pool_obj.map(Matcher,FileList)
    DictList.append(dict)
    pool_obj.close()
    pool_obj.join()
    return DictList

def Progress():
    p = "/-\\|"
#    global t
    for s in p:
        time.sleep(0.1)
        sys.stdout.write("%c" % s)
        sys.stdout.flush()
        sys.stdout.write('\b')
    t2 = threading.Timer(0.1,Progress).start()
#    t.start()


#----Main--------#
def Main():
    Mainls = []
    dictList = []
    finish_List = []
    BLINK = '\033[05m'
    NOBLINK = '\033[25m'
    dir = sys.argv[1]
    process = int(sys.argv[3])
    Top_rec = int(sys.argv[4])
    Mainls = GetFileListFrom_Dir(dir)
    bar = "*"
    # setup toolbar
    sys.stdout.write("%s" % BLINK+"Processing...."+ NOBLINK + "With "+ str(process) + " Multi Process...")#+" \n")
    if Top_rec != 0:
        charwidth = len(Mainls)/Top_rec
    elif Top_rec == 0: charwidth = len(Mainls)
    t = threading.Timer(0.1,Progress)
    t.start()
#    sys.stdout.write("[%s]" % ("-" * charwidth))
#    sys.stdout.flush()
#    sys.stdout.write("\b" * (charwidth+1)) # return to start of line, after '['

    #----------------------------------------------------------#
    for id,orgFile in enumerate(sorted(Mainls)):
        for dl in MatcherPooling(sorted(Mainls),orgFile,process):
            for dict in dl:
                if dict != None:
                    dictList.append(dict)

            #Append Finish Files List For CSV ALL(Write Once)
            fl = Finish_Files(dictList,Top_rec,id+1)
            if Top_rec != 0:
                for del_List in fl:
                    Mainls.remove(del_List['Path/FileName(Source)'])
                    Mainls.sort()

            finish_List.extend(fl)
            dictList = []

        sys.stdout.write("%s" % bar)
        sys.stdout.flush()

        #Exit Loop
        if len(Mainls) == 0:
            break
    #----------------------------------------------------------#
    Write_To_CSV_All(finish_List)
    #print os.system('clear')
    sys.stdout.write("%s" % " ")
    print "Finished!"
    t.cancel()
    print os._exit(99)

if __name__ == '__main__':
    Main()
4

4 に答える 4

3

部分的な答えですが、明らかな最適化の1つは、ほぼ同じサイズのファイルのみを比較することです。また、ファイルaとファイルbを比較することは、bとaを比較することと同じです。20000ファイルは20000 *(20000-1)/2の比較を行います。300 MBはそれほど大きくないので、最初にすべてのファイルを読み込もうとすることができます。

インデックス作成では、各ファイルを1つ以上の番号で記述するだけです。サイズは1つです。非空白または空白または改行文字の数は他のものである可能性があります。すべてのファイルに同じ種類のデータが含まれている場合は、データを解釈して、より有用な数値を作成できます。また、完全に同一のファイルは同じSHA-256ハッシュを持ちます。これは、ファイルのかなりの部分が同一である場合にのみ役立ちます。

import hashlib
m = hashlib.sha256()
m.update(file_contents)
this_files_hash_value=m.digest()

残念ながらdifflib.SequenceMatcher、入力ファイルのすべての可能なチャンクを動的に比較しているため、実行される内容(の一部)を完全に正確かつ正確に因数分解する方法は考えられません。

于 2012-02-29T08:20:39.453 に答える
0

ここで述べたように、まず、サイズが比較的近いか、MIMEタイプが類似しているファイルのみを比較します。

次に、データのごく一部を比較して、ほとんどの場合をすぐに除外します。優れたアルゴリズムは、ファイルの小さなチャンクから開始し、それを比較し、サイズが十分に類似している場合は2倍(必要に応じてそれ以上)にサイズを増やし、すべての比較が完了するまで、または任意の段階になるまで続けます。類似度が低すぎます。

これは、おそらく最初の1〜2回の反復でほとんどのファイルが除外されることを意味します。

于 2012-02-29T08:30:16.320 に答える
0

まず第一に、あなたはあなたの手順がそれができる限り速いかどうかを知る必要があります。

  • 2つのファイルを比較するのにかかる平均実行時間。それらを比較するだけで、マルチプロセッシングを使用したり、何もインデックス付けしたり、csvに何も書き込んだりしないでください。
  • 20000 x 10000 / 4(4人の労働者がいるので)それを掛けます
  • 得られた結果を現在の25時間と比較します。

これは、現在の比較アルゴリズムでまだ改善の余地があるかどうかを示すため、非常に重要なテストであると思います。

改善の余地があれば、それを始めましょう!最適化された手順を実行すると、先に進んで、より適切な比較ソリューションを探し始めることができるためです。

その方法について助けを求めたい場合は、現在持っているものに取り組むことは不可能であるため、より読みやすいコード例(および短い)を提供する必要があります。

于 2012-03-01T15:55:42.327 に答える
0

大きなコレクションで作業していて、テキストベースのファイル(PDF、DOC、HTMLなど)内で重複だけでなくほぼ重複も見つけたい場合は、次のようなことを考える必要があります: http:// softcorporation .com / products / neardup / Javaベースであるため、さまざまなプラットフォームで動作し、無料でダウンロードできます。

于 2013-04-07T19:48:01.127 に答える