簡體   English   中英

重復數據刪除ArangoDB文檔集

[英]deduplicating ArangoDB document collection

我確信有一種簡單快捷的方法可以做到這一點,但它正在逃避我。 我有一個大型數據集,有一些重復的記錄,我想擺脫重復。 (重復項由一個屬性唯一標識,但文檔的其余部分也應相同)。

我試圖創建一個只有幾種不同方式的唯一值的新集合,但它們都很慢。 例如:

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

TL; DR

重復刪除記錄並將其寫入另一個集合( 少於60秒 ),至少在我的桌面計算機上(Windows 10,Intel 6700K 4x4.0GHz,32GB RAM,Evo 850 SSD)不需要很長時間。

但是,某些查詢需要正確的索引 ,否則它們將永遠存在。 索引需要一些內存,但與查詢執行期間為記錄分組所需的內存相比,它可以忽略不計。 如果內存不足,性能將受到影響,因為操作系統需要在內存和大容量存儲之間交換數據。 這對於旋轉磁盤尤其是一個問題,而不是快速閃存設備。

制備

我生成了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讀取並將所有文檔 (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來將具有唯一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

但請注意,它需要在test1 myid上使用myid實現~ myid的查詢執行時間。 否則,子查詢將導致數百萬次掃描並花費很長時間。

使用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

內存使用情況:加載源集合后為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

加載test1后RAM為8.3GB,峰值為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

test2中使用myid上的(唯一)哈希索引處理需要40 myid ,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。 刪除重復項(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}

結論

ArangoDB v3.0的性能似乎合理,但如果沒有足夠的RAM可能會降低性能。 不同的查詢大致在同一時間內完成,但顯示了不同的RAM使用特性。 對於某些查詢,索引是必要的,以避免高計算復雜性(這里:完整的集合掃描;在最壞的情況下讀取2,200,000,000,000?)。

您可以在數據上嘗試我提供的解決方案並檢查機器的性能嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM