5

我正在做一个需要解析日志文件的项目。我正在寻找一种快速算法,可以接收这样的组消息:

P1 处的温度为 35F。

P1 处的温度为 40F。

P3 处的温度为 35F。

记录仪停止。

记录仪启动。

P1 处的温度为 40F。

并以 printf() 的形式输出一些东西:

"The temperature at P%d is %dF.", Int1, Int2" 
{(1,35), (1, 40), (3, 35), (1,40)}

该算法需要足够通用以识别消息组中的几乎所有数据负载。

我尝试搜索这种技术,但我什至不知道要搜索的正确术语。

4

10 回答 10

12

我认为您可能忽略并错过了 fscanf() 和 sscanf()。与 fprintf() 和 sprintf() 相反。

于 2008-08-13T14:28:26.397 回答
6

概述:

一个天真!算法以每列的方式跟踪单词的频率,其中可以假设每一行都可以用分隔符分隔成列。

示例输入:

狗跳过月亮
猫跳过月亮
月亮跳过月亮
汽车跳过月亮

频率:

Column 1: {The: 4}
Column 2: {car: 1, cat: 1, dog: 1, moon: 1}
Column 3: {jumped: 4}
Column 4: {over: 4}
Column 5: {the: 4}
Column 6: {moon: 4}

我们可以通过根据字段总数进行分组来进一步划分这些频率列表,但在这个简单方便的示例中,我们只使用固定数量的字段 (6)。

下一步是遍历生成这些频率列表的行,让我们以第一个示例为例。

  1. :符合一些手动标准,算法决定它必须是静态的。
  2. dog:根据频率列表的其余部分,它似乎不是静态的,因此它必须是动态的而不是静态文本。我们遍历一些预定义的正则表达式并提出/[a-z]+/i.
  3. over : 与#1 相同的交易;它是静态的,所以保持原样。
  4. : 与#1 相同的交易;它是静态的,所以保持原样。
  5. 月亮:与#1 相同的交易;它是静态的,所以保持原样。

因此,只要从第一行开始,我们就可以将以下正则表达式放在一起:

/The ([a-z]+?) jumps over the moon/

注意事项:

  • 显然,人们可以选择在第一遍扫描部分或整个文档,只要人们确信频率列表将是整个数据的充分采样。

  • 误报可能会蔓延到结果中,这将取决于过滤算法(挥手)来提供静态和动态字段之间的最佳阈值,或者一些人工后处理。

  • 总体思路可能不错,但实际实现肯定会影响该算法的速度和效率。

于 2008-08-15T16:45:12.813 回答
3

感谢所有伟大的建议。克里斯,是的。我正在寻找一种通用解决方案来规范任何类型的文本。该问题的解决方案归结为在两个或更多相似字符串中动态查找模式。几乎就像根据前两个预测集合中的下一个元素:

1:珠穆朗玛峰高30000英尺

2:K2 高 28000 英尺

=> 模式是什么?=> 答案:

[名称] 是 [数字] 英尺高

现在文本文件可以有数百万行和数千种模式。我想非常非常快地解析文件,找到模式并收集与每个模式关联的数据集。

我考虑过创建一些高级语义哈希来表示消息字符串中的模式。我会使用分词器并给每个令牌类型一个特定的“权重”。然后我将对哈希进行分组并评估它们的相似性。分组完成后,我将收集数据集。

我希望,我不必重新发明轮子,并且可以重复使用已经存在的东西。

克劳斯

于 2008-08-15T15:00:43.553 回答
2

这取决于您要做什么,如果您的目标是快速生成 sprintf() 输入,则此方法有效。如果您尝试解析数据,也许正则表达式也可以。

于 2008-08-13T15:52:09.300 回答
1

你不会找到一个工具,它可以简单地接受任意输入,猜测你想要从中得到什么数据,并产生你想要的输出。对我来说,这听起来像是强大的人工智能。

制作这样的东西,即使只是为了识别数字,也会变得非常棘手。例如“123.456”是一个数字还是两个?这个“123,456”怎么样?“35F”是十进制数字和“F”还是十六进制值0x35F?您将不得不构建一些能够以您需要的方式解析的东西。您可以使用正则表达式来执行此操作,也可以使用 来执行此操作sscanf,或者您可以通过其他方式执行此操作,但是您将不得不编写一些自定义的东西。

但是,使用基本的正则表达式,您可以自己执行此操作。这不会是魔法,但它不是那么多的工作。像这样的东西会解析你感兴趣的行并将它们合并(Perl):

my @vals = ();
while (defined(my $line = <>))
{
    if ($line =~ /The temperature at P(\d*) is (\d*)F./)
    {
        push(@vals, "($1,$2)");
    }
}
print "The temperature at P%d is %dF. {";
for (my $i = 0; $i < @vals; $i++)
{
    print $vals[$i];
    if ($i < @vals - 1)
    {
        print ",";
    }
}
print "}\n";

这个的输出是L

The temperature at P%d is %dF. {(1,35),(1,40),(3,35),(1,40)}

您可以为需要解析的每种类型的行做类似的事情。您甚至可以从文件中读取这些正则表达式,而不是对每个正则表达式进行自定义编码。

于 2008-08-14T02:25:16.637 回答
1

我不知道有什么特定的工具可以做到这一点。当我有类似的问题要解决时,我所做的是尝试猜测正则表达式以匹配行。

然后我处理了这些文件并只显示了不匹配的行。如果一行不匹配,则意味着模式错误,应该调整或添加另一个模式。

经过大约一个小时的工作,我成功地找到了大约 20 种模式来匹配 10000 多行。

在您的情况下,您可以首先“猜测”一个模式是"The temperature at P[1-3] is [0-9]{2}F.". 如果您重新处理删除任何匹配行的文件,它会留下“仅”:

记录仪停止。

记录仪启动。

然后你可以匹配它"Logger (.+)."

然后,您可以优化模式并找到新的模式以匹配您的整个日志。

于 2008-08-15T15:32:17.873 回答
0

@John:我认为这个问题与一种算法有关,该算法实际识别日志文件中的模式并自动“猜测”适当的格式字符串和数据。*scanf家庭无法独自做到这一点,只有在首先识别出模式后才能提供帮助。

于 2008-08-14T02:01:34.000 回答
0

@Derek Park:好吧,即使是强大的人工智能也不能确定它有正确的答案。

也许可以使用一些类似压缩的机制:

  1. 查找大而频繁的子串
  2. 查找大而频繁的子字符串模式。(即[模式:1] [垃圾] [模式:2])

另一个要考虑的项目可能是按edit-distance对行进行分组。将相似的行分组应该将问题分成每组一个模式的块。

实际上,如果你能写出这个,让全世界都知道,我想我们很多人都会喜欢这个工具!

于 2008-08-15T18:01:45.187 回答
0

@安德斯

好吧,即使是强大的人工智能也无法确定它是否有正确的答案。

我在想足够强大的人工智能通常可以从上下文中找出正确的答案。例如,强人工智能可以识别出“35F”在这种情况下是一个温度,而不是一个十六进制数。在某些情况下,即使是强大的 AI 也无法回答。但是,这些情况与人类无法回答的情况相同(假设人工智能非常强大)。

当然,这并不重要,因为我们没有强大的人工智能。:)

于 2008-08-15T18:11:42.263 回答
0

http://www.logparser.com转发到一个似乎相当活跃的 IIS 论坛。这是 Gabriele Giuseppini 的“Log Parser Toolkit”的官方网站。虽然我从未真正使用过这个工具,但我确实从亚马逊市场买了一本便宜的书——今天一本低至 16 美元。没有什么能比只翻阅页面的死树界面更好的了。

浏览这个论坛,我以前没有听说过http://www.lizardl.com/上的“MS Log Parser,Log Parser Lizard 的新 GUI 工具” 。

当然,关键问题是语法的复杂性。要使用该术语常用的任何类型的日志解析器,您需要确切地知道要扫描的内容,您可以为其编写 BNF。很多年前,我参加了基于 Aho-and-Ullman 的“龙之书”的课程,而深入了解的 LALR 技术可以为您提供最佳速度,当然前提是您拥有该 CFG。

另一方面,您似乎确实可能正在寻找类似 AI 的东西,这完全是一种不同的复杂性顺序。

于 2008-09-23T04:33:19.750 回答