重复数据删除ArangoDB文档集

rop*_*der 4 arangodb aql

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

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

FOR doc IN Documents
    COLLECT docId = doc.myId, doc2 = doc
    INSERT doc2 IN Documents2
Run Code Online (Sandbox Code Playgroud)

要么

FOR doc IN Documents
    LET existing = (FOR doc2 IN Documents2
        FILTER doc.myId == doc2.myId
        RETURN doc2)
    UPDATE existing WITH doc IN Documents2
Run Code Online (Sandbox Code Playgroud)

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

FOR doc IN Documents
    UPSERT {myId: doc.myId}}]}
    INSERT doc
    UPDATE doc IN Documents2
Run Code Online (Sandbox Code Playgroud)

CoD*_*anX 6

TL; DR

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

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

制备

我生成了220万条记录,每个属性有5-20个随机属性和160个乱码乱码.此外,每条记录都有一个属性myid.187k记录具有唯一ID,60k myids存在两次,70k s存在三次.收集的大小报告为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
Run Code Online (Sandbox Code Playgroud)

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

底线

在我的系统上读取test1和插入所有文件(2.2米)test2需要20秒,内存峰值约为17.6GB:

FOR doc IN test1
    INSERT doc INTO test2
Run Code Online (Sandbox Code Playgroud)

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

LET result = (
    FOR doc IN test1
        COLLECT myid = doc.myid
        RETURN 1
)
RETURN LENGTH(result)
Run Code Online (Sandbox Code Playgroud)

分组失败

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

使用INTO进行分组

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

FOR doc IN test1
    COLLECT myid = doc.myid INTO groups
    INSERT groups[0].doc INTO test2
Run Code Online (Sandbox Code Playgroud)

使用子查询进行分组

以下查询显示内存消耗更稳定,达到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
Run Code Online (Sandbox Code Playgroud)

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

使用INTO和KEEP进行分组

我们可以只分配_id一个变量,而不是存储属于一个组的整个文档,KEEP以便我们可以使用DOCUMENT()以下方法查找文档正文:

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

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

使用INTO和投影进行分组

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

FOR doc IN test1
    COLLECT myid = doc.myid INTO groups = doc._id
    INSERT DOCUMENT(groups[0]) INTO test2
Run Code Online (Sandbox Code Playgroud)

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

UPSERT

我尝试过UPSERT,但看到了一些奇怪的结果.事实证明这是对ArangoDB upsert实现的疏忽.v3.0.2 包含一个修复程序,我现在得到了正确的结果:

FOR doc IN test1
    UPSERT {myid: doc.myid}
    INSERT doc
    UPDATE {} IN test2
Run Code Online (Sandbox Code Playgroud)

花了40多岁上用(唯一的)哈希索引来处理myidtest2,与周围13.2GB一个RAM高峰.

就地删除重复项

我首先将所有文件复制test1test2(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
Run Code Online (Sandbox Code Playgroud)

内存为8.2GB(仅test2加载),在查询期间上升至13.5GB.删除重复项(200k)大约需要16秒.

验证

以下查询组合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}
Run Code Online (Sandbox Code Playgroud)

结论

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

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