Gawk

詞頻 gawk 記憶體洩漏

  • January 26, 2019

我有以下 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 Nisbetsort | 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 想發布他們自己的答案,他們可以。

引用自:https://unix.stackexchange.com/questions/322909