首页 文章

重复数据删除ArangoDB文档集

提问于
浏览
3

我确信有一种简单快捷的方法可以做到这一点,但它正在逃避我 . 我有一个大型数据集,有一些重复的记录,我想摆脱重复 . (重复项由一个属性唯一标识,但文档的其余部分也应相同) .

我试图创建一个只有几种不同方式的唯一值的新集合,但它们都很慢 . 例如:

FOR doc IN Documents
    COLLECT docId = doc.myId, doc2 = doc
    INSERT doc2 IN Documents2

要么

FOR doc IN Documents
    LET existing = (FOR doc2 IN Documents2
        FILTER doc.myId == doc2.myId
        RETURN doc2)
    UPDATE existing WITH doc IN Documents2

或(这给了我一个“违反的唯一约束”错误)

FOR doc IN Documents
    UPSERT {myId: doc.myId}}]}
    INSERT doc
    UPDATE doc IN Documents2

1 回答

  • 5

    TL; DR

    重新删除记录并将其写入另一个集合( less than 60 seconds )并不需要很长时间,至少在我的桌面计算机上(Windows 10,Intel 6700K 4x4.0GHz,32GB RAM,Evo 850 SSD) .

    但是,某些查询需要 proper indexing ,否则它们将永久存在 . 索引需要一些内存,但与查询执行期间为记录分组所需的内存相比,它可以忽略不计 . 如果内存不足,性能将受到影响,因为操作系统需要在内存和大容量存储之间交换数据 . 这对于旋转磁盘尤其是一个问题,而不是快速闪存设备 .

    准备工作

    我生成了220万条记录,每个属性有5-20个随机属性和160个乱码乱码 . 此外,每条记录都有一个属性 myid . 187k条记录具有唯一ID,60k myid s存在两次,70k三次存在 . 收集的大小报告为4.83GB:

    // 1..2000000: 300s
    // 1..130000: 20s
    // 1..70000: 10s
    FOR i IN 1..2000000
        LET randomAttributes = MERGE(
            FOR j IN 1..FLOOR(RAND() * 15) + 5
                RETURN { [CONCAT("attr", j)]: RANDOM_TOKEN(160) }
        )
        INSERT MERGE(randomAttributes, {myid: i}) INTO test1
    

    启动ArangoDB之前的内存消耗在启动4.0GB后为3.4GB,在加载 test1 源集合后为8.8GB .

    基线

    test1 读取并将 all documents (2.2m)插入 test2 在我的系统上耗时20秒,内存峰值为~17.6GB:

    FOR doc IN test1
        INSERT doc INTO test2
    

    在没有写作的情况下按 myid 分组大约9s对我来说,在查询期间有9GB RAM峰值:

    LET result = (
        FOR doc IN test1
            COLLECT myid = doc.myid
            RETURN 1
    )
    RETURN LENGTH(result)
    

    分组失败

    我在一个只有3条记录和一条重复 myid 的数据集上尝试了 COLLECT docId = doc.myId, doc2 = doc 方法 . 它表明查询实际上并不分组/删除重复项 . 因此,我试图找到替代查询 .

    使用INTO进行分组

    要将复制 myid 组合在一起但仍保留访问完整文档的可能性,可以使用 COLLECT ... INTO . 我只是选择了每个组的第一个文档来删除多余的 myid . 查询花了大约40秒来将带有唯一 myid 属性的2m记录写入 test2 . 我没有准确测量内存消耗,但我看到不同的内存峰值跨越14GB到21GB . 也许截断测试集合并重新运行查询会增加所需的内存,因为某些陈旧的条目会以某种方式阻塞(压缩/密钥生成)?

    FOR doc IN test1
        COLLECT myid = doc.myid INTO groups
        INSERT groups[0].doc INTO test2
    

    使用子查询进行分组

    以下查询显示内存消耗更稳定,达到13.4GB:

    FOR doc IN test1
        COLLECT myid = doc.myid
        LET doc2 = (
            FOR doc3 IN test1
                FILTER doc3.myid == myid
                LIMIT 1
                RETURN doc3
        )
        INSERT doc2[0] INTO test2
    

    但请注意,它需要 test1myid 上的哈希索引才能实现~38s的查询执行时间 . 否则,子查询将导致数百万次扫描并花费很长时间 .

    使用INTO和KEEP进行分组

    我们可以只将 _id 分配给一个变量而不是存储组中的整个文档,而不是存储 _id ,以便我们可以使用 DOCUMENT() 查找文档正文:

    FOR doc IN test1
        LET d = doc._id
        COLLECT myid = doc.myid INTO groups KEEP d
        INSERT DOCUMENT(groups[0].d) INTO test2
    

    内存使用情况:加载源集合后为8.1GB,查询期间为13.5GB峰值 . 这个2m的记录只花了 30 seconds

    使用INTO和投影进行分组

    而不是保持,我也出于好奇而尝试投射:

    FOR doc IN test1
        COLLECT myid = doc.myid INTO groups = doc._id
        INSERT DOCUMENT(groups[0]) INTO test2
    

    加载 test1 后RAM达到8.3GB,峰值达到17.8GB(查询执行期间实际上有两次重击,均超过17GB) . 完成200万条记录需要35秒才能完成 .

    Upsert

    我尝试过UPSERT,但看到了一些奇怪的结果 . 事实证明这是对ArangoDB upsert实现的疏忽 . v3.0.2 contains a fix我现在得到了正确的结果:

    FOR doc IN test1
        UPSERT {myid: doc.myid}
        INSERT doc
        UPDATE {} IN test2
    

    test2myid 上使用(唯一)哈希索引进行处理需要40秒,RAM峰值约为13.2GB .

    就地删除重复项

    我首先将所有文件从 test1 复制到 test2 (2.2m记录),然后我尝试 REMOVE 只是 test2 中的重复项:

    FOR doc IN test2
        COLLECT myid = doc.myid INTO keys = doc._key
        LET allButFirst = SLICE(keys, 1) // or SHIFT(keys)
        FOR k IN allButFirst
            REMOVE k IN test2
    

    内存为8.2GB(仅加载了 test2 ),在查询过程中上升到13.5GB . 删除重复项大致需要 16 seconds (200K) .

    验证

    以下查询将 myid 组合在一起并聚合每个ID出现的频率 . 针对目标集合 test2 运行,结果应为 {"1": 2000000} ,否则仍有重复项 . 我仔细检查了上面的查询结果,检查了所有内容 .

    FOR doc IN test2
        COLLECT myid = doc.myid WITH COUNT INTO count
        COLLECT c = count WITH COUNT INTO cc
        RETURN {[c]: cc}
    

    结论

    ArangoDB v3.0的性能似乎合理,但如果没有足够的RAM可能会降低性能 . 不同的查询大致在同一时间内完成,但显示了不同的RAM使用特性 . 对于某些查询,索引是必要的,以避免高计算复杂性(这里:完整的集合扫描;在最坏的情况下读取2,200,000,000,000?) .

    您可以在数据上尝试我提供的解决方案并检查机器的性能吗?

相关问题