Уведомления

Группа в Telegram: @pythonsu

#1 Авг. 12, 2020 19:39:18

stratum
Зарегистрирован: 2019-04-30
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Бинарный поиск по большому файлу

Приветствую.

Перейду сразу к делу, есть очень большой текстовый файл (65ГБ) который содержит строки.
И мне нужно ускорить процесс поиска в этом файле, потому-что grep нужно ждать несколько минут.

Я уже вычитал что самым лучшим алгоритмом для моего обьема данных является бинарный поиск.
Но проблема в том, что я не знаю как его можно реализовать не загружая файл в память.
Помогите, может где-то видели рабочий код, или хотя-бы нерабочий но более менее документированный, что-бы можно было починить новичку вроде меня.

А то уже 2 часа потратил в поисках гугла и stackoverflow.

Единственcтвенный приближенный к рабочему код что я находил:
Но судя по xrange он написан под 2 питон. И у меня он не работает.
К тому-же я совсем не понимаю, как он должен работать

 import os
 
def line_binary_search(filename, matchvalue, key=lambda val: val):
    """
    Binary search a file for matching lines.
    Returns a list of matching lines.
    filename - path to file, passed to 'open'
    matchvalue - value to match
    key - function to extract comparison value from line
 
    >>> parser = lambda val: int(val.split('\t')[0].strip())
    >>> line_binary_search('sd-arc', 63889187, parser)
    ['63889187\t3592559\n', ...]
    """
 
    # Must be greater than the maximum length of any line.
 
    max_line_len = 2 ** 12
 
    start = pos = 0
    end = os.path.getsize(filename)
 
    with open(filename, 'rb') as fptr:
 
        # Limit the number of times we binary search.
 
        for rpt in xrange(50):
 
            last = pos
            pos = start + ((end - start) / 2)
            fptr.seek(pos)
 
            # Move the cursor to a newline boundary.
 
            fptr.readline()
 
            line = fptr.readline()
            linevalue = key(line)
 
            if linevalue == matchvalue or pos == last:
 
                # Seek back until we no longer have a match.
 
                while True:
                    fptr.seek(-max_line_len, 1)
                    fptr.readline()
                    if matchvalue != key(fptr.readline()):
                        break
 
               # Seek forward to the first match.
 
                for rpt in xrange(max_line_len):
                    line = fptr.readline()
                    linevalue = key(line)
                    if matchvalue == linevalue:
                        break
                else:
                    # No match was found.
 
                    return []
 
                results = []
 
                while linevalue == matchvalue:
                    results.append(line)
                    line = fptr.readline()
                    linevalue = key(line)
 
                return results
            elif linevalue < matchvalue:
                start = fptr.tell()
            else:
                assert linevalue > matchvalue
                end = fptr.tell()
        else:
            raise RuntimeError('binary search failed')

Отредактировано stratum (Авг. 12, 2020 19:40:32)

Офлайн

#2 Авг. 13, 2020 03:03:34

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9885
Репутация: +  853  -
Профиль   Отправить e-mail  

Бинарный поиск по большому файлу

stratum
Перейду сразу к делу, есть очень большой текстовый файл (65ГБ) который содержит строки.
И мне нужно ускорить процесс поиска в этом файле, потому-что grep нужно ждать несколько минут.
Нужно этот файл подготовить для поиска сначала. Для этого существует индексирование в той или иной форме. Ты строишь для него индекс несколько десятков минут, а потом ищешь по этому индексу очень быстро.

stratum
Я уже вычитал что самым лучшим алгоритмом для моего обьема данных является бинарный поиск.
Бинарный поиск требует отсортированности данных. Сортировать один раз такой файл ты будешь гораздо дольше, чем grep'ом по нему искать. При обновлении файла всё повторится сначала.

А быстрее grep'а ты ничего не напишешь, потому что этой программе столько лет, что там за все годы всё оптимизировано максимально.



Офлайн

#3 Авг. 13, 2020 19:22:51

stratum
Зарегистрирован: 2019-04-30
Сообщения: 9
Репутация: +  0  -
Профиль   Отправить e-mail  

Бинарный поиск по большому файлу

py.user.next
Само собой файл отсортирован, как иначе я собрался бы в нем использовать бинарный поиск? Файл обновляется раз в 2 недели, так-что пересортировывать его не проблема.

grep же просто итерируется по файлу. Я уже пересмотрел документацию, к grep и не нашел там бинарный поиск.

К тому-же, код который я приложил, судя по описанию когда-то работал, на 2 питоне.
Только я не могу понять, как именно, но файл там не индекированный подается на вход.

Офлайн

#4 Авг. 14, 2020 00:42:39

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  252  -
Профиль   Отправить e-mail  

Бинарный поиск по большому файлу

Поконкретнее как не работает и что непонятно. По идее xrange на range меняете и все. Ну и голова нужна чтобы функцию вызвать.

А вообще поступайте проще. суньте файл в sqlite и ищите запросами. Настоящие базы делают не бинарный поиск. Имеет смысл читать сразу большой кусок файла. Так растет вероятность массового засасывания нужных вам вещей.



Офлайн

#5 Авг. 14, 2020 00:47:39

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9885
Репутация: +  853  -
Профиль   Отправить e-mail  

Бинарный поиск по большому файлу

stratum
Файл обновляется раз в 2 недели, так-что пересортировывать его не проблема.
А если он чаще начнёт обновляться? Сегодня ты об этом не думаешь, а завтра это может стать для тебя сюрпризом. А потом эти файлы пойдут ещё не в количестве одного, а сотнями друг за другом. Ты не сможешь сортировать их просто физически. И вообще файл не надо сортировать, потому что дальше он понадобится в первоначальном виде, а у тебя он уже отсортирован и тебе нужно будет ещё исходник где-то держать в таком же размере. Поэтому строится отсортированный индекс, по которому ты потом и ищешь бинарным поиском.

stratum
Я уже пересмотрел документацию, к grep и не нашел там бинарный поиск.
Ты не сказал, что файл всегда отсортирован. Ты сказал “у меня есть огромный файл какой-то там произвольный и мне нужно кодом на питоне каким-нибудь волшебным искать быстрее, чем grep'ом на си”.

А у тебя, оказывается, файл-то отсортированный по строкам! А я забыл свои карты таро достать, разложить их и узнать об этом.

В отсортированном файле можно бинарным поиском пройти, но зачем это делать? Гарантия его отсортированности ничем не гарантируется. Вот я тебе говорю, у тебя просто к файлу нужно будет добавить одну строку или просто в одной строке файла исправить одну букву - и всё. Из-за этой маленькой правки ты должен будешь сразу пересортировывать весь файл от начала до конца. Тебе grep покажется чудесными минутами, проведёнными в жизни.

Так что либо ты его раскладываешь на раздельные куски и с ними можешь потом то же самое повторить в плане разложения, либо ты строишь индекс и ищешь потом по индексу.

stratum
К тому-же, код который я приложил, судя по описанию когда-то работал, на 2 питоне.
Только я не могу понять, как именно, но файл там не индекированный подается на вход.
Ну, он прыгает по файлу через прозвольный доступ, читает строки в бинарном режиме и сравнивает их. Но для этого нужно, чтобы файл отсортированным был. А у тебя файл 65 гигабайт и это не предел. Из того, что он у тебя сейчас один и на 65 гигабайт, не следует то, что завтра у тебя их не будет сто и каждый по 100 гигабайт. Так что вся твоя эта система накроется медным тазом.



Офлайн

#6 Авг. 14, 2020 13:43:39

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2757
Репутация: +  184  -
Профиль   Отправить e-mail  

Бинарный поиск по большому файлу

> Само собой файл отсортирован, как иначе я собрался бы в нем использовать бинарный поиск?

Он у тебя отсортирован по нужному признаку?

> Но проблема в том, что я не знаю как его можно реализовать не загружая файл в память.

Тебе ни надо ничего в память загружать.
1) Открываешь файл на чтение
2) Смотришь его размер и записываешь в переменную size (size = os.stat(“/path”).st_size)
3) Перемещаешься к середине файла (file.seek(size//2))
3) Считываешь одну строку и сдвигаешься на четверть размера
4) и т.д. в соответствии с алгоритмом



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Отредактировано Rodegast (Авг. 14, 2020 13:48:00)

Онлайн

#7 Авг. 19, 2020 18:47:18

ZerG
Зарегистрирован: 2012-04-05
Сообщения: 2627
Репутация: +  61  -
Профиль   Отправить e-mail  

Бинарный поиск по большому файлу

Я сомневаюсь что на питоне можно реализовать выборку быстрее грепа.
Не спорю - после загрузки - получить данные будет быстрее; Но общее время выполнения будет гораздо больше.

вот годное чтиво к осмыслению вашей задачи.
https://habr.com/ru/post/359284/



Влодение рускай арфаграфией - это как владение кунг-фу: настаящие мастира не преминяют ево бес ниабхадимости

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version