今回は前回に引き続いて、
プロパティ最適化のポイント
ここで、
- 検索対象の文書データのプロパティごとの分布を調べる。
- 部分検索式の検索結果がどの程度のヒット結果集合になるかを考察する。
- 部分検索式を求めるために、
少ないヒット結果集合を使って表現できないかを考える。
検索対象の文書データのプロパティごとの分布を調べるのは、
部分検索式の検索結果がどの程度のヒット結果集合になるかを考察するには、
部分検索式を求めるために、AND [ public_
の部分をNOT [ public_
のように書き換えた作業に相当します。
では、
インデックス済み文書数 | 100万件 |
グループ番号10の文書 | 95万件 |
公開フラグ0 | 4万件 |
公開フラグ1 | 96万件 |
"地磁気センサー"を含む | 400件 |
[ group_num = "10" ] NOT [ public_flag = "0" ]
の部分検索では次のような集合演算が見込まれます。
95万件のヒット結果集合 NOT 4万件のヒット結果集合
ここは、
グループ番号10の文書が多いという分布は、
("地磁気センサー" NOT [ group_num < "10" > "10" ]) NOT [ public_flag = "0" ]
それぞれの部分検索式のヒット結果集合の件数は次の通りです。
"地磁気センサー" ← 400件のヒット結果集合
[ group_num < "10" > "10" ] ← 5万件のヒット結果集合
[ public_flag = "0" ] ← 4万件のヒット結果集合
論理演算部分の演算量は、("地磁気センサー" NOT [ group_
が400×5万=2000万回、
検索エンジン側のプロパティ検索の最適化
プロパティ検索式の最適化は特定プロパティの分布を利用する手法です。したがってプロパティの値が均等に分布している場合には最適化の手がかりが得られないことになります。先の例では公開と非公開が50万件ずつの分布だった場合、
FINDSPOTの内部は、[ group_
のような検索式を、[ group_
と[ public_
の部分検索式を別々にSQLの書誌データベース対して問い合わせを行っていました。必然的に部分検索式の実行結果をSQLの書誌データベースから取り出す処理が、
連続するプロパティ検索の一括処理
そこでFINDSPOTの内部処理を変更し、
現在のFINDSPOTでは、
ただし最適化の対象となるのは、
論理演算の最適化
もう1つFINDSPOTの内部処理で、
FINDSPOTの1つの文書に対する検索結果は、
1つの文書に対する検索結果
- 文書ID
- 文中での検索語の出現位置
- 文中での出現回数
- 検索結果のソート用のキー情報
(複数)
なお、
この4つの情報を1要素として、
まず、
たとえば、
ヒット結果集合 | 文書ID |
---|---|
A | 1, 4, 6, 12 |
B | 2, 3, 4, 5, 6 |
「A AND B」
このAND演算のアルゴリズムをPerlで表現してみましょう
my @a = ( 1, 4, 6, 12 ); ← ヒット結果集合A
my @b = ( 2, 3, 4, 5, 6 ); ← ヒット結果集合B
my @ans;
foreach my $unit_a (@a)
{
foreach my $unit_b (@b)
{
if ($unit_a == $unit_b)
{
push @ans, $unit_a;
}
}
}
foreach my $x (@ans)
{
print "$x\n";
}
リスト1内のif文の箇所は、O(MN)
の計算量が必要になります。この例では、
一般に集合は順序を持っていませんが、
my @a = ( 1, 4, 6, 12 );
my @b = ( 2, 3, 4, 5, 6 );
my @ans;
foreach my $unit_a (@a)
{
my $match = bsearch($unit_a, \@b);
if ($match != -1)
{
push @ans, $unit_a;
}
}
foreach my $x (@ans)
{
print "$x\n";
}
sub bsearch($)
{
my ($unit, $ref_list) = @_;
my @list = @$ref_list;
return bsearch_x($unit, 0, $#list, $ref_list);
}
sub bsearch_x($)
{
my ($unit, $from, $to, $ref_list) = @_;
my @list = @$ref_list;
if ($from > $to)
{
return -1;
}
my $pos = int(($from + $to) / 2);
my $x = $list[$pos] - $unit;
if ($x == 0)
{
return $unit;
}
elsif ($x > 0)
{
return bsearch_x($unit, $from, $pos - 1, $ref_list);
}
else
{
return bsearch_x($unit, $pos + 1, $to, $ref_list);
}
}
この工夫で、O(M log 2 N)
と遙かに少ない演算で同じ結果が得られます。Mが4個、
FINDSPOTの初期実装では、