二进制搜索具有未知行长度的巨大文件

时间:2011-12-03 16:41:04

标签: python database io binary-search large-files

我正在处理大量数据CSV文件。每个文件包含数百万条记录,每条记录都有一个密钥。记录按其密钥排序。我不想在搜索certian数据时查看整个文件。 我见过这个解决方案:Reading Huge File in Python

但它建议你在文件上使用相同长度的行 - 在我的情况下不支持。

我考虑过为每一行添加一个填充,然后保持一个固定的行长度,但我想知道是否有更好的方法来实现它。

我正在使用python

3 个答案:

答案 0 :(得分:7)

您不必拥有固定宽度记录,因为您不必进行面向记录的搜索。相反,您可以只进行面向字节的搜索,并确保在进行搜索时重新对齐键。这是一个(可能是错误的)示例,说明如何修改链接到从面向记录到面向字节的解决方案:

bytes = 24935502 # number of entries
for i, search in enumerate(list): # list contains the list of search keys
  left, right = 0, bytes - 1 
  key = None
  while key != search and left <= right:
    mid = (left + right) / 2
    fin.seek(mid)
    # now realign to a record
    if mid:
        fin.readline()
    key, value = map(int, fin.readline().split())
    if search > key:
      left = mid + 1
    else:
      right = mid - 1
  if key != search:
    value = None # for when search key is not found
  search.result = value # store the result of the search

答案 1 :(得分:2)

要解决此问题,您还可以使用二进制搜索,但需要更改一下:

  1. 获取文件大小。
  2. 使用File.seek寻找中间大小。
  3. 搜索第一个EOL角色。然后你找到一个新的一行。
  4. 检查此行的密钥,如果不是,请更新大小并转到2.
  5. 以下是示例代码:

    fp = open('your file')
    fp.seek(0, 2)
    begin = 0
    end = fp.tell()
    
    while (begin < end):
        fp.seek((end - begin) / 2, 0)
        fp.readline()
        line_key = get_key(fp.readline())
        if (key == line_key):
            pass # find what you want
        elif (key > line_key):
            begin = fp.tell()
        else:
            end = fp.tell()
    

    也许代码有bug。验证自己。如果你真的想要一个最快的方式,请检查性能。

答案 2 :(得分:1)

关于二进制搜索仅用于固定长度记录的引用问题的答案是错误的。而且您根本不需要进行搜索,因为您有多个要查找的项目。只需一次遍历整个文件一行,为每行构建一个key:offset字典,然后为每个搜索项跳转到感兴趣的记录,使用os.lseek对应的偏移量每把钥匙。

当然,如果您不想一次读取整个文件,则必须进行二分查找。但是,如果构建索引可以在多个查找中分摊,如果每天只进行一次查找,可能会保存索引,那么搜索是不必要的。