储水池算法

每天有数十万条日志产生,条数不固定,需要从中随机抽取 2 万条。

“随机”就代表和概率有关,100 条日志随机抽 1 条,每条被抽中的概率是 1/100。现在,不知道每次抽取时,总共有多少条日志,如何去保证每条被抽中的概率一样。

简单点,可以先计算出一共多少条日志,再在这个范围内随机产生 2 万个数字作为行号,遍历日志,提取出来。这种方法不适合量大、计算资源不足的场景。

储水池算法能解决在未知行数中随机抽取的问题,算法本身比较简单, 可见维基百科

一段简单的 demo 代码:

# coding=utf-8

import random

k = 5  # 输出数量
n = 0
lines = list()

with open('/etc/passwd') as f:
    for line in f:
        line = line.strip()

        if n < k:
            lines.append(line)
        else:
            # 以 r/k 的概率抽取数据
            r = random.randint(0, n)

            if r < k:
                lines[r] = line

        n = n + 1

# output result
for line in lines:
    print line