詞頻 gawk 記憶體洩漏
我有以下 bash 腳本:
#!/usr/bin/env bash grep -e '^[a-zA-Z]\{4,8\}$' data/words3.txt | tr '[:upper:]' '[:lower:]' | sort -u > data/passphrase-words.txt function wordfrequency() { awk '{ for (i=1; i<=NF; i++) { word = tolower($i); words[word]++ } } END { for (w in words) printf("%3d %s\n", words[w], w) } ' | sort -rn } function getArticleText() { awk '/<text xml:space="preserve">/,/<\/text>/' | sed 's/<.*>//' } function reduceWikiText() { tr ' [:punct:]' '[\n*]' | sed '/^$/d' | tr '[:upper:]' '[:lower:]' } bzcat data/enwiki-20161020-pages-articles.xml.bz2 | getArticleText | reduceWikiText | grep -F -f data/passphrase-words.txt | wordfrequency > data/wordFreqs.txt
我確信它可以通過多種方式進行簡化,但這是我想出的。data/passphrase-words 是大約 170k 單詞的列表,每行一個單詞。
data/enwiki-*
是 12GB 的壓縮 XML(它是 Wikipedia 轉儲)。從那裡,getArticleText 從每篇文章中獲取文本,reduceWikiText 將該文本“減少”為每行一個單詞,去除所有 xml 和標點符號,並且 wordfrequency 計算每個單詞出現的頻率。如果我正確地閱讀了我的任務管理器,那麼 wordFrequency() 中的笨蛋正在使用大量記憶體;695MB,如果我讓它執行足夠長的時間,超過 1GB 的 RAM。
不屬於任何函式的 grep 命令限制了 gawk 將看到的不同單詞的數量,並且它佔用恆定的 36 MB。我可以看到 gawk 需要 50MB 甚至 100MB,但超過 1GB?這似乎是錯誤的。增長率意味著它將無限增長。
我需要弄清楚為什麼 gawk 使用這麼多記憶體?由於 BZ2 文件的大小,我不能讓 gawk 失控太遠……
以及我不使用排序的原因 | 唯一的-c | sort -nr 是因為我真的希望單詞計數聚合發生在記憶體中;我知道它可以適合我正在處理的單詞數量。更少的 HDD 使用 = 更快,對吧?
作為參考,適用於 Windows 的 Linux 子系統,以及:
$ gawk --version GNU Awk 4.0.1 Copyright (C) 1989, 1991-2012 Free Software Foundation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
編輯:在https://github.com/proegssilb/wikipedia-wordcount發布我所擁有的(減去 12GB .xml.bz2 文件)。根據評論中的建議,使用 mawk 似乎沒有做任何事情,但我在 200MB 的 RAM 處停止了該過程。將讓程序在不使用 awk 的情況下執行一夜,只是為了看看會發生什麼。
**EDIT2:**替換
| sort | uniq -c
有問題的 awk 後,該過程在我外出的 6-7 小時內完成。我將做一些進一步的調整以嘗試去除文章中的 HTML 使用(擺脫造成如此多污染的“”),然後再次計時,但至少它現在執行在“合理”的時間內.
因此,有幾件事有所幫助,但根據 Gregory Nisbet
sort | uniq -c
的說法,使這項工作發揮作用的主要因素是使用而不是 gawk 。我還使用了@dave_thompson_085關於
tr -sc '[:alpha:]' '\n'
. 該標誌-s
結合了重複,這意味著我不必刪除空行,並-c
反轉要查找的字元集。的副作用-c
是您只能使用一個替換字元,而不是一組。還要感謝 Dave 對grep 和精確行匹配(-x
) 的了解。如果我有支持該評論的聲譽,我會的。最後,我不得不使用一些額外的程式碼來刪除 XML 實體 (
"
) 並去除 html (excess<ref />
)。在getArticleText
中,新的 sed 命令是| sed -e 's/"/"/g' -e 's/</</g' -e 's/>/>/g' -e 's/&/&/g' -e 's/<.*>//g'
. 每個表達式(-e
連結命令)處理不同的 HTML 實體。我嘗試了一些更完整的選項(例如按照StackOverflow使用 perl ),但由於特定於機器的問題,它們在我的情況下不起作用。最終腳本可以在我的 wordcount repo上看到。該腳本在我的機器上在 3 小時 20 分鐘內完成,但它也是多年前帶有 HDD 的 6 核 AMD。您的里程可能會有所不同,但這對我來說已經足夠了。
我會避免接受這個答案,以便如果@Gregory Nisbet 或@dave_thompson_085 想發布他們自己的答案,他們可以。