2016-09-28 295 views
1

我有一個大約10 GB的文本文件,我需要對文件中的文本數據進行一些處理。 什麼是讀取,訪問和處理如此巨大的文件的最佳方式?處理10 GB的.txt文件

我想打破文件分割成塊,然後通過處理小文件處理它(或者可以在緩衝區 - 更好),然後將合併的結果。更像是map-reduce範例,但不會使用大數據技術。

+0

你總是可以使用Unix來處理這樣的大文件。 – hemalp108

+0

我將進行一些複雜的處理,這將在應用程序級別上完成 –

+2

如果您在算法中使用流式方法,則不會受到任何大小的限制。此外,不需要*將文件分割成塊,然後通過處理較小的文件來處理它*。打開文件,讀取內存中的塊,處理塊,讀取另一塊,然後合併結果 – UmNyobe

回答

0

如果將全部10 GB加載到內存中,一切都很簡單。

如果你不能,那麼你一次只能加載一系列的大文件到您的緩衝區。

當您使用的部分完成的,你滑動窗口(改變的範圍內),加載數據的新範圍到您的緩衝區,因此在緩衝器中的數據的前面的範圍被丟棄(覆蓋)。

您可以尋求所需的位置,並可能需要來回加載數據。它可能相對較慢,但這是您使用較少內存(空間時間折衷)所付出的代價。

-

您可能想要閱讀可以處理大文件的程序的源代碼。例如。文件歸檔器。

0

我會使用線程文件的每個塊裝入一個緩衝,然後再處理緩衝區,做你所需要的。然後加載更多的緩衝區從內存中刪除以前的緩衝區並繼續。看看如何加載音頻,因爲它是像你想要的那樣加載到緩衝區中的。

+0

*使用線程*否。其餘的都是有道理的。 – UmNyobe

+0

如果你正確地傳輸一切,你可以線程化,它更高效但更困難。 –

1

選項如何處理數據:

  • 負載一切到RAM,並立即處理它 - 它是否適合那裏...

  • 進程只有一個在一次線;例如逐行。好極了,如果所有的處理都不需要除了處理過的行本身以外的其他信息 - 沒有共享存儲,沒有數據庫...

  • 結合上述兩項:讀取一堆項目(文本行等),處理它們,讀取另一堆物品......如果你想/需要在處理時使用共享存儲(數據庫),那麼批量處理比逐一處理更有效。 「Hadoop風格」:使用良好的可擴展算法和數據結構,如地圖,排序,可能窗口,事件流,二進制搜索 - 並將它們連接到數據處理管道中。沒有共享存儲。基本上這是「一行一行」的方法,但有一些魔術會給你「合適的線條」(排序,聚合,按一些關鍵,前N,後N ...分組)。

從我的經驗的一些技巧:

  • 使用壓縮。即使您的磁盤足夠大,磁盤(或網絡!)I/O通常也是瓶頸。

  • 使用批次/塊儘可能處理/一次發送/保存/載入......更多的項目。如果處理數據庫:一次處理(選擇,插入,更新...)更多項目。例如MongoDB具有批量操作。這節省了網絡I/O開銷。

  • 儘量減少系統調用次數(通過像上面提到分批做的東西)。每個系統調用是指CPU有上下文切換,CPU緩存的內容就沒了,操作系統可能不得不與硬件

  • 使用所有的CPU內核溝通...。有些平臺(Python,Ruby)在進程中比線程更好。

  • 如果可能,請使用CPU高速緩存。例如像數組或C++ vector這樣的「線性」數據結構在這方面比鏈接列表更好。使用排序後的數組和二進制搜索代替字典/映射和鍵查找 - 更小的內存佔用量,更小的內存碎片,更高的CPU緩存命中率。

  • 分割輸入數據,以零件所以即使加載該數據可以容易地並行化。現在

,如何做到這一點:

您可以使用Hadoop的或類似的工具中的「本地主機模式」 - 無需部署完整的堆棧紗,動物園管理員和諸如此類的東西。只需安裝hadoop(或類似的東西),用你的數據處理邏輯編寫一些.java文件,編譯爲.jar,在Hadoop中執行完成。無需使用HDFS(如果你不想),只需要正常的文件。或者從頭開始寫東西。在這裏,我推薦使用Python,因爲它可以與所有可以想象的東西(文件格式,數據庫,數學庫)配合使用,其模塊提供了很好的工具(如進程,進程池,隊列,鎖,並行映射,類似redis的數據服務器)讓你的程序有點分佈。如果您發現Python slow只是將緩慢的部分重寫爲C/C++並從Python使用它(使用cffi或Cython)。

大多數Python的多處理功能僅限於單個主機/計算機。我認爲這大部分是好的,因爲今天的硬件通常有很多CPU核心。如果沒有,只需啓動一些AWS EC2實例,並以每小時幾美分的價格購買許多核心。

讓我們來舉一個例子 - 字數統計,「大數據你好世界」。使用Python。我將使用cswiki.xml.bz2維基百科轉儲,這是618 MB壓縮和2.35 GB未壓縮。這是一個XML文件,但我們將它作爲一個文本文件,以保持簡單:)

首先與一個單一的文件工作是乏味的。這是更好的分裂它更小的文件,以便 輸入數據,可以更容易分佈到多個工人:

$ bzcat cswiki-20160920-pages-articles-multistream.xml.bz2 | \ 
    split \ 
     --filter='xz -1 > $FILE' \ 
     --additional-suffix=.xz \ 
     --lines=5000000 \ 
     - cswiki-splitted. 

結果:

$ ls -1hs cswiki* 
618M cswiki-20160920-pages-articles-multistream.xml.bz2 
94M cswiki-splitted.aa.xz 
77M cswiki-splitted.ab.xz 
74M cswiki-splitted.ac.xz 
64M cswiki-splitted.ad.xz 
62M cswiki-splitted.ae.xz 
56M cswiki-splitted.af.xz 
54M cswiki-splitted.ag.xz 
58M cswiki-splitted.ah.xz 
59M cswiki-splitted.ai.xz 
15M cswiki-splitted.aj.xz 

下面是一個使用multiprocessing.Pool一個簡單的單詞計數實現:

#!/usr/bin/env python3 

import lzma 
import multiprocessing 
from os import getpid 
from pathlib import Path 
import re 

def main(): 
    input_dir = Path('.') 
    input_files = [p for p in input_dir.iterdir() if p.name.startswith('cswiki-splitted.')] 

    pool = multiprocessing.Pool() 
    partial_results = pool.map(process_file, input_files) 

    aggregated_results = {} 
    for pr in partial_results: 
     for word, count in pr.items(): 
      aggregated_results[word] = aggregated_results.get(word, 0) + count 

    words_and_counts = aggregated_results.items() 
    counts_and_words = [(c, w) for w, c in words_and_counts] 
    counts_and_words.sort(reverse=True) 
    print('Top 100:', counts_and_words[:100]) 

def process_file(path): 
    print('Process {} reading file {}'.format(getpid(), path)) 
    f = lzma.open(str(path), 'rt') 
    counts = {} 
    for line in f: 
     words = re.split(r'\W+', line) 
     for word in words: 
      if word != '': 
       word = word.lower() 
       counts[word] = counts.get(word, 0) + 1 
    return counts 

if __name__ == '__main__': 
    main() 

輸出:

$ ./wordcount.py 
Process 2480 reading file cswiki-splitted.ab.xz 
Process 2481 reading file cswiki-splitted.ah.xz 
Process 2482 reading file cswiki-splitted.aj.xz 
Process 2483 reading file cswiki-splitted.aa.xz 
Process 2484 reading file cswiki-splitted.af.xz 
Process 2485 reading file cswiki-splitted.ac.xz 
Process 2486 reading file cswiki-splitted.ai.xz 
Process 2487 reading file cswiki-splitted.ae.xz 
Process 2482 reading file cswiki-splitted.ad.xz 
Process 2481 reading file cswiki-splitted.ag.xz 
Top 100: [(4890109, 'quot'), (4774018, 'gt'), (4765677, 'lt'), (4468312, 'id'), (4433742, 'v'), (4377363, 'a'), (2767007, 'na'), (2459957, 'text'), (2278791, 'amp'), (2114275, 'se'), (1971423, 'ref'), (1968093, 'kategorie'), (1799812, 'align'), (1795733, 'nbsp'), (1779981, 'title'), (1662895, '0'), (1592622, '1'), (1489233, 'page'), (1485505, 'je'), (1483416, 'model'), (1476711, 'format'), (1473507, '2'), (1470963, 'ns'), (1468018, 'revision'), (1467530, 'contributor'), (1467479, 'timestamp'), (1467453, 'sha1'), (1429859, 'comment'), (1414549, 'username'), (1261194, 's'), (1177526, '3'), (1159601, 'z'), (1115378, 'http'), (1040230, 'parentid'), (1012821, 'flagicon'), (949947, 'do'), (920863, 'right'), (887196, 'br'), (828466, 'x'), (797722, 've'), (795342, '4'), (783019, 'www'), (778643, '6'), (762929, 'name'), (762220, 'wiki'), (757659, 'i'), (752524, 'space'), (742525, 'xml'), (740244, 'center'), (733809, 'preserve'), (733752, 'wikitext'), (730781, 'o'), (725646, 'cz'), (679842, '5'), (672394, 'datum'), (599607, 'u'), (580936, 'byl'), (563301, 'k'), (550669, 'roce'), (546944, '10'), (536135, 'pro'), (531257, 'jako'), (527321, 'rd1'), (519607, '7'), (515398, 'roku'), (512456, 'od'), (509483, 'style'), (488923, 'za'), (485546, 'titul'), (467147, 'jméno'), (451536, '14'), (448649, '2016'), (447374, 'po'), (444325, 'citace'), (442389, 'jpg'), (424982, '12'), (423842, 'že'), (416419, 'název'), (408796, 'redirect'), (405058, 'minor'), (402733, 'to'), (400355, 'soubor'), (398188, '8'), (395652, 'the'), (393122, '11'), (389370, 'místo'), (368283, '15'), (359019, 'url'), (355302, 'monografie'), (354336, 'odkazy'), (352414, 'jsou'), (348138, 'of'), (344892, 'narození'), (340021, 'vydavatel'), (339462, '2014'), (339219, '20'), (339063, 'jeho'), (336257, '9'), (332598, 'praha'), (328268, 'byla')] 

我們可以看到XML標籤和屬性存在很多噪音。這就是你在XML文件上運行wordcount所得到的結果:)

所有的文件讀取和文字計數都是並行完成的。只有最後的聚合在主流程中進行。

+0

非常感謝您的詳細解答。欣賞它。 –