經典面試題目——250M內存處理10G大小的log文件


前言

周末逛知乎的時候,看到的一個經典面試題目:http://www.zhihu.com/question/26435483。非常經典的一道分而治之的題目。

題目描寫敘述例如以下:

有次面試遇到一個問題,10G的log里面每一行都保存着一個url,內存僅僅有250M,當輸入一個url時,假設高速查出日志里是否有這條記錄,假設有,有多少條?要求不能使用數據庫,僅僅能使用文本處理。

思路

之前我的研究生導師已經從project角度分析了這個問題。這里我是簡單的記錄思想,並寫出完整的演示樣例來解決問題。
這是一道很典型的使用分治法來解決這個問題的題目。思路例如以下:
  1. 首先。考慮將10G的log文件划分為多個小於250M的文件,這樣每一個小文件就能夠一次性加載內存了。

  2. 當小文件能夠一次性加載內存后,能夠直接grep搜索,也能夠對文件內容排序后,然后二分查找。
疑問:怎樣避免在切分文件的過程中。誤操作切斷url?
解答:能夠使用split按行來切分文件(注意:這里按行是依照“\n”切割,和你用vim編譯器打開看到的行是不一樣地)。因此,我們如果一個記錄幾乎相同是480byte(已經不少了),那么依照-l 500000 切割文件。那事實上每一個文件存儲500000行也才240M。全然能夠加載內存,也不存在url被截斷的問題了。


演示樣例

1. 通過一個4k大小的日志文件。構造一個1G大小的測試log文件。並添加特殊的url為“www.wangzhengyi.com”,這也是我們要查詢的特殊url。
思路:cat 4k大小的日志文件256000次,每次結束時添加這個特殊的url:"www.wangzhengyi.com“。演示樣例代碼例如以下:
#!/bin/bash

BASE_LOG_PATH=/tmp/test/access.log.1
RES_LOG_PATH=/tmp/test/big.log
if [ -f $RES_LOG_PATH ]; then
    rm -rf $RES_LOG_PATH
fi
touch $RES_LOG_PATH

for i in `seq 1 256000`; do
    cat $BASE_LOG_PATH >> $RES_LOG_PATH 
    echo "www.example.com|10.32.185.95|-[28/Oct/2014:12:34:39 +0800]|" >> $RES_LOG_PATH
done
建成之后,我們du -sh看一下文件大小確實是1G多。



2. 我們更苛刻一些,如果最多能用的內存是5k,那我們能夠依照1000行來對1G的文件進行分割,然后bash shell for循環遍歷分割后的文件,通過grep將特殊的url查找出來,存儲到特定的文件里。演示樣例腳本例如以下:
#!/bin/bash

LOAD_DIR_PATH="/tmp/test/children"
SOURCE_PATH="/tmp/test/big.log"

if [ ! -d $LOAD_DIR_PATH ];then
    mkdir -p $LOAD_DIR_PATH
fi

cp $SOURCE_PATH $LOAD_DIR_PATH

#1.split依照1000行來進行切分
NUMBER=1000
cd $LOAD_DIR_PATH
split -l $NUMBER $LOAD_DIR_PATH/big.log

#2.for循環遍歷查找
TARGET_URL="www.wangzhengyi.com"
TARGET_PATH="/tmp/test/res.txt"
for file in `ls $LOAD_DIR_PATH`; do
    if [[ $file != "big.log" ]]; then
        grep -i $TARGET_URL $file >> $TARGET_PATH
    fi
done

#3.統計行數(前提:總結果數不超過規定的內存限制)
echo `cat $TARGET_PATH | wc -l`


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM