転置インデックスとtop k-query
DESCRIPTION
転置インデックスから上位k件を取得する方法についてTRANSCRIPT
坪坂正志
mail : m.tsubosaka(at)gmail(dot)com
今回の話の概要
転置インデックスに対してdisjunctiveなクエリで問い合わせを行った際に上位k件を取ってくるためのDAAT(Document-at-a-time)
ベースの効率的な手法について紹介する
ようするに
大規模な文章セットに対する”watch OR iwc
OR rolex”というクエリに関連度の高い文章を高速に持ってきたい
話の流れ
転置インデックスについて
TAAT, DAAT
Top-k Query
max-score
inteval-based prunning
other method
○ wand
○ layered-index
転置インデックスとは
単語がどの文章に出現するかを格納した索引構造
例えば下の構造から”iwc”が含まれる文章は文章1,5
の2つであることが分かる
また単語に紐づいてるリストを転置リストと呼ぶ
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
転置インデックスの利点
全体の文章に対してはるかに少ない量のリストを見るだけでよい
例えば英語版Wikipediaの記事は約397万あるが、そのうちiwcが含まれる記事は284件
ANDやORなどの論理演算が含まれるクエリと相性が良い
代表的なクエリのタイプ
AND検索 (Conjunctive query)
クエリ𝑄 = (𝑞1, … , 𝑞𝑁)が与えられた時に全ての𝑞𝑖が含まれる文章を返す
例 : 𝑄 = (𝑤𝑎𝑡𝑐ℎ, 𝑖𝑤𝑐, 𝑟𝑜𝑙𝑒𝑥)ならば”watch”, “iwc”, “rolex”全てが含まれる文章を返す
OR検索 (Disjunctive query)
クエリ𝑄 = (𝑞1, … , 𝑞𝑁)が与えられた時に𝑞𝑖のいずれかが含まれる文章を返す
例 : 𝑄 = (𝑤𝑎𝑡𝑐ℎ, 𝑖𝑤𝑐, 𝑟𝑜𝑙𝑒𝑥)ならば”watch”, “iwc”, “rolex”いずれかが含まれる文章を返す
ANDクエリとORクエリ
一般にANDクエリとORクエリの場合ANDクエリの方が高速
また、簡単な絞り込み用途としての検索エンジンであればANDクエリのみで十分なことが多い
一方でORクエリが有用なケースも多い
ORクエリが有用な例
クエリ拡張
代表的な検索エンジンで”algorithm”と検索すると”アルゴリズム”が含まれる記事もヒットしたりする
このようにシノニムなどが含まれる記事もヒットするようにしたい場合はORクエリが使われる
○ この場合は”algorithm” OR “アルゴリズム”などのようになる
○ *検索エンジンの中の人ではないので本当にこうしてるかは知りません
ORクエリが有用な例
類似検索 表示されてる文章から類似の文章を検索する
ex : コンテンツ連動型広告、関連文表示
文章中の単語が全部含まれてるというのはありえないので、ANDクエリでは文章がヒットしない
話の流れ
転置インデックスについて
TAAT, DAAT
Top-k Query
max-score
inteval-based prunning
other method
○ wand
○ layered-index
ORクエリの実装
ORクエリの高速化について見ていく前にnaiveな実装について説明する
代表的な手法として
TAAT(Term-at-a-time)
DAAT(Document-at-a-time)
の2つが存在する
TAATについて
Termごとに順番に処理していく手法
処理の結果はアキュムレータという中間データに格納されていく
TAATの例
例として”iwc OR rolex OR watch”というクエリを考える
初めに空のアキュムレータを作成する
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
accumulator = {}
TAATの例
iwcに関する転置リストをaccumulatorに入れる
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
accumulator = {1,5}
TAATの例
rolexに関する転置リストをaccumulatorとマージする
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
accumulator = {1,2,3,5}
TAATの例
watchに関する転置リストをaccumulatorとマージする
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
accumulator = {1,2,3,4,5}
TAATの例
結果文章1,2,3,4,5がクエリに適合することが分かる
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
accumulator = {1,2,3,4,5}
TAATのメリット・デメリット
実装が簡単
シーケンシャルアクセス中心になるのでデータがファイルに格納されてる時に割と性能がよい
最近流行してるsuffix treeなどのデータ構造系と相性が良い [G. Navarro and Y. Nekrich
2012]
アキュムレータがORの結果が多くなるほど負荷が大きくなる
DAATについて
クエリに関する転置インデックスを文章番号順に処理していく
DAATの例
各単語の転置インデックスの先頭にカーソルを設定する
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソル上の文章番号の最も小さい文章を処理する
この場合は1
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソルを次に進める
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソル上の文章番号の最も小さい文章を処理する
この場合は2
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソルを次に進める
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソル上の文章番号の最も小さい文章を処理する
この場合は3
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソルを次に進める
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソル上の文章番号の最も小さい文章を処理する
この場合は4
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソルを次に進める
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソル上の文章番号の最も小さい文章を処理する
この場合は5
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATの例
カーソルが最後まで来たので終了
一連の処理では1,2,3,4,5の順で文章を処理した
iwc
rolex
watch
1 5
2 3 5
1 2 4 5
DAATのメリット・デメリット
文章番号の小さい順に処理をするところはPriority Queueというデータ構造を使うと効率的に処理できる 例えばLuceneのorg.apache.lucene.search.
DisjunctionSumScorerの実装が参考になる
アキュムレータを持つ必要がない
文章ごとに処理していくので、フィルタ処理などとの相性が良い 例えば値段が50万円以下のもののみ出力する、メンズ用品のみ出力するなど
Luceneの実装もDAATになっている
ファイルへのランダムアクセスが多い
話の流れ
転置インデックスについて
TAAT, DAAT
Top-k Query
max-score
inteval-based prunning
other method
○ wand
○ layered-index
OR検索をどうやって高速化するか
単純にORでマッチする全部を取る必要がある場合は候補数が多い時にどうやっても処理に時間を要する
しかし、検索結果の上位数件だけ必要であれば上位に来る可能性がない文章の評価をスキップすることにより、処理の高速化が可能となる
このような問い合わせに対して上位k件のみ取り出すことをtop-k query processingと呼ぶ
文章のランク付け
上位k件を出力するためには、クエリに対してどの文章の順位が高いかを決定する必要がある
どういった文章が適合してるかを考えてみる 例えば“watch”のみ含まれる文章では置時計や動詞の
watchが含まれる文章もヒットし、また数も大量にあるため、”iwc”のみが含まれる文章の方が関連性が高いと考えられる
また”iwc”のみ含まれるページより”iwc”と”rolex”を含むページの方が関連性が高い
“iwc”を1回含む文章よりも2回含む文章の方が関連度が高い
文章のランク付け
クエリ𝑄 = (𝑞1, … , 𝑞𝑁)に対して、文章𝑑のスコアを𝑠𝑐𝑜𝑟𝑒 𝑄, 𝑑 = 𝑠𝑐𝑜𝑟𝑒(𝑞𝑛, 𝑑)𝑛 の形で表す
𝑠𝑐𝑜𝑟𝑒(𝑞𝑛, 𝑑)は文章における𝑞𝑛の出現頻度、
𝑞𝑛の珍しさなどが加味された値となる
またこの後の議論の都合上𝑠𝑐𝑜𝑟𝑒 𝑞𝑛, 𝑑 ≥ 0を仮定する
この形のスコアリング関数にはTF-IDF,
BM25などの多くの代表的なものが含まれる
転置インデックスの拡張
転置インデックスに対して、scoreの値および各単語のscoreの最大値を付与する
図では(文章番号, スコア)という形式で書く
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,2) (4,1) (5,1)
max_score=5
max_score=3
max_score=2
話の流れ
転置インデックスについて
TAAT, DAAT
Top-k Query
max-score
inteval-based prunning
other method
○ wand
○ layered-index
max_score [H.R. Turtle and J. Flood, 1995]
今上位k位に入るための閾値が4だとするとwatchのみ含む文章はmax_score=2から絶対に候補に入ることが無いことを利用する
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=3
max_score=2
max_scoreの例1
上位1件のみ取ることを考える
最初の文章1を評価するとスコアは6になる
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=3
max_score=2
max_scoreの例1
1位のスコアが6のため”watch”+”rolex”ではスコアが5にしかならないので、候補となる文章は必ず”iwc”を含まなければならない
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=3
max_score=2
max_scoreの例1
”iwc”のカーソルを進める
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=3
max_score=2
max_scoreの例1 他の2つに関しては”iwc”を含まないものを評価しても意味が無いので文章5まで飛ばす 実装上ここで効率的に飛ばすためには転置インデックスに100個先までのポインタなどを持たせる必要がある
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=3
max_score=2
max_scoreの例1
文章5を評価してスコアが4であることを得る
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=3
max_score=2
max_scoreの例1
全て見たので終了
処理の中で文章1,5のみを評価しており、2,3,4の評価を飛ばせている
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,3) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=3
max_score=2
max_scoreの例2
上位1件のみ取ることを考える ただ前のとスコアの設定が違う
最初の文章1を評価するとスコアは6になる
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
1位のスコアが6のため”watch”のみではスコアが2にしかならないので、候補となる文章は必ず”iwc”か”rolex”を含まなければならない
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
“iwc”のカーソルを進める
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
“watch”の方は文章2まで飛ばす
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
文章2を評価してスコアが3であることを得る
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
“rolex”のカーソルを進める
“watch”の方は3以降に飛ばす
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
文章3を評価して、スコアが5であることを得る
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
“rolex”のカーソルを進める
“watch”の方は5以降に飛ばす
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
文章5を評価してスコアが4であることを得る
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_scoreの例2
一連の流れで文章1,2,3,5の評価を行なっている
iwc
rolex
watch
(1,5) (5,2)
(2,2) (3,5) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=5
max_score=2
max_score 補足
今上げた2つの例では文章1が最も大きいスコアになる例であったが、文章の途中のものが1番になった場合、閾値もそれにあわせて変化していく
例2では閾値が6のときに”iwc”と”rolex”を含むの代わりに”iwc”と”watch”を含むとしても良かったが、通常は転置リストの長いものもしくはスコアが低いものから候補から除外していく
max_scoreの性能
例えば[M. Fontoura+, 2011] では約340万文章、3GBの広告データに対して平均長57.76
のクエリ検索を行った場合
Naive DAAT 26778.3 μsec
DAAT max_score 9321.3 μsec
と2.8倍近い性能改善が報告されている
* この辺りの性能改善率に関しては検索エンジンの性能および文章の性質に強く依存する
topdocsの利用[T. Stohman+, 2005] 極端にスコアが大きい文章のみ別の転置インデックスに分ける 実装によってはメタデータに格納することもある
下の例ではこれにより文章2より先は”iwc”もしくは”rolex_2”が入った文章のみ評価すれば良いことが分かる
iwc
rolex_1
watch
(1,5) (5,2)
(2,2) (5,1)
(1,1) (2,1) (4,2) (5,1)
max_score=5
max_score=2
max_score=2
rolex_2
max_score=5
(3,5)
話の流れ
転置インデックスについて
TAAT, DAAT
Top-k Query
max-score
inteval-based prunning
other method
○ wand
○ layered-index
閑話: modernな転置インデックスの機能 多くの場合転置リストはブロックごとに圧縮されて格納されている
例えば転置リストの内容が{1,3,6,8,15,16}であれば{1,3},{6,8},{15,16}と分けられており、内部は圧縮されている
圧縮アルゴリズムはVbyte, Simple9,
PForDeltaなどがある.
例えば[H. Yan+, 2009]などが参考になる
ブロック圧縮された転置インデックスに対する検索手法 ブロックは圧縮されているのでなるべく
decode処理を飛ばしたい
またデータをブロック単位で持ってるのでブロックごとのスコアの最大値や最小値を持つことができる
ブロック圧縮された転置インデックスに対する検索手法はここ最近2件ほど独立に手法が提案されている [K. Chakrabarti+, 2011] [S. Ding and T. Suel,
2011]
今回は主に[K. Chakrabarti+, 2011]の紹介を行う
Interval-based pruning for top-k processing over compressed lists
ここからは最近の研究である
K. Chakrabarti, S. Chaudhuri and V. Ganti :
Interval-based pruning for top-k processing over
compressed lists, ICDE, 2011
の紹介を行う
著者はMicrosoft Researchの研究者
モチベーション k=1のとき、通常のmax_scoreを実行すると文章9の時点でスコアが8になり、𝑞1の転置リストのみでは1位に届かないのでブロックDは飛ばせる
一方で文章3を見た時にスコアが3になり、ブロックBの最大値は2であるため本来はdecodeしなくてもよいが通常のmax_scoreではここをdecodeしてしまう
[K. Chakrabarti+, 2011]より
max_score=5
max_score=6
提案手法
与えられたクエリに対するブロックから区間を作成して、Upper boundが現在の閾値以上の区間のみ評価する
[K. Chakrabarti+, 2011]より
例
論文のFig1の例、数値は一部変えてある
A
(1,3) (3,3)
F
B
(5,1) (8,1)
(1,2) (9,3)
C
(9,5) (11,2)
D
(12,1) (14,2)
E
(15,1) (16,1)
G
(15,6) (16,1)
例
区間を生成して、取り得る最大のスコアを計算する
A
(1,3) (3,3)
F
B
(5,1) (8,1)
(1,2) (9,3)
C
(9,5) (11,2)
D
(12,1) (14,2)
E
(15,1) (16,1)
G
(15,6) (16,1)
6 3 4 8 5 1 2 0 7 max
score
区間 [1,3] (3,5) [5,8] (8,9] (9,11] (11,12] (12,14] (14,15) [15,16]
例
始めの区間に関して, max_scoreを実行する
このときブロックA,Fをデコードする
A
(1,3) (3,3)
F
B
(5,1) (8,1)
(1,2) (9,3)
C
(9,5) (11,2)
D
(12,1) (14,2)
E
(15,1) (16,1)
G
(15,6) (16,1)
6 3 4 8 5 1 2 0 7 max
score
区間 [1,3] (3,5) [5,8] (8,9] (9,11] (11,12] (12,14] (14,15) [15,16]
例 一位のスコアが5となるので、続く2つの区間は見なくてよい
ブロックBのデコードはスキップされる
A
(1,3) (3,3)
F
B
(5,1) (8,1)
(1,2) (9,3)
C
(9,5) (11,2)
D
(12,1) (14,2)
E
(15,1) (16,1)
G
(15,6) (16,1)
6 3 4 8 5 1 2 0 7 max
score
区間 [1,3] (3,5) [5,8] (8,9] (9,11] (11,12] (12,14] (14,15) [15,16]
例 区間(8,9]を処理して、文章9のスコアが8であることを得る このときブロックCがデコードされる
A
(1,3) (3,3)
F
B
(5,1) (8,1)
(1,2) (9,3)
C
(9,5) (11,2)
D
(12,1) (14,2)
E
(15,1) (16,1)
G
(15,6) (16,1)
6 3 4 8 5 1 2 0 7 max
score
区間 [1,3] (3,5) [5,8] (8,9] (9,11] (11,12] (12,14] (14,15) [15,16]
例
残りは全てスキップできる
A
(1,3) (3,3)
F
B
(5,1) (8,1)
(1,2) (9,3)
C
(9,5) (11,2)
D
(12,1) (14,2)
E
(15,1) (16,1)
G
(15,6) (16,1)
6 3 4 8 5 1 2 0 7 max
score
区間 [1,3] (3,5) [5,8] (8,9] (9,11] (11,12] (12,14] (14,15) [15,16]
Interval-baseの利点
max_scoreがglobalな最大値のみ使うのに対して、ブロックごとの最大値を利用できるのでより枝刈りが利用できる
区間の数は高々ブロックの数の2倍程度にしかならない
通常ブロックには100個程度の文章idが格納されているので、長さ10万程度の転置リストでもブロックは1000個程度しかないので、区間の生成はほとんど負荷にならない
区間へのアクセス方法
例では前から順に区間にアクセスしていったが論文ではこれをPruneSeqと言っている
他にはPruneScoreOrder, PruneHybrid,
PruneLazyというアクセス方法を提案している
PruneScoreOrder
スコアが高い区間から順にアクセスする
下の例では最初の区間で最大値を得るので、残りは全てスキップできる
A
(1,3) (3,3)
F
B
(5,1) (8,1)
(1,2) (9,3)
C
(9,5) (11,2)
D
(12,1) (14,2)
E
(15,1) (16,1)
G
(15,6) (16,1)
6 3 4 8 5 1 2 0 7 max
score
区間 [1,3] (3,5) [5,8] (8,9] (9,11] (11,12] (12,14] (14,15) [15,16]
PruneHybrid
PruneScoreOrderの欠点として、 ランダムアクセスが多く発生すること
同じ転置リストのブロックに何回もアクセスすることがある ○ これに関して論文ではキャッシュを用意して、なるべくディスクから読む回数及びデコード回数を少なくするという工夫が成されている
これに対してPruneHybridでは上位x%の区間のみPruneScoreOrderを実施し、そこで得た閾値を元にPruneSeqを実施するというのがPruneHybridである x=0のときPruneSeqと一致し
x=100のときPruneScoreOrderと一致する
PruneLazy
転置リストのIOがランダムになることを防ぐため
1. 一定量の区間のブロックをメモリに読み込む このときdecodeは行わない
2. 読み込んだ区間に関して、スコア順に区間を処理していく
閾値によってはいくつかの読み込んだブロックに関してはdecodeは飛ばされる
を繰り返す
実験結果
TREC Terabyte (800万ページ)のデータセットで実験
max_scoreに近い手法に比べて3-6倍の性能改善
[K. Chakrabarti+, 2011]より
話の流れ
転置インデックスについて
TAAT, DAAT
Top-k Query
max-score
inteval-based prunning
other method
○ wand
○ layered-index
WAND [A. Broder+, 2003] 転置リストを先頭の文章番号の順に並べて、
pivotとなるtermの文章番号より前にある転置リストのカーソルを進める手法 今閾値が7であるとすると”rolex”のみでは閾値に届かないので”iwc”も必要になる. このため”rolex”のカーソルを5以降に飛ばしてよいことが分かる
max_scoreだと”watch”の方を除外してしまうので文章2,3を評価してしまう
iwc
rolex
watch
(1,5) (5,2)
(1,1) (2,5) (3,1)
(1,1) (6,1) (7,2) (8,3)
max_score=5
max_score=5
max_score=3
pivot term
WANDの変形
WANDの改良としては
メモリ上の実行に適したmWAND [M. Fontoura+,
2011]
ブロック情報を利用したBlock-max WAND (BMW)
[S. Ding and T. Suel, 2011]
がある
両論文とも割と読みやすい
Layered-index [T. Stohman and W. Croft, 2007]
スコアに応じて、転置リストを複数に分ける
クエリの評価はTAATベースで行い、スコアが高いリストから順にマージしていく 途中でこれ以上アキュムレータにないものを追加しても上位k件に入らないときはアキュムレータ内のみで評価する. アキュムレータ内のものでも上位k件に入る可能性の無いものを除外するなどの最適化が行われる
iwc_2
rolex_3
rolex_2
rolex_1
iwc_1
(1,1) (3,1)
(4,3) (5,2)
(5,4) (6,4)
(2,5) (4,6)
(1,8) max_score=8
max_score=6
max_score=4
max_score=3
max_score=1
まとめ
転置インデックスに対してdisjunctiveなクエリで問い合わせを行った際に上位k件を取ってくるためのDAAT(Document-at-a-time)
ベースの効率的な手法について述べた
この辺りの論文はquery-processingというキーワードでSIGIRなどの情報検索系の会議によく投稿される
参考文献 情報検索の基本的な教科書
[S. Büttcher+ 2010] Information Retrieval: Implementing and Evaluating Search Engines, MIT Press
Max-score [H.R. Turtle and J. Flood, 1995] Query evaluation: strategies and optimization. Information
processing and management
[T. Stohman+, 2005] Optimization strategies for complex queries, SIGIR
[K. Chakrabarti+, 2011] Interval-based pruning for top-k processing over compressed lists, ICDE
WAND [A. Broder+, 2003] Efficient query evaluation using a two-level retrieval process, CIKM
[M. Fontoura+, 2011] Evaluation strategies for top-k queries over memory-resident inverted indexes, VLDB
[S. Ding and T. Suel, 2011] Faster top-k document retrieval using block-max indexes, SIGIR
Layered Index [V. N. Anh and A. Moffat, 2006] Pruned query evaluation using pre-computed impacts,
SIGIR
[T. Stohman and W. Croft, 2007] Efficient document retrieval in main memory, SIGIR
その他 [H.Yan+ 2009] Inverted index compression and query processing with optimized document
ordering, WWW
[G. Navarro and Y. Nekrich 2012] Top-k Document Retrieval in Optimal Time and Linear Space, SODA