У меня есть большой текстовый файл (от 5 до 10 миллионов строк). Каждая строка содержит от 10 до 5 000 буквенно-цифровых элементов, отделенных друг от друга пробелом или запятой. Каждая строка заканчивается разрывом строки. Количество строк известно до выполнения, и текстовый файл не изменяется во время выполнения.
Каждый раз при запуске кода в него передается 50-200 списков поиска, каждый из которых содержит 2-10 элементов (слов). Для каждого из этих списков поиска я хотел бы найти x количество строк в текстовом файле, который содержит хотя бы один элемент из этого списка strong >. Количество строк x варьируется от 5 до 10 строк и устанавливается во время выполнения. Соответствие регистронезависимо и должно быть точным на границе слова (например, «foo» соответствует «, foo», но не «foobar»).
В каждом списке поиска есть одна из трех стратегий порядка поиска:
Нормально. Начните с первой строки, ищите построчно в последовательном порядке, пока не найдет x количество строк или не дойдет до последней строки.
Случайно. Выбирайте строки из текстового файла случайным образом. Продолжайте, пока он не найдет x количество строк или не завершит поиск каждой строки.
Диапазон ковша. Сначала найдите диапазон строк с наивысшим приоритетом, затем следующий диапазон строк с наивысшим приоритетом, затем следующий и т. Д. Например, приоритет диапазона поиска может заключаться в том, чтобы сначала просмотреть строки от 1000000 до 1499999, затем строки от 0 до 999999, затем строки От 1 500 000 до 2 199 999 и т. Д. Может быть от 3 до 20 сегментов, каждая из которых охватывает диапазон от 100 000 до 5 000 000 строк. Количество сегментов и диапазоны номеров строк указываются во время выполнения. Последовательный поиск в каждом диапазоне. Ищите, пока не найдет x количество строк или не дойдет до конца последнего сегмента.
Вот что я написал для «обычного поиска» [этот тестовый код проверяет все строки до конца файла без остановки после x строк; в окончательной версии после того, как он найдет x совпадений для списка поиска, он остановится и перейдет к следующему списку поиска]:
import re
textFile = "bigTextFile.txt"
searchItems = ["foo","bar","anotherfoo","anotherbar","etc"]
searchStrategy = "normal" #could be "normal", "random", "bucket"; this code is just for "normal"
results = []
with open(textFile) as inFile:
for line in inFile:
regex = re.compile('(' + '|'.join('\\b'+item+'\\b' for item in searchItems) +')', re.IGNORECASE)
match = regex.search(line)
if match is not None:
analysisResult = analyze_the_match(line)
results.append(analysisResult)
Этот код для "обычного поиска" работает. Из того, что я пробовал, он кажется самым быстрым, но я новичок в Python и думаю, что должен быть лучший способ (скорость / эффективность) сделать это.
[Обновите в ответ на комментарии, чтобы лучше объяснить причину использования разных стратегий поиска]. Элементы сильно перекошены. Играя с данными, я обнаружил, что примерно половина поисков завершится до 10 000 строк, 40% может занять несколько миллионов строк, чтобы найти достаточное количество совпадений, а 10% не найдут достаточного количества совпадений во всем текстовом файле. Элементы в каждой строке не имеют отношения к строке, в которой они находятся, но диапазоны строк похожи (т. Е. Строки 100 000–500 000 связаны, 1 500 000–1750 000 связаны и т. Д.). Код можно запускать много раз для заданного списка поиска, и для каждого запуска приоритет может заключаться в том, чтобы сосредоточиться на другом диапазоне строк. Если весь текстовый файл содержит только x строк с элементами в определенном списке поиска, то результатом всегда будут эти строки x. Но для многих списков поиска есть строки 2x, 10x или 100 000x, которые совпадают, и в разное время я бы хотел выберите разные строки. В определенные моменты приоритетом может быть конкретный диапазон, в других случаях лучше всего использовать случайную выборку, а иногда достаточно просто найти первые строки x с самого начала, следовательно, "нормальный", "случайный" и стратегии поиска "ведра".
Я был бы очень признателен за любые идеи для «случайного» и «ведро», так как я не уверен, как лучше всего подойти к ним эффективно. Я поигрался с linecache
, _ 3_, readlines
(за @Martin Thoma в этот ответ, readlines
на удивление быстро), а также изменение приведенного выше кода, но все мои попытки «случайного» и «ведро» неуклюжи, неэффективны и Я знаю, что не знаю достаточно, чтобы знать, что может быть лучше :).
Какие-либо предложения? Спасибо.
re.compile('\\b(' + '|'.join(item for item in searchItems) +')\b', re.IGNORECASE)
. Это улучшит производительность RE (и избавится от некоторой конкатенации строк в цикле;) - person SamWhan   schedule 20.04.2016