从大型数据集中删除重复的行

时间:2013-07-26 17:47:06

标签: hash computer-science large-files bloom-filter

让我们假设我有一个非常大的数据集,无法容纳到内存中,数据集中有数百万条记录,我想删除重复的行(实际上从重复行中保留一行)

在空间和时间复杂性方面,最有效的方法是什么?

我的想法:

1.使用布隆过滤器,我不确定它是如何实现的,但我猜副作用是假阳性,在这种情况下,我们怎么能找到它是否真的重复?

2.使用哈希值,在这种情况下,如果我们有少量的重复值,唯一哈希值的数量会很大,我们可能再次遇到内存问题,

2 个答案:

答案 0 :(得分:2)

您的解决方案2:使用哈希值不会强制出现内存问题。您只需将哈希空间划分为适合内存的切片。更确切地说:

考虑存储记录集的哈希表,每个记录仅由表中的索引表示。比如说这样的哈希表将是4GB。然后在k = 4切片中拆分哈希空间。根据散列值的最后两位数,每条记录进入一个切片。所以算法大致如下:

let k = 2^M
for i from 0 to k-1:
    t = new table
    for each record r on the disk:
        h = hashvalue(r)
        if (the M last bit of h == i) {
            insert r into t with respect to hash value h >> M
        }
    search t for duplicate and remove them
    delete t from memory

缺点是您必须将每条记录哈希k次。优点是它可以轻松地分发。

这是Python的原型:

# Fake huge database on the disks
records = ["askdjlsd", "kalsjdld", "alkjdslad", "askdjlsd"]*100

M = 2
mask = 2**(M+1)-1
class HashLink(object):
    def __init__(self, idx):
        self._idx = idx
        self._hash = hash(records[idx]) # file access

    def __hash__(self):
        return self._hash >> M

    # hashlink are equal if they link to equal objects
    def __eq__(self, other):
        return records[self._idx] == records[other._idx] # file access

    def __repr__(self):
        return str(records[self._idx])

to_be_deleted = list()
for i in range(2**M):
    t = set()
    for idx, rec in enumerate(records):
        h = hash(rec)
        if (h & mask == i):
            if HashLink(idx) in t:
                to_be_deleted.append(idx)
            else:
                t.add(HashLink(idx))

结果是:

>>> [records[idx] for idx in range(len(records)) if idx not in to_be_deleted]
['askdjlsd', 'kalsjdld', 'alkjdslad']

答案 1 :(得分:1)

由于您需要删除重复项目而不进行排序或索引,因此您可能最终会为每次删除扫描整个数据集,这在性能方面难以承受。鉴于此,您可能会想到一些外部排序或数据库。如果您不关心输出数据集的排序。根据记录或记录键的哈希值创建“n”个文件,这些文件存储输入数据集的子集。获取哈希并以'n'取模,并获取正确的输出文件来存储内容。由于现在每个输出文件的大小都很小,因此删除操作会非常快;对于输出文件,您可以使用普通文件或sqlite / berkeley db。我会推荐sqlite / bdb。为了避免扫描每个写入输出文件,您可以为每个输出文件都有一个前端布隆过滤器。布隆过滤器并不困难。有很多图书馆可供选择。我会说,计算'n'取决于你的主存。对'n'表示悲观,巨大的价值。完成工作后,将所有输出文件连接成一个。