Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
全文検索のアルゴリズムとデータ構造
Search
toyama
December 13, 2020
0
240
全文検索のアルゴリズムとデータ構造
toyama
December 13, 2020
Tweet
Share
More Decks by toyama
See All by toyama
Path Copying による永続データ構造
toyama1710
0
510
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
28
4.5k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Documentation Writing (for coders)
carmenintech
67
4.6k
Making Projects Easy
brettharned
116
6k
Rails Girls Zürich Keynote
gr2m
94
13k
KATA
mclloyd
29
14k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Practical Orchestrator
shlominoach
186
10k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
52k
A Modern Web Designer's Workflow
chriscoyier
693
190k
[RailsConf 2023] Rails as a piece of cake
palkan
53
5.2k
The Invisible Side of Design
smashingmag
299
50k
Transcript
Hugo でブログ作成 会津大学 学部1年 toyama1710
自己紹介 • HN: 遠山 • Twitter: @toyama_pts • github: toyama1710
• 趣味: 絵, バイク
はじめに • ブログを作りました ◦ https://blog.toyama1710.net • 見てね!
Hugo • SSG の一種 • markdown で書いた記事を html に変換してくれる
記事検索機能 • タグ検索 • カテゴリ検索
記事検索機能 • タグ検索 • カテゴリ検索 全文検索も欲しくないスカ?
文字列検索アルゴリズム Hugo でブログ作成 会津大学 学部1年 toyama1710 勉強したので知見共有するぜ!
問題設定
パターンマッチング 文字列 T は部分文字列として文字列 P を含むか? を判定する問題
パターンマッチング 例 • “アメリカンジョーク” に “カンジョー” は含まれる?
パターンマッチング 例 • “アメリカンジョーク” に “カンジョー” は含まれる? ◦ Yes
パターンマッチング 例 • “アメリカンジョーク” に “カンジョー” は含まれる? ◦ Yes •
“任意コードジッコウ” に “ドジッコ” は含まれる?
パターンマッチング 例 • “アメリカンジョーク” に “カンジョー” は含まれる? ◦ Yes •
“任意コードジッコウ” に “ドジッコ” は含まれる? ◦ Yes
パターンマッチング 例 • “アメリカンジョーク” に “カンジョー” は含まれる? ◦ Yes •
“任意コードジッコウ” に “ドジッコ” は含まれる? ◦ Yes • “Linux” に “Linx” は含まれる?
パターンマッチング 例 • “アメリカンジョーク” に “カンジョー” は含まれる? ◦ Yes •
“任意コードジッコウ” に “ドジッコ” は含まれる? ◦ Yes • “Linux” に “Linx” は含まれる? ◦ No
記法,用語の導入 • 文字列 T の長さを |T| と書く ◦ T =
“abc” のとき |T| = 3 ◦ S = “efghi” のとき |S| = 5
記法,用語の導入 • prefix ◦ 文字列の先頭部分を抜き出してきた文字列 ◦ “ABC” の prefix -
“ABC”, “AB”, “A”, “” • suffix ◦ 文字列の末尾部分を抜き出した文字列 ◦ “ABC” の suffix - “ABC”, “BC”, “C”, “”
注意 • 今回の LT では定数アルファベットを仮定 ◦ 文字の種類数は定数
総当たり
総当たり • T と P を一字ずつずらして一致比較 • 途中で異なる文字があれば T をずらしてもう一度
A I Z U U N I V U N I V P: T:
総当たり • T と P を一字ずつずらして一致比較 • 途中で異なる文字があれば T をずらしてもう一度
A I Z U U N I V U N I V P: T:
総当たり • T と P を一字ずつずらして一致比較 • 途中で異なる文字があれば T をずらしてもう一度
A I Z U U N I V U N I V P: T:
総当たり • T と P を一字ずつずらして一致比較 • 途中で異なる文字があれば T をずらしてもう一度
A I Z U U N I V U N I V P: T:
総当たり • T と P を一字ずつずらして一致比較 • 途中で異なる文字があれば T をずらしてもう一度
A I Z U U N I V U N I V P: T:
総当たり • T と P を一字ずつずらして一致比較 • 途中で異なる文字があれば T をずらしてもう一度
• 時間計算量: O(|T||P|) A I Z U U N I V U N I V P: T:
総当たり 1. 狂った僕が あああああああああああ....(100万字) とだけ書かれた記事を投稿
総当たり 1. 狂った僕が あああああああああああ....(100万字) とだけ書かれた記事を投稿 2. ユーザも狂って検索窓に ああああああああ....(100万+1字)
総当たり 1. 狂った僕が あああああああああああ....(100万字) とだけ書かれた記事を投稿 2. ユーザも狂って検索窓に ああああああああ....(100万+1字) 3. 検索が終わらない
ラビンカープ法
ラビンカープ法 • 基本方針 ◦ 文字列の比較をハッシュで行う ◦ O(|P|) -> O(1) へ改善!!
◦ 全体として O(|T| + |P|)
Rolling Hash
Rolling Hash - ラビンカープ法 • 部分文字列のハッシュを高速に計算できる • 文字列を B 進数として解釈して
MOD をとるだけ ◦ B > 1 の正整数 ◦ 素数で MOD を取ると一様分布しやすい
Rolling Hash - ラビンカープ法 • 文字列 S のハッシュ値が既に計算済み ◦ S
の末尾に 1 文字付け加える: O(1) ◦ S の先頭を 1 文字削除: O(1) • 検索位置をスライドしながらハッシュ値を計算可能 A I Z U U N I V U N I V P: T:
Rolling Hash - ラビンカープ法 • 文字列 S のハッシュ値 h ◦
S.push(c): h * B + c ◦ S.erase(0): h - S[0] * B^|P| A I Z U U N I V U N I V P: T:
Rolling Hash - ラビンカープ法 • 文字列 S のハッシュ値 h ◦
S.push(c): h * B + c ◦ S.erase(0): h - S[0] * B^|P| A I Z U U N I V U N I V P: T:
Rolling Hash - ラビンカープ法 • 文字列 S のハッシュ値 h ◦
S.push(c): h * B + c ◦ S.erase(0): h - S[0] * B^|P| • 検索位置のスライドが O(1) A I Z U U N I V U N I V P: T:
Rolling Hash - ラビンカープ法 • 文字列 S のハッシュ値 h ◦
S.push(c): h * B + c ◦ S.erase(0): h - S[0] * B^|P| • 検索位置のスライドが O(1) • O(|T| + |P|) A I Z U U N I V U N I V P: T:
Rolling Hash - ラビンカープ法 • 記事全体の文字数は 1万字を超える • ユーザが検索する語は 30
字も無いはず • まだ改善できそう
Suffix Trie お気に入りデータ構造
Suffix Trie の前に Trie について お気に入りデータ構造
Trie • こんな感じの木構造 • 根から頂点へのパスが単語を表す • apple • apart •
bug • bag a p p l e a r t b u g a g
Trie • 共通した prefix を持った単語の列挙が得意 • 根からラベルを辿っていくだけで OK • prefix:
ap • prefix: bu a p p l e a r t b u g a g
Suffix Trie 再び
Suffix Trie • Thm. ◦ 部分文字列は suffix の prefix
Suffix Trie • Thm. ◦ 部分文字列は suffix の prefix A
I Z U U N I V T: U U N I V U U
Suffix Trie • T の suffix を全部 Trie に入れちゃお!w •
マジでこれだけ T = “ababc” a b a b c c b a b c c c
Suffix Trie • T の suffix を全部 Trie に入れちゃお!w •
マジでこれだけ • 構築時間: O(|T|^2) • 空間計算量: O(|T|^2) • 検索時間: クエリ毎 O(|P|)
Suffix Trie • 流石にメモリを食いすぎ • 1万字で 1 GB 食う計算
DAWG - Directed Acyclic Word Graph Suffix Automaton の名でも親しまれる
DAWG • Suffix Trie をよく見ると全く同じ部分木がたくさん • 一つにまとめてしまおう T = “ababc”
a b a b c c b a b c c c
DAWG • 検索は Suffix Trie と同様始点から辺を辿っていく a b a b
c c b a b c c c
DAWG • 構築時間: O(|T|) • 空間計算量: O(|T|) • 検索時間: クエリ毎
O(|P|) • 満足しました
実測 - DAWG
実測 • AOJ ALDS1 - 14 D を解いてみます ◦ https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/14/
ALDS1_14_D • 冒頭の問題設定と全く同じ
実測 • AOJ ALDS1 - 14 D を解いてみます ◦ https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/14/
ALDS1_14_D • 冒頭の問題設定と全く同じ • |T| < 1,000,000 • |P| < 1,000 • クエリ数 10,000
実測 • はやい • はやいと、うれしい!!
参考文献 • 秋葉拓哉, 岩田陽一, 北川宣稔 プログラミングコンテストチャレンジ ブック[第二版] - マイナビ出版 •
Anselm Blumer, Janet Blumer, David Haussler, Andrzej Ehrenfeucht, M. T. Chen, and Joel I. Seiferas. The smallest automation recognizing the subwords of a text. Theoretical Computer Science, 40:31–55, 1985.
ありがとうございました 楽しんでいただけたなら幸いです