Perl 根据更新的时间和严重性获取记录
我有一些事件数据,我只需要根据事件的更新时间打印关于单个事件的单个数据 我将所有数据保存在数组的散列中,从中我需要从每个具有最新更新时间的事件中提取一条记录 以下是脚本:Perl 根据更新的时间和严重性获取记录,perl,Perl,我有一些事件数据,我只需要根据事件的更新时间打印关于单个事件的单个数据 我将所有数据保存在数组的散列中,从中我需要从每个具有最新更新时间的事件中提取一条记录 以下是脚本: use strict; use warnings; my %data = ( '1342' => [ { 'Severity' => 'MEDIUM',
use strict;
use warnings;
my %data = (
'1342' => [
{
'Severity' => 'MEDIUM',
'Node' => 'Node002',
'State' => 'ACTIVE_UNACKNOWLEDGED',
'Updated' => '2020-10-01T12:00:00',
'eventId' => '1342'
},
{
'Severity' => 'HIGH',
'Node' => 'Node002',
'Updated' => '2020-10-01T12:05:00',
'eventId' => '1342',
'State' => 'ACTIVE_UNACKNOWLEDGED'
}
],
'1341' => [
{
'State' => 'ACTIVE_UNACKNOWLEDGED',
'eventId' => '1341',
'Updated' => '2020-10-01T12:10:00',
'Node' => 'Node001',
'Severity' => 'HIGH'
},
{
'State' => 'ACTIVE_UNACKNOWLEDGED',
'Updated' => '2020-10-01T12:15:00',
'eventId' => '1341',
'Severity' => 'HIGH',
'Node' => 'Node001'
},
{
'State' => 'CLEARED_ACKNOWLEDGED',
'Updated' => '2020-10-01T12:15:00',
'eventId' => '1341',
'Severity' => 'CLEARED',
'Node' => 'Node001'
}
]
);
foreach my $id ( sort keys %data ){
print "Event: $id\n";
foreach my $record( sort { $b->{Updated} cmp $a->{Updated} } @{ $data{$id} }) {
print "\t";
print "$record->{Node},$record->{Severity},$record->{State},$record->{Updated}";
print "\n";
last;
}
}
电流输出:
Event: 1341
Node001,HIGH,ACTIVE_UNACKNOWLEDGED,2020-10-01T12:15:00
Event: 1342
Node002,HIGH,ACTIVE_UNACKNOWLEDGED,2020-10-01T12:05:00
Event: 1341
Node001,CLEARED,CLEARED_ACKNOWLEDGED,2020-10-01T12:15:00
Event: 1342
Node002,HIGH,ACTIVE_UNACKNOWLEDGED,2020-10-01T12:05:00
预期输出:
Event: 1341
Node001,HIGH,ACTIVE_UNACKNOWLEDGED,2020-10-01T12:15:00
Event: 1342
Node002,HIGH,ACTIVE_UNACKNOWLEDGED,2020-10-01T12:05:00
Event: 1341
Node001,CLEARED,CLEARED_ACKNOWLEDGED,2020-10-01T12:15:00
Event: 1342
Node002,HIGH,ACTIVE_UNACKNOWLEDGED,2020-10-01T12:05:00
如果特定事件对于不同的严重性具有相同的更新时间,则应选择已清除严重性的记录
在上述情况下,我们可以看到对于EventID
1341
有清除的和高的严重性同时存在,即2020-10-01T12:15:00
。
因此,我应该选择清除的
严重性记录,而不是高
严重性记录。如何选择该记录?迭代数据结构中的每个级别,以便能够根据需要进行比较
foreach my $ev (sort keys %data) {
my $ra = $data{$ev};
my $fmt = "%Y-%m-%dT%T";
# Initialize "best" time and its hashref
my $hr = $ra->[0];
my $dt = Time::Piece->strptime($hr->{Updated}, $fmt);
foreach my $idx (1..$#$ra) {
my $dt_curr = Time::Piece->strptime(
$ra->[$idx]{Updated}, $fmt
);
if ($dt_curr > $dt) {
$dt = $dt_curr;
$hr = $ra->[$idx];
}
elsif ($dt_curr == $dt) {
if ($ra->[$idx]{Severity} eq 'CLEARED') {
$dt = $dt_curr;
$hr = $ra->[$idx];
}
}
}
say "Event: $hr->{eventId}";
say "\t", join ',',
map { $hr->{$_} } qw(Node Severity State Updated);
# Or rather, as clarified in a comment
#say join ','
# map { $hr->{$_} } qw(eventId Node Severity State Updated);
}
使用提供的%数据
,为了可读性而省略,这将打印预期结果。†
我假设数据结构中还没有更深层次的内容,所以我只复制hashref,否则它们应该被克隆(深度复制)
显示的时间戳(%Y-%m-%dT%T
)可以直接按字典形式作为字符串进行比较($dt1 gt$dt2
),但我仍然使用了日期-时间模块,因为如果使用了不同的时间戳格式,它很容易调整
为了提高效率,可以对代码进行调整。(这也取决于数据细节。)
出现了一个问题:如果没有Time::Piece
(或者我使用的任何库),如何实现它,因为它在该安装中不可用。关于如何使用这种(残废的)工具,请看我的评论,但这里有一个简单的方法。(这也更快。)
分隔符的split
参数是一个正则表达式。当字符类[-T://code>中的字符在字符串中匹配(按给定顺序尝试)时,字符串将在其上拆分。它们的顺序与时间戳相同,因此split
返回:年、月、日、小时、分钟、秒
有了这样一个每个时间戳的列表,我们可以通过按顺序比较组件(比较年份,然后是月份,…)来清楚地比较它们的日期时间
但是,使用Time::Local
(已确认安装),您可以通过使用timelocal
获取自epoch以来的秒数并进行比较,从而避免编写冗长(且容易出错)的代码来比较组件
use Time::Local;
# parse timestamps to get yr, mon, ... for each
my $dt1 = timelocal($sec1, $min1, $hour1, $mday1, $mon1, $yr1);
my $dt2 = ...
if ($dt1 > $dt2) { ... }
总之,通过一次基本的健康检查
sub ts_to_epoch {
my ($timestamp) = @_;
# For format year-mon-dayThour:minute:second
my @dt_parts = split /[-T:]/, $timestamp;
die "Parsing of '$timestamp' failed" if @dt_parts != 6;
return timelocal( reverse @dt_parts );
}
my $epoch_1 = ts_to_epoch($timestamp1);
...
如果您需要从epoch之后的几秒钟中检索时间戳,那么使用有限的工具集的一种方法是使用localtime($epoch)
†最后一行代码(注释掉)按所需顺序打印,按该顺序列出键。但如果这出现在代码中的许多地方,那么我们就会有分散的硬编码密钥列表;当添加或重命名另一个键时会发生什么?我们必须搜捕所有这些地方
相反,在一个辅助散列中拼写出顺序
# One place in code where the hard-coded order is given
my %sort_by = do {
my @keys = qw(eventId Node Severity State Updated);
map { $keys[$_] => $_ } 0..$#keys;
};
现在通过使用键
获取键,然后对它们进行排序来打印
say join ',',
map { $hr->{$_} }
sort { $sort_by{$a} <=> $sort_by{$b} }
keys %$hr;
说连接',',
映射{$hr->{$}
排序{$sort_by{$a}$sort_by{$b}
密钥%$hr;
因此,%sort\u by
在代码中的一个位置给出(并保持不变!),并且打印语句不使用任何特定的硬编码数据。OP代码中的一个小更改会产生所需的结果
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my %data = (
'1342' => [
{
'Severity' => 'MEDIUM',
'Node' => 'Node002',
'State' => 'ACTIVE_UNACKNOWLEDGED',
'Updated' => '2020-10-01T12:00:00',
'eventId' => '1342'
},
{
'Severity' => 'HIGH',
'Node' => 'Node002',
'Updated' => '2020-10-01T12:05:00',
'eventId' => '1342',
'State' => 'ACTIVE_UNACKNOWLEDGED'
}
],
'1341' => [
{
'State' => 'ACTIVE_UNACKNOWLEDGED',
'eventId' => '1341',
'Updated' => '2020-10-01T12:10:00',
'Node' => 'Node001',
'Severity' => 'HIGH'
},
{
'State' => 'ACTIVE_UNACKNOWLEDGED',
'Updated' => '2020-10-01T12:15:00',
'eventId' => '1341',
'Severity' => 'HIGH',
'Node' => 'Node001'
},
{
'State' => 'CLEARED_ACKNOWLEDGED',
'Updated' => '2020-10-01T12:15:00',
'eventId' => '1341',
'Severity' => 'CLEARED',
'Node' => 'Node001'
}
]
);
foreach my $id ( sort keys %data ){
print "Event: $id\n";
my $found;
for( @{$data{$id}} ) {
$found = $_ unless defined $found;
if( $_->{Updated} eq $found->{Updated} ) {
$found = $_ if $_->{Severity} eq 'CLEARED';
}
$found = $_ if $_->{Updated} ge $found->{Updated};
}
say "\t" . join ',', $found->@{qw/Node Severity State Updated/};
}
输出
Event: 1341
Node001,CLEARED,CLEARED_ACKNOWLEDGED,2020-10-01T12:15:00
Event: 1342
Node002,HIGH,ACTIVE_UNACKNOWLEDGED,2020-10-01T12:05:00
这将产生预期的结果。在这里,我使用的是perl5.10
,安装量很小,没有核心模块。Perl 5.10最小安装附带的Time::Piece
Perl模块是否有任何可能性/替代方案。@vkk05如果不能使用库,则必须编写代码来解析日期时间字符串,并逐段进行比较。(正如我在回答中所指出的,在这个问题中,使用时间戳,您可以按字典顺序将它们作为字符串进行比较。但是通过注释中的问题,我假设格式确实不一定如图所示,并且您希望将其视为datetime。如果您不能使用ready库,那么您必须为此编写自己的代码。)@vkk05甚至不能使用核心模块,这是一个有点不可能的困境。主要计算环境中的工具是结构化和组织的,良好的功能块是通过设计(通常是必要的)在模块/库中实现的。如果你不能使用这些工具,那么你就是在使用一个残废的工具,你必须自己实现一些功能。这可能没问题(通常情况下,当您在一个已编译的脚本语言中寻求方便的时候!),比较两个日期很简单。但是,祝你在没有图书馆的情况下上网或使用数据库时好运。@vkk05我不是要批评你或诸如此类的人,只是说如果你使用一种语言的有限工具集,你应该会遇到一些困难。相关:谢谢@Polar Bear。逻辑看起来简单而有趣,我得到了预期的输出。但是使用ge
操作符进行时间比较可以吗?@vkk05您的ISO时间戳具有非常有趣的特性,可以按顺序进行排序。YYYY-MM-DD
格式远远优于本地化格式,如DD.MM.YYYY
或MM/DD/YYYY
,因为它基本上是以正确的顺序内置的,就像在查看以日期命名的文件夹时一样。T
总是相同的,并且HH:MM:SS
字符串总是按照预期的方式排序。是的,你可以用一个更大的字符串来表示。无需解析。@vkk05——在这种特殊情况下,使用的截止日期格式ge
运算符是适用的。如果日期格式不同,那么您必须对其进行一些操作,使其可排序,而无需借助某些模块进行解析