# $Id: Kekka.pm,v 3.0 1998/11/19 07:13:12 tsuchiya Exp $ # This file is part of IREX tools. # Please refer "Copyright file" at the root directory. # (C) IREX committee IREX実行委員会. All rights reserved. # TREC 検索結果リストを扱うための関数を定義したモジュール package TREC::Kekka; require 5.000; require Exporter; use Carp; use IREX::Common qw( @BUF %TREE ); @ISA = qw( Exporter ); @EXPORT_OK = qw( parser parse @BUF generator generate %TREE ); %EXPORT_TAGS = ( parser => [qw( parse @BUF )], generator => [qw( generate %TREE )] ); # @BUF に格納されているファイルを対象として構文解析を行う関数 # # 1行の形式が次のようになっているファイルを扱う。 # 0001 A 98093022 1 9999 203 # 各フィールドは \t によって区切られている。 # 第1フィールド = TOPIC-ID # 第2フィールド = ダミー # 第3フィールド = 文書番号 # 第4フィールド = Rank # 第5フィールド = Score # 第6フィールド = SYSTEM-ID # # TREC 結果提出ファイル中では、SYSTEM-ID として検索チームの略称 # と順序数の組み合わせとなっている。 sub parse { for( @BUF ){ /^(\d+)\t[^\t\r\n]+\t([^\t\r\n]+)\t(\d+)\t(\d+\.?\d*|\.\d+)\t(\w+)$/ or warn( "Can't parse line \"$_\"\n" ), return 0; $TREE{$1}->{$2}->{SYSTEM}->{$5} = sprintf( "",$5,$3,$4 ); } 1; } # 構文木 %TREE からデータを生成する関数 # # %TREE に格納されている IREX 結果統合ファイル形式のデータから、 # 引数によって指定された SYSTEM-ID を持つデータのみを抜き出し # て、TREC 結果提出ファイル形式に変換する関数 # # ただし、第5フィールドの Score は、IREX では必須のデータではな # いので、Rank などの情報から復元せざるを得ない。この場合、次の # ような優先順位で復元される。 # # (1) SIM= で指定された値 # # ただし、1つのシステムに関する情報が矛盾する事を避けるため、 # 対象となっているシステムの全ての SYSTEM タグに SIM= の項目が # 存在しなければならない。部分的に存在した場合は、その情報は失 # われる。 # # (2) SCORE= で指定された値 # # SIM= の場合と同様の制限を受ける。 # # (3) RANK= から復元 # # IREX では RANK が必須とされているので、この情報は確実に存在 # する。あるシステムの出力した結果の RANK が、 # RANK = { 1, 2, 3, 5, 6 } # となっていた場合、 # SCORE = { 5, 4, 3, 2, 1 } # と RANK の順序関係を逆転させた順序に SCORE を与える。すなわち、 # RANK の順序関係と矛盾しない SCORE が与えられることだけが保証 # される。 sub generate ( $ ) { my $sid = shift; for $topic_id ( sort keys %TREE ){ my( %rank, %sim, %score, $t ); my $use_sim = 1; my $use_score = 1; for $docno ( keys %{ $TREE{$topic_id} } ){ if( $t = $TREE{$topic_id}->{$docno}->{SYSTEM}->{$sid} ){ $t =~ /\sRANK=(\d+)[>\s]/ or warn( "Can't find rank in \"$t\"\n" ), return 0; $rank{$docno} = $1; if( $use_sim ){ if( $t =~ /\sSIM=(\d+\.?\d*|\.\d+)[>\s]/ ){ $sim{$docno} = $1; } else { $use_sim = 0; } } if( $use_score ){ if( $t =~ /\sSCORE=(\d+\.?\d*|\.\d+)[>\s]/ ){ $score{$docno} = $1; } else { $use_score = 0; } } } } if( $use_sim ){ # SIM を利用する場合 for $docno ( sort { $rank{$a}<=>$rank{$b}; } ( sort { $sim{$a}<=>$sim{$b}; } keys %rank ) ){ printf( "%s\t0\t%s\t%d\t%f\t%s\n", $topic_id, $docno, $rank{$docno}, $sim{$docno}, $sid ); } } elsif( $use_score ){ # SCORE を利用する場合 for $docno ( sort { $rank{$a}<=>$rank{$b}; } ( sort { $score{$a}<=>$score{$b}; } keys %rank ) ){ printf( "%s\t0\t%s\t%d\t%f\t%s\n", $topic_id, $docno, $rank{$docno}, $score{$docno}, $sid ); } } else { # RANK を利用する場合 my $i = keys %rank; for $docno ( sort { $rank{$a}<=>$rank{$b}; } keys %rank ){ printf( "%s\t0\t%s\t%d\t%d\t%s\n", $topic_id, $docno, $rank{$docno}, $i--, $sid ); } } } 1; } 1;