[英]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
重復刪除記錄並將其寫入另一個集合( 少於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
方法。 它表明查詢實際上並不分組/刪除重復項。 因此,我試圖找到替代查詢。
要將重復的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
的查詢執行時間。 否則,子查詢將導致數百萬次掃描並花費很長時間。
我們可以只將_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秒 !
而不是保持,我也出於好奇而嘗試投射:
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,但看到了一些奇怪的結果。 事實證明這是對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.