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 · 2609 次点击
    这是一个创建于 2000 天前的主题,其中的信息可能已经有所发展或是发生改变。
    对这个需求,我举个栗子如下:
    文件 1 和文件 2 均含有客户 ID、客户年龄以及客户地址,要找出以下 3 种数据:
    1、客户在文件 1、文件 2 都存在,但是地址或年龄至少有一个属性不同(变化数据)
    2、客户在文件 1 中存在,但是文件 2 中不存在(新增数据)
    3、客户在文件 2 中存在,但是文件 1 中不存在(删除数据)

    大概意思就是这样。这个需求实际上用数据库的话很好解决,但是碍于环境限制,无法将数据装载入数据库中再进行关联对比 /(ㄒoㄒ)/~~,必须直接在外部进行对比。每天处理的文件大概在 800G 左右,文件数量大概在 200 左右,最大文件大概在 50G 左右,设备为 8Core CPU,内存 32G。文件比较大,对性能也有一些要求。随意想请教大家,是否有什么好的实现思路,如何对比能够高效。非常感谢大家~
    12 条回复    2019-06-14 08:15:10 +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 命令的性能。
    liprais
        4
    liprais  
       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
    liprais
        6
    liprais  
       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 抱歉由于工作原因,我这边还没有抽出时间实现这个对比,后续待我完成给您后续反馈,非常感谢~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1703 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 16:47 · PVG 00:47 · LAX 08:47 · JFK 11:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.