经典面试题目——250M内存处理10G大小的log文件

来源:互联网 发布:dos是什么办公软件 编辑:程序博客网 时间:2024/06/05 00:33

前言

周末逛知乎的时候,看到的一个经典面试题目:http://www.zhihu.com/question/26435483,很经典的一道分而治之的题目。题目描述如下:
有次面试遇到一个问题,10G的log里面每一行都保存着一个url,内存只有250M,当输入一个url时,如果快速查出日志里是否有这条记录,如果有,有多少条?要求不能使用数据库,只能使用文本处理。

思路

之前我的研究生导师已经从工程角度分析了这个问题,这里我是简单的记录思想,并写出完整的示例来解决这个问题。
这是一道非常典型的使用分治法来解决问题的题目。思路如下:
  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/bashBASE_LOG_PATH=/tmp/test/access.log.1RES_LOG_PATH=/tmp/test/big.logif [ -f $RES_LOG_PATH ]; then    rm -rf $RES_LOG_PATHfitouch $RES_LOG_PATHfor 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_PATHdone
建成之后,我们du -sh看一下文件大小确实是1G多。



2. 我们更苛刻一些,假设最多能用的内存是5k,那我们可以按照1000行来对1G的文件进行切割,然后bash shell for循环遍历切割后的文件,通过grep将特殊的url查找出来,存储到特定的文件中。示例脚本如下:
#!/bin/bashLOAD_DIR_PATH="/tmp/test/children"SOURCE_PATH="/tmp/test/big.log"if [ ! -d $LOAD_DIR_PATH ];then    mkdir -p $LOAD_DIR_PATHficp $SOURCE_PATH $LOAD_DIR_PATH#1.split按照1000行来进行切分NUMBER=1000cd $LOAD_DIR_PATHsplit -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    fidone#3.统计行数(前提:总结果数不超过规定的内存限制)echo `cat $TARGET_PATH | wc -l`

0 0
原创粉丝点击