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
320
0
Share
全文検索のアルゴリズムとデータ構造
toyama
December 13, 2020
More Decks by toyama
See All by toyama
Path Copying による永続データ構造
toyama1710
0
690
Featured
See All Featured
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
150
How STYLIGHT went responsive
nonsquared
100
6.1k
Paper Plane (Part 1)
katiecoart
PRO
0
7.3k
Designing Powerful Visuals for Engaging Learning
tmiket
1
360
Amusing Abliteration
ianozsvald
1
160
How to Think Like a Performance Engineer
csswizardry
28
2.6k
VelocityConf: Rendering Performance Case Studies
addyosmani
333
25k
Agile that works and the tools we love
rasmusluckow
331
21k
A designer walks into a library…
pauljervisheath
211
24k
The Cost Of JavaScript in 2023
addyosmani
55
9.9k
How Software Deployment tools have changed in the past 20 years
geshan
0
33k
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2k
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.
ありがとうございました 楽しんでいただけたなら幸いです