高效查询已排序的csv

时间:2019-01-28 12:46:16

标签: python csv search

我有一个具有几百万行的.csv。第一列是每个条目的ID,每个ID仅出现一次。第一列已排序。直观地说,使用分而治之算法可以高效地查询此文件。但是,我找不到与此相关的任何内容。

.csv文件示例:

+----+------------------+-----+
| id | name             | age |
+----+------------------+-----+
| 1  | John Cleese      | 34  |
+----+------------------+-----+
| 3  | Mary Poppins     | 35  |
+----+------------------+-----+
| .. | ...              | ..  |
+----+------------------+-----+
| 87 | Barry Zuckerkorn | 45  |
+----+------------------+-----+

我不想将文件加载到内存中(太大),并且我不想使用数据库。我知道我可以只在sqlite中导入此文件,但是我有此数据的多个副本,出于多种原因,我希望避免这样做。

我可以忽略一个好的包裹吗?还是我必须自己写东西?

2 个答案:

答案 0 :(得分:2)

好吧,我的理解是,您需要轻型数据库的某些功能,但是必须使用csv文本文件来保存数据。恕我直言,这可能是一个有问题的设计:过去几百行,我只会看到一个csv文件,是一种中间格式或交换格式。

由于这是一个非常不常见的设计,因此不太可能已经存在用于它的软件包-就我而言,我一无所知。因此,我想像两种可能的方法:扫描文件一次并建立索引id-> row_position,然后使用该索引进行查询。根据行的实际长度,您可以仅索引第n行以更改内存速度。但这要花一个索引文件

另一种方法是直接分治算法:使用stat / fstat获取文件大小,然后从文件中间开始搜索下一行。您会立即获得一个ID。如果您想要的ID是一个,那么您将赢得罚款,如果更大,则仅在上部递归,如果较小,则在下部递归。但是,由于必须搜索行尾,因此要准备好处理极端情况,就像永远不要在预期范围内找到行尾一样,或者在行末找到它。

答案 1 :(得分:0)

在Serges回答之后,我决定编写自己的实现,就在这里。它不允许换行,也没有处理有关.csv格式的许多详细信息。它假定.csv在第一列上排序,并且第一列是整数值。

import os

def query_sorted_csv(fname, id):
    filesize = os.path.getsize(fname)

    with open(fname) as fin:
        row = look_for_id_at_location(fin, 0, filesize, id)
        if not row:
            raise Exception('id not found!')

    return row

def look_for_id_at_location(fin, location_lower, location_upper, id, sep=',', id_column=0):
    location = int((location_upper + location_lower) / 2)
    if location_upper - location_lower < 2:
        return False
    fin.seek(location)
    next(fin)
    try:
        full_line = next(fin)
    except StopIteration:
        return False

    id_at_location = int(full_line.split(sep)[id_column])
    if id_at_location == id:
        return full_line

    if id_at_location > id:
        return look_for_id_at_location(fin, location_lower, location, id)

    else:
        return look_for_id_at_location(fin, location, location_upper, id)

row = query_sorted_csv('data.csv', 505)

您可以在200万行250MB .csv文件中每秒查询约4000个id。相比之下,您可以每秒查询3个ID,同时逐行循环浏览整个文件。