在Python/PyTables中有效验证记录唯一性的方法
我在PyTables里有一个大约5000万条记录的表格。这里面有两个字段(具体来说是用户ID和日期)的组合应该是唯一的,也就是说,一个用户在一天内最多只能有一条记录。不过,我需要确认这点是否真的成立。
简单来说,我的表格长这样:
userID | date
A | 1
A | 2
B | 1
B | 2
B | 2 <- bad! Problem with the data!
一些额外的细节:
- 这个表格现在“基本上”是排好序的。
- 我只能勉强把一列数据加载到内存中作为numpy数组,但同时加载两列是不行的。
- 用户ID和日期都是整数。
3 个回答
我对PyTables了解不多,但我会尝试这个方法。
- 对于每个用户ID,获取所有的
(用户ID, 日期)
组合。 assert len(rows)==len(set(rows))
- 这个判断成立的前提是,rows
列表中的所有(用户ID, 日期)
组合都是独一无二的。
多年后我还是有同样的问题,不过现在有了索引和查询的功能,这个问题就稍微好解决一些,具体还得看你的表有多大。使用 readWhere 或 getListWhere 的话,我觉得这个问题的复杂度大概是 O(n)。
我做了以下几件事……
1. 我创建了一个有两个索引的表。你可以在 PyTables 中使用多个索引:
http://pytables.github.com/usersguide/optimization.html#indexed-searches
一旦你的表被索引了,我还使用了 LZO 压缩,你可以这样做:
import tables
h5f = tables.openFile('filename.h5')
tbl = h5f.getNode('/data','data_table') # assumes group data and table data_table
counter += 0
for row in tbl:
ts = row['date'] # timestamp (ts) or date
uid = row['userID']
query = '(date == %d) & (userID == "%s")' % (ts, uid)
result = tbl.readWhere(query)
if len(result) > 1:
# Do something here
pass
counter += 1
if counter % 1000 == 0: print '%d rows processed'
不过我写的这段代码其实有点慢。我相信有一些 PyTables 的高手能给你更好的答案。但我对性能的看法是:
如果你知道自己开始时的数据是干净的,也就是说没有重复数据,那么你只需要查询一次表,找出你感兴趣的键,这样你只需要做:
ts = row['date'] # timestamp (ts) or date
uid = row['userID']
query = '(date == %d) & (userID == "%s")' % (ts, uid)
result = tbl.getListWhere(query)
if len(result) == 0:
# key pair is not in table
# do what you were going to do
pass
elif len(result) > 1:
# Do something here, like get a handle to the row and update instead of append.
pass
如果你有很多时间去检查重复数据,可以创建一个后台进程,遍历你的文件目录,寻找重复项。
希望这能对其他人有所帮助。
看起来在PyTables中,索引只能针对单一列。
我建议你可以添加一个哈希列,并在这个列上建立索引。你的唯一数据可以通过把数据库中的其他列连接起来定义。用分隔符可以确保不会有两行数据产生相同的唯一值。这个哈希列可以直接存放这个唯一字符串,但如果你的数据比较长,建议使用哈希函数。像md5或sha1这样的快速哈希函数非常适合这个用途。
计算出哈希后的数据,然后检查它是否在数据库中。如果在,那就说明你遇到了重复的数据。如果不在,那你就可以安全地添加这条数据。