在文件中突出显示的行,但不完全相同

时间:2009-04-20 19:30:37

标签: python algorithm unix grep nlp

我正在梳理一个webapp的日志文件,以查找突出的语句。

大多数线条相似且无趣。我会通过Unix uniq传递它们,但是没有过滤,因为所有行都略有不同:它们都有不同的时间戳,类似的语句可能会打印不同的用户ID等。

有什么方法和/或工具可以获得与其他线条明显不同的线条? (但是,再次,不是精确的重复)

我正在考虑使用Python的difflib,但这似乎是为了区分两个文件,而不是同一个文件中的所有线对。

[编辑]

我认为解决方案会为每一行提供唯一性分数。因此,通过“显着不同”,我选择一个阈值,唯一性分数必须超过输出中包含的任何行。

基于此,如果还有其他可行的方法来定义它,请讨论。此外,该方法不必具有100%的准确性和召回率。

[/编辑]

示例:

我更喜欢尽可能通用的答案。我知道我可以在开头删除时间戳。剥离结束更具挑战性,因为它的语言可能绝对不同于文件中的任何其他内容。这些细节是我之前从具体例子中回避的原因,但是因为有些人问过......

类似1:

2009-04-20 00:03:57 INFO  com.foo.Bar - URL:/graph?id=1234
2009-04-20 00:04:02 INFO  com.foo.Bar - URL:/graph?id=asdfghjk

类似2:

2009-04-20 00:05:59 INFO  com.baz.abc.Accessor - Cache /path/to/some/dir hits: 3466 / 16534, 0.102818% misses
2009-04-20 00:06:00 INFO  com.baz.abc.Accessor - Cache /path/to/some/different/dir hits: 4352685 / 271315, 0.004423% misses

不同的1:

2009-04-20 00:03:57 INFO  com.foo.Bar - URL:/graph?id=1234
2009-04-20 00:05:59 INFO  com.baz.abc.Accessor - Cache /path/to/some/dir hits: 3466 / 16534, 0.102818% misses

在不同的情况下,我想要返回两行,但不喜欢其他行。换句话说,那两行是不同的类型(之后我可以只询问统计上罕见的线型)。一方面,这两者之间的编辑距离要大得多。

6 个答案:

答案 0 :(得分:3)

定义“明显不同”。然后看看"edit distance" measures

答案 1 :(得分:2)

您可以尝试一些计算单词的代码,然后按那些具有最少常用单词的行排序。

如果这不起作用,您可以添加一些智能来过滤掉时间戳和数字。

您的问题类似于generating summaries of news stories上的早期问题。

答案 2 :(得分:2)

我不知道一个适合你的工具,但是如果要自己推出,我就会这样做:

据推测,原木线结构清晰,不是吗?所以

  • 解析该结构上的行
  • 编写了许多非常基本的相关过滤器(仅从解析后的结构中返回一个简单数字的函数)
  • 通过一组过滤器运行已解析的行,并根据总分
  • 进行剪切
  • 可能会通过更多过滤器
  • 的结果将剩余的行分类到各个分箱中
  • 生成报告,转储文件或其他输出

如果您熟悉unix工具procmail,我建议为您的数据量身定制类似的处理。


正如评论中的zacherates说明,您的过滤器通常会忽略时间戳(可能还有IP地址),只关注内容:例如真正长的http请求可能代表攻击。 。或任何适用于您的域名的内容。

您的分箱过滤器可能与几个选定字段上的哈希一样简单,或者您可能尝试对Charlie Martin's suggestion执行某些操作并使用编辑距离度量。

答案 3 :(得分:1)

也许你可以对“单词相同”/“所有单词”进行基本计算?

e.g。 (包括一个偏移量,允许你忽略时间戳和单词'INFO',如果它总是相同的话):

def score(s1, s2, offset=26):
    words1 = re.findall('\w+', s1[offset:])
    words2 = re.findall('\w+', s2[offset:])
    return float(len(set(words1) & set(words2)))/max(len(set(words1)), len(set(words2)))

假设:

>>> s1
'2009-04-20 00:03:57 INFO  com.foo.Bar - URL:/graph?id=1234'
>>> s2
'2009-04-20 00:04:02 INFO  com.foo.Bar - URL:/graph?id=asdfghjk'
>>> s3
'2009-04-20 00:05:59 INFO  com.baz.abc.Accessor - Cache /path/to/some/dir hits: 3466 / 16534, 0.102818% misses'
>>> s4
'2009-04-20 00:06:00 INFO  com.baz.abc.Accessor - Cache /path/to/some/different/dir hits: 4352685 / 271315, 0.004423% misses'

这会产生:

>>> score(s1,s2)
0.8571428571428571
>>> score(s3,s4)
0.75
>>> score(s1,s3)
0.066666666666666666

您仍然需要决定要比较哪些行。此外,使用set()可能会略微扭曲分数 - 一个简单算法的价格: - )

答案 4 :(得分:0)

我想知道你是否可以专注于为你定义唯一性的部分。在这种情况下,似乎定义唯一性的部分只是中间部分:

2009-04-20 00:03:57 INFO  com.foo.Bar - URL:/graph?id=1234
                    ^---------------------^ 

2009-04-20 00:05:59 INFO  com.baz.abc.Accessor - Cache /path/to/some/dir hits: 3466 / 16534, 0.102818% misses
                    ^--------------------------------^

然后我会比较这个部分,也许是使用正则表达式(只是带括号的组;如何访问像这样的子匹配依赖于语言):

/^.{20}(\w+\s+[\w\.-]+\s+-\s+\w+)/

答案 5 :(得分:0)

我认为您希望将其分解为字段,按“严重性级别”字段和下一个字段(看起来像“类”)排序。我会用Haskell:

module Main where 
import Data.List (nubBy, sortBy)

sortAndNub s = nubBy fields2and3 
     $ sortBy fields2and3comp
     $ map words $ lines s

fields2and3 a b =    fieldEq 2 a b 
                  && fieldEq 3 a b
fieldEq f a b = a!!f == (b!!f)
fields2and3comp a b = case compare (a!!2) (b!!2) of
   LT -> LT
   GT -> GT
   EQ -> compare (a!!3) (b!!3)
main = interact $ unlines.(map unwords).sortAndNub