2013-06-05 4 views
0

У меня есть пользовательский ввод в список элементов, которые он хотел бы отфильтровать. Оттуда фильтры с помощью:Фильтровать массивные файлы журнала Linux

while knownIssuesCounter != len(newLogFile): 
    for line in knownIssues: 
     if line in newLogFile[knownIssuesCounter]: 
      if line not in issuesFound: 
       issuesFoundCounter[line]=1 
       issuesFound.append(line) 
       issuesFound.append(knownIssues[line]) 
      else: 
       issuesFoundCounter[line]=issuesFoundCounter[line] + 1 
    knownIssuesCounter +=1 

Я бегу в сотни лог-файлов мег и принимает НАВСЕГДА ..... Есть ли лучший способ делать это с помощью Python?

+1

Почему вы не с помощью встроенного Linux команд? Что-то с небольшим количеством grep, awk и wc magic? – Ben

+0

С моей работой мы работаем над МНОГИМ многих журналов linux.Был надеяться, что сможет отфильтровать определенные группы информации в зависимости от характера проблемы, а затем передать отфильтрованные журналы в нижние команды, которые не так хороши с grep и т. Д. – user1678432

+0

Как побочное примечание, итерация с явными счетчиками, как это делает ваш код труднее читать. Почему не просто 'for newLogLine в newLogFile:' для внешнего цикла? – abarnert

ответ

1

Попробуйте изменить issuesFound из списка, чтобы установить:

issuesFound = set() 

и использовать add вместо append:

issuesFound.add(line) 
+0

Я думаю, что он хочет список 'issuesFound' (который содержит как' line', так и 'knownIssues [line]', и порядок может быть важен), но он _also_ хочет, чтобы 'set' выполнял быструю проверку, если уже видел ». – abarnert

0

Большая часть причины, ваш код настолько медленно, что if line not in issuesFound:. Это требует линейного поиска через огромный список.

Вы можете исправить это, добавив set замеченных проблем (которые можно эффективно искать). Это сокращает время от O (NM) до O (N).

На самом деле, вы можете сделать это еще проще, полностью удалив if.

Во-первых, вы можете сгенерировать список issuesFound после факта с помощью ключей от issuesFoundCounter. Для каждой строки в issuesFoundCounter вы хотите эту строку, а затем ее knownIssues[line]. Итак:

issuesFound = list(flatten((line, knownIssues[line]) for line in issuesFoundCounter)) 

(. Я использую flatten рецепт от itertools документов Вы можете скопировать это в ваш код, или вы можете просто написать это с itertools.chain.from_iterable вместо flatten.)

и это означает, вы можете просто найти if line not in issuesFoundCounter: вместо in issuesFound:, который уже является dict (и, следовательно, его эффективно искать). Но если вы просто используете setdefault -или, еще проще, используйте defaultdict или Counter вместо dict - вы можете сделать это автоматически.

Так что, если issuesFoundCounter является Counter, все это сводится к этому:

for newLogLine in newLogFile: 
    for line in knownIssues: 
     if line in newLogLine: 
      issuesFoundCounter[line] += 1 

И вы можете превратить это в выражение генератора, устраняя медленный иш явного зацикливания в Python с более быстрым зацикливанием внутри интерпретатор. Это только будет, скажем, фиксированный 5: 1 убыстрение, в отличие от ускорения линейной к постоянной от первой половины, но это все-таки стоит задуматься:

issuesFoundCounter = collections.Counter(line 
             for newLogLine in newLogFile 
             for line in knownIssues 
             if line in newLogLine) 

Единственная проблема с этим что список issuesFound теперь находится в произвольном порядке, а не в порядке обнаружения проблем. Если это важно, просто используйте OrderedCounter вместо Counter. Там простой рецепт в collections документы, но для случая, это может быть столь же просто, как:

class OrderedCounter(Counter, OrderedDict): 
    pass 
+0

Просто хочу сказать, что я полностью решил это: – user1678432

+0

Любая проблема, которая может быть решена целиком с пустым пространством между комментарием и сигнатурой, является хорошей проблемой. :) – abarnert

Смежные вопросы