请问大家一个问题,小弟想实现一个文件对比的功能,按照文本固定一列为关联列,来对比其他列是否相同,并输出不同的、文件 1 不存在关联列的、文件 2 不存在关联列的所有内容 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
praynise
V2EX    Go 编程语言

请问大家一个问题,小弟想实现一个文件对比的功能,按照文本固定一列为关联列,来对比其他列是否相同,并输出不同的、文件 1 不存在关联列的、文件 2 不存在关联列的所有内容

  •  
  •   praynise 2019-06-03 14:16:24 +08:00 2940 次点击
    这是一个创建于 2322 天前的主题,其中的信息可能已经有所发展或是发生改变。
    对这个需求,我举个栗子如下:
    文件 1 和文件 2 均含有客户 ID、客户年龄以及客户地址,要找出以下 3 种数据:
    1、客户在文件 1、文件 2 都存在,但是地址或年龄至少有一个属性不同(变化数据)
    2、客户在文件 1 中存在,但是文件 2 中不存在(新增数据)
    3、客户在文件 2 中存在,但是文件 1 中不存在(删除数据)

    大概意思就是这样。这个需求实际上用数据库的话很好解决,但是碍于环境限制,无法将数据装载入数据库中再进行关联对比 /(ㄒoㄒ)/~~,必须直接在外部进行对比。每天处理的文件大概在 800G 左右,文件数量大概在 200 左右,最大文件大概在 50G 左右,设备为 8Core CPU,内存 32G。文件比较大,对性能也有一些要求。随意想请教大家,是否有什么好的实现思路,如何对比能够高效。非常感谢大家~
    13 条回复    2024-12-26 18:22:06 +08:00
    dongyx
        1
    dongyx  
       2019-06-03 14:44:52 +08:00
    直接用 diff 能够处理吗?
    praynise
        2
    praynise  
    OP
       2019-06-03 15:41:42 +08:00
    @dongyx 直接用 diff 的话,需要解析 diff 输出内容,会比较麻烦
    lonelinsky
        3
    lonelinsky  
       2019-06-03 16:01:20 +08:00
    先外部 sort 排序之后,然后两个文件同时读着处理下? 不过文件有点大,不太确定 sort 命令的性能。
    F281M6Dh8DXpD1g2
        4
    F281M6Dh8DXpD1g2  
       2019-06-03 16:07:25 +08:00   1
    不能用数据库就学学数据库怎么做的呗
    文件 1 文件 2 都按年龄分桶,然后每个桶对应的去比较呗
    你地址格式化的好的话也可以先按地址分桶再按年龄分桶,然后随便搞个 hash 查找就行了
    或者你可以用 pandas........
    praynise
        5
    praynise  
    OP
       2019-06-04 10:26:42 +08:00
    @liprais pandas 加载太大的文件内存就撑不住了 orz
    F281M6Dh8DXpD1g2
        6
    F281M6Dh8DXpD1g2  
       2019-06-04 10:44:55 +08:00
    @praynise 分好桶之后再用呗
    dongyx
        7
    dongyx  
       2019-06-04 11:22:50 +08:00   1
    @praynise 哦哦,那你可以这样做,先把两个文件按照客户 id 做外排序。然后利用类似于归并排序的归并过程。

    我给你准备了一个简单的 sample:

    $ cat before.txt
    Smith 26 Beijing
    Sam 47 Washington
    Mary 15 Tokyo

    $ cat after.txt
    Smith 26 Beijing
    Sam 57 Washington
    Nancy 21 Paris

    这个 Sample 里,新增了 Nancy,删除了 Mary,修改了 Sam。

    先做外排序:

    $ sort -k1 before.txt > sorted_before.txt
    $ sort -k1 after.txt > sorted_after.txt

    然后利用归并过程来实现你的需求,具体是这样的:

    两个迭代器或者指针 fp_before, fp_after 分别指向 sorted_before.txt 和 sorted_after.txt 的第一行,进行如下迭代:

    1. 如果 before_key > after_key,说明 after 中的第一行是新增的,输出结果,fp_after 移动到下一行
    2. 如果 before_key < after_key,如果 before 中的第一行被删除了,输出结果,fp_before 移动到下一行
    3. 如果 before_key == after_key,两个指针都移动下一行,但是移动前先对比当前两条记录,如果不一致,说明修改了

    迭代完后,如果 fp_before 没有到文件末尾,那么剩下的内容都会被删除的记录;如果 fp_after 没有到末尾,那么剩下的内容都会新增的记录。

    很遗憾,我不会 Go,用 Python3 写了份代码供你参考,时间有限写得不好请见谅:

    #!/usr/env/python3
    # -*- coding: utf-8 -*-

    with open("sorted_before.txt") as fp_before, \
    open("sorted_after.txt") as fp_after:

    before = fp_before.readline()
    after = fp_after.readline()

    while before and after:
    before = before.rstrip()
    after = after.rstrip()

    before_key = before.split()[0]
    after_key = after.split()[0]

    if after_key < before_key:
    print("+", after)
    after = fp_after.readline()

    elif after_key > before_key:
    print("-", before)
    before = fp_before.readline()

    else:
    if before != after:
    print(' ', before, "=>", after)
    before = fp_before.readline()
    after = fp_after.readline()

    for before_surplus in fp_before:
    print("-", before_surplus)

    for after_surplus in fp_after:
    print("+", after_surplus)

    这份代码跑上面的 sample 的结果:

    - Mary 15 Tokyo
    + Nancy 21 Paris
    Sam 47 Washington => Sam 57 Washington
    dongyx
        8
    dongyx  
       2019-06-04 11:24:46 +08:00
    Python 的缩进粘贴过来没有了,我给个 gist 吧: https://gist.github.com/dongyx/a052cadf160896b879cdfb4d48e2f038
    dongyx
        9
    dongyx  
       2019-06-04 11:32:34 +08:00
    typo:

    2. 如果 before_key < after_key,*如果* before 中的第一行被删除了,输出结果,fp_before 移动到下一行

    =>

    2. 如果 before_key < after_key,*说明* before 中的第一行被删除了,输出结果,fp_before 移动到下一行
    praynise
        10
    praynise  
    OP
       2019-06-04 13:09:21 +08:00
    @dongyx 我用 go 实现以下,非常感谢~
    dongyx
        11
    dongyx  
       2019-06-10 12:18:07 +08:00
    @praynise 你那边试了吗?能不能解决问题?我对这个问题挺感兴趣的,很希望能得到你的后续反馈。
    praynise
        12
    praynise  
    OP
       2019-06-14 08:15:10 +08:00
    @dongyx 抱歉由于工作原因,我这边还没有抽出时间实现这个对比,后续待我完成给您后续反馈,非常感谢~
    xihuannihesuanna
        13
    xihuannihesuanna  
       289 天前 via Android
    @dongyx 太强了 初学者前来报到
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2195 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 00:39 PVG 08:39 LAX 17:39 JFK 20:39
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86