Share
Embed
検索エンジン自作入門 Go Conference 2021 Spring
Go Conference 2021 Springの登壇資料です
アウトライン
1. 検索エンジンとは ~ 一般的な検索エンジンの仕組みと構成要素
2. 自作した検索エンジンの紹介 ~ 具体的に自作した検索エンジンの構成要素と動作例
3. 自作した検索エンジンの実装 ~ アルゴリズムとデータ構造、ライブラリ
4. おわりに ~ 検索エンジンを自作した感想
kotaroooo0
April 24, 2021
Transcript
58 slides
-
ݕࡧΤϯδϯͱ υΩϡϝϯτͷू߹͔ΒΫΤϦʹద͢ΔυΩϡϝϯτΛฦ͢ ݕࡧΤϯδϯ ΫΤϦೖྗ υΩϡϝϯτฦ٫ υΩϡϝϯτొ 🤖 👦 Ϣʔβʔଆ ఏڙଆ
ಛʹෳυΩϡϝϯτ͔ΒಛఆͷจࣈྻΛݕࡧ͢Δ͜ͱΛશจݕࡧ 7 (GoogleݕࡧͰWebϖʔδ) (GoogleݕࡧͰΫϩʔϦϯά) -
શจݕࡧͷछྨ G O R U B Y J S J
S J S J S J S J S G O R U B Y G O R U B Y J S Grepܕ ΠϯσοΫεܕ ྫ: υΩϡϝϯτʮGO RUBY JSʯʹจࣈྻʮJSʯؚ͕·Ε͍ͯΔ͔ݕࡧ 8 ࣄલʹݕࡧରͷυΩϡϝϯτͷࡧҾσʔλΛ࡞ -
ΠϯσοΫεܕݕࡧΤϯδϯͷߏ ΠϯσοΫε ΫΤϦೖྗ υΩϡϝϯτొ Analyzer Analyzer Indexer Searcher υΩϡϝϯτฦ٫ 9
Sorter ҎԼͷཁૉͰߏ͞Ε͍ͯ·͢(ৄࡉ͜ͷޙઆ໌͠·͢) ※Sorter࣮͍ͯ͠ͳ͍ͨΊɺҎޙͷઆ໌Ͱলུ -
ΠϯσοΫε సஔΠϯσοΫε(ࣙॻ+ϙεςΟϯάϦετ)͕Ұൠత go js ruby 1 1 2 3 4
5 5 ࣙॻ ϙεςΟϯάϦετ 10 -
Indexing “I have pens.” “We have a desk.” Indexer Analyzer
จࣈྻΛ୯ޠղ సஔΠϯσοΫε࡞ 11 1 2 have pen we desk 1 1 2 2 2 సஔΠϯσοΫε υΩϡϝϯτΛసஔΠϯσοΫεʹొ͢Δ -
Search ΫΤϦ “PENS” υΩϡϝϯτ1͕ώοτ Searcher Analzyer จࣈྻΛ୯ޠղ “PENS” → “pen”
సஔΠϯσοΫεΛ୳ࡧ 12 have pen we desk 1 1 2 2 2 సஔΠϯσοΫεΛ୳ࡧͯ͠ద߹͢ΔυΩϡϝϯτΛ୳͢ -
Analyzer Char Filter จࣈྻΛ୯ޠׂ͢Δલͷจࣈͷௐ ྫ: & → & 13 Token
Filter ׂͨ͠୯ޠΛௐ ྫ: খจࣈ౷Ұɺετοϓϫʔυআڈ Tokenizer จࣈྻΛ୯ޠʹׂɺදه༳Εٵऩ ྫ: I have pens → I, have, pens Char Filter Tokenizer Token Filter 3ͭ߹ΘͤͯAnalyzer จࣈྻ ෳ୯ޠ දه༳ΕΛٵऩ &จࣈྻΛ୯ޠʹׂ Indexing, Search྆ํͰར༻ ※྆ํͰಉ͡AnalyzerΛΘͳ͍ͱޮՌബ͍ -
ಈ࡞ྫ Analyzer Analyzeલ MappingCharFilter StandardTokenizer LowercaseFilter StemmerFilter StopWordFilter I feel
TIRED :( I feel TIRED sad I, feel, TIRED, sad i, feel, tired, sad i, feel, tire, sad feel, tire, sad ॲཧͷྲྀΕ 17 -
Analyzeલ MorphologicalTokenizer ReadingformFilter ౦ژͱژ ౦ژ, ͱ, ژ tokyo, to, kyoto
ॲཧͷྲྀΕ ಈ࡞ྫ Analyzer 18 -
ಈ࡞ྫ Indexing & Search 19 ΠϯσοΫεՃ 1: “Go Ruby PHP”
2: “Go PHP Python” ϑϨʔζݕࡧ ”go php” ANDݕࡧ ”go php” 2ͷΈώοτ 1,2͕ώοτ 1⃣ 2⃣ 3⃣ 1⃣ 2⃣ 3⃣ 3: “Go Python Ruby” -
ಈ࡞ྫ ઃఆॳظԽ • సஔΠϯσοΫεΛӬଓԽ͢ΔMySQLઃఆ • MySQLΞΫηε͢ΔӬଓԽͷॳظԽ • ΞφϥΠβͷॳظԽ • CharFilter:
ͳ͠ • Tokenizer: εϖʔεͰ۠Δ(Standard Tokenizer) • Token Filter: খจࣈԽ 20 -
ಈ࡞ྫ Indexing • సஔΠϯσοΫεΛ࡞͢ΔIndexerͷॳظԽ • ҎԼͷυΩϡϝϯτΛIndexing(సஔΠϯσοΫεΛੜ͠MySQLอଘ) 1: “Go Ruby PHP”
• Analyzeޙ: go, ruby, php 2: “Go PHP Python” • Analyzeޙ: go, php, python 3: “Go Python Ruby” • Analyzeޙ: go, python, ruby 21 go 1 1:1 ruby php 2:1 3:1 1:2 1:3 3:3 2:2 ɾ ɾ ɾ υΩϡϝϯτID:ग़ݱҐஔ -
ಈ࡞ྫ Search ANDݕࡧ(“GO PHP”) • ΞφϥΠβͰେจࣈখจࣈͷදه༳ΕΛٵऩ • “Go”ͱ”PHP”͕྆ํؚ·ΕΔυΩϡϝϯτ1,2͕ώοτ 22 1:
“Go Ruby PHP” 2: “Go PHP Python” -
Analyzerͷ࣮ 25 Analyzerߏମ • CharFilter InterfaceͷSlice • Tokenizer Interface(1ͭͷΈ) •
ToknenFilter InterfaceͷSlice Analyzeϝιου • string → TokenStream(TokenͷSlice) • CharFilter, Tokenizer, TokenFilterͷॱʹ దԠ -
Char Filterͷ࣮ 26 CharFilter Interface • Filterϝιου ࣮ྫ: MappingCharFilter •
Key → ValueϚοϐϯά͢Δ -
Tokenizerͷ࣮ 27 Tokenizer Interface • Tokenizeϝιου ࣮ྫ: StandardTokenizer • String
→ TokenStream • จࣈͰࣈͰͳ͚Εׂ -
Token Filterͷ࣮ 28 TokenFilter Interface • Filterϝιου ࣮ྫ: LowercaseFilter •
strings.ToLowerͰখจࣈԽ ࣮ྫ: StopWordFilter • ରͷจࣈΛTokenStream͔Βল͘ -
Token Filterͷ࣮ ReadingformFilter • ࣈ → ϩʔϚࣈม͢ΔFilter • ࣈ →
ฏԾ໊ → ϩʔϚࣈ • ࣈ → ฏԾ໊(ܗଶૉղੳث͕ߦ͏) • ฏԾ໊ → ϩʔϚࣈ(ࣗ࡞) ࣮ • ۪ͳϚοϐϯά+ ϔϘϯࣜͷϧʔϧ 29 -
సஔΠϯσοΫεͷ࣮ సஔΠϯσοΫε(ࣙॻ+ϙεςΟϯάϦετ) • Ϛοϓ: τʔΫϯID → ϙεςΟϯάϦετ ϙεςΟϯάϦετ • ϙεςΟϯάͷϦϯΫτϦετ
ϙεςΟϯά • υΩϡϝϯτID • υΩϡϝϯτதͷҐஔใ(ϑϨʔζݕࡧ༻) • ࣍ͷϙεςΟϯάͷϙΠϯλ 30 -
సஔΠϯσοΫεͷ࣮ 31 0 TokenID(mapͷkey) 3 PostingListͷPostings Postings 1 6 17
90 198 5 8 14 Postings Postings nil Next Next Next Next ※ऴnilΛࢦ͢ TokenID 0ͷτʔΫϯ͕ υΩϡϝϯτID3,5,8,14ʹؚ·Ε͍ͯΔ͜ͱΛࣔ͢ -
సஔΠϯσοΫεͷ࣮ 32 0 TokenID 3 PostingListͷPostings Postings 1 3 7
90 198 5 8 14 Postings Postings nil Next Next Next Next ※ऴnilΛࢦ͢ 7 Postings Next ϦϯΫτϦετ: ͋ΔϊʔυޙͷσʔλͷՃআO(1) ϙεςΟϯάϦετͰυΩϡϝϯτIDͷঢॱΛΩʔϓ͢ΔͨΊ ͜ͷૢ࡞͕ଟ͘ϦϯΫτϦετ͕͍͍ͯΔ ϙΠϯλͷ͚ସ͑ͷΈ -
Indexerͷ࣮ ( ͷ۩ମྫ) ϝϞϦ্ͷసஔΠϯσοΫε Ճ͍ͨ͠υΩϡϝϯτ go php go php MySQL্ͷసஔΠϯσοΫε
సஔΠϯσοΫεՃ ϝϞϦͱMySQLͷసஔΠϯσοΫε Ϛʔδ ӬଓԽ ”Go PHP” go, php Analyze 33 Analyzer Indexer MySQL͔ΒRead 1⃣ 2⃣ 3⃣ ϝϞϦ্ͷసஔΠϯσοΫεͷ αΠζ͕ᮢΛ͑Δͱ… 4⃣ 3⃣ MySQLWrite (ᮢετϨʔδͷΞΫηεճͱϝϞϦ༻ྔͷτϨʔυΦϑ) -
Searcherͷ࣮ 35 go php go php MySQL্ͷసஔΠϯσοΫε ݕࡧΫΤϦ ”Go PHP”
go, php Analyzer Analyze Searcher ద߹ͨ͠υΩϡϝϯτ τʔΫϯʹରԠ͢ΔϙεςΟϯάϦετΛ MySQL͔ΒϝϞϦRead ϙεςΟϯάϦετ ࠪ -
ద߹͢ΔυΩϡϝϯτΛ୳ͨ͢ΊʹͲ͏ϙεςΟϯάϦετΛͲ͏ࠪ͢Δ͔? DAAT(Document At A Time) • ΫΤϦʹؚ·ΕΔτʔΫϯͷϙεςΟϯάϦετͷΧʔιϧΛͯ͢։͖ಉ ࣌ʹॲཧ • υΩϡϝϯτ͝ͱʹࠪ͢Δ
• Elasticsearch(Lucene)Ͱ࠾༻ ※DAATʹରͯ͠TAAT(Team At A Time)͕͋Δ͕ࠓճϊʔλον ࢀߟࢿྉΛఴ https://www.slideshare.net/tsubosaka/top-kquery Searcherͷ࣮ 36 -
DAATͰͷANDݕࡧ Χʔιϧ͕ࢦ͢υΩϡϝϯτ͕ҟͳΔͷͰΧʔιϧΛਐΊΔ Result = [] 37 ྫ “PHP” AND “Ruby”
ݕࡧ ruby php 1 2 5 5 2 4 -
DAATͰͷANDݕࡧ Χʔιϧ͕ࢦ͢υΩϡϝϯτ͍͠ͷͰ݁ՌʹυΩϡϝϯτΛՃ͑Δ Result = [2] 38 ྫ “PHP” AND “Ruby”
ݕࡧ ruby php 1 5 5 2 4 2 -
DAATͰͷANDݕࡧ Χʔιϧ͕ࢦ͢υΩϡϝϯτ͕ҟͳΔͷͰΧʔιϧΛਐΊΔ Result = [2] 39 ྫ “PHP” AND “Ruby”
ݕࡧ ruby php 1 5 2 4 2 5 -
DAATͰͷANDݕࡧ Χʔιϧ͕ࢦ͢υΩϡϝϯτ͍͠ͷͰ݁ՌʹυΩϡϝϯτΛՃ͑Δ Result = [2, 5] 40 ྫ “PHP” AND
“Ruby” ݕࡧ ruby php 1 5 2 4 2 5 -
DAATͰͷORݕࡧ ΧʔιϧΛಈ͔ͯ͠ɺશͯͷIDΛॏෳͳ͘Ճɹ ✌︎ (‘ω' ✌︎ ) ݪ࢝త ( ✌︎ ’ω')
✌︎ ※࣮ࡍͷݕࡧΤϯδϯͰORݕࡧ࠷దԽ͕ߦΘΕ͍ͯΔ(͜ͷτʔΫͰϊʔλον) 41 ྫ “PHP” OR “Ruby” ݕࡧ ruby php 1 2 5 5 2 4 -
ҎԼೋͭͷυΩϡϝϯτ“Amazon Prime”ͱݕࡧ • D1: “Amazon Prime movies” • D2: “a
prime concern of Amazon” ϙεςΟϯάʹυΩϡϝϯτதͷҐஔใ ୯ޠͷॱংΛߟྀͰ͖Δ D1ͷΈΛώοτͤ͞ΒΕΔ 42 ϑϨʔζݕࡧ -
ΫΤϦ“Go PHP”Ͱݕࡧ͢Δ߹ 43 ϑϨʔζݕࡧ go 1:1 php 2:1 1:3 2:2
υΩϡϝϯτID:ग़ݱҐஔ go 1:1-0 php 2:1-0 1:3-1 2:2-1 υΩϡϝϯτID:૬ରग़ݱҐஔ go 1:1 php 2:1 1:2 2:1 υΩϡϝϯτID:૬ରग़ݱҐஔ ૬ରग़ݱҐஔ͕͍͠ → ϑϨʔζΛؚΜͰ͍Δ 1: “Go Ruby PHP” 2: “Go PHP Python” ΫΤϦ্ͰGo0൪ɺPHP1൪ͳͷͰ૬ରग़ݱҐஔΛܭࢉ͢Δ సஔΠϯσοΫεʹొͨ͠υΩϡϝϯτ -
సஔΠϯσοΫεͷѹॖ సஔΠϯσοΫεΛετϨʔδ͔ΒಡΈग़͕࣌ؒ͢ϘτϧωοΫʹͳΔ͜ͱ͕͋Δ → సஔΠϯσοΫεΛѹॖͯ͠อଘ͢Δ 46 ѹॖࡁͷసஔΠϯσοΫεΛ ετϨʔδ͔ΒಡΈग़࣌ؒ͢ ະѹॖͷసஔΠϯσοΫεΛ ετϨʔδ͔ΒಡΈग़࣌ؒ͢ <
্ͷෆ͕ࣜΓཱͭΑ͏ʹѹॖ ※ࠓճܭଌ·Ͱ͍ͯ͠ͳ͍ 600MB 1GB ྃ ಡΈग़͠ ෮ݩ ಡΈग़͠ ྃ సஔΠϯσοΫεͷ෮ݩ࣌ؒ ʴ -
సஔΠϯσοΫεͷѹॖ go υΩϡϝϯτID ̍ 4 21 241 412 500 560
600 888 1324 2000 2321 10940 23131 29898 3001 8090 9012 3001 8090 9012 901 1201 ϙεςΟϯάϦετʹυΩϡϝϯτID͕Կेສͱ͋Δ߹͋Γ༰ྔ͕େ͖͘ͳΔ → Մมූ߸ԽͱࠩྻΛΈ߹Θͤͯѹॖ 47 -
సஔΠϯσοΫεͷѹॖ ࠩྻ go ̍ 5 50 250 500 800 1000
2500 2800 υΩϡϝϯτIDঢॱʹιʔτ͞Ε͍ͯΔ ࠩΛͱΔ → Մมූ߸Խʹ͓͍ͯใྔ͕গͳ͘ͳΔ go ̍ 4 45 200 250 300 200 1500 300 υΩϡϝϯτIDࠩ 49 -
సஔΠϯσοΫεͷѹॖ Մมූ߸Խ • Մมූ߸Խࣗ࡞ͤͣʹඪ४ύοέʔδ”encoding/gob"Λར༻ • JSONXML, Protocol buffersͳͲ͋Δ͕Goʹดͨ͡ڥͰgobͷํ͕ศར • json:”hoge"ͷΑ͏ͳλά͕ෆཁ
• ςΩετϕʔεͰͳ͘όΠφϦʔͰແବ͕ͳ͍ • ࣗݾهड़త • GoͷมͳΒstructͰnilͰΤϯίʔυͰ͖Δ(ϦϯΫτϦετͰ͖ͨ) • gobͷunsigned intͷΤϯίʔυ • 0 → 00000000(1byte) • 7 → 00000111(1byte) • 256 → 11111110 000000001 00000000(3byte) https://blog.golang.org/gob https://golang.org/pkg/encoding/gob/ 50 -
͓ΘΓʹ 53 • ंྠͷ࠶ൃ໌ͰΠϯϓοτͱΞτϓοτͷαΠΫϧΛճͤͨ • ࣗ࡞ָ͕͍͠(Ϟνϕʔγϣϯ) • ৄ͘͠ͳ͍ٕज़ʹ৮ΕΔඞཁ(Πϯϓοτ) • (ྫ)ΤϯίʔσΟϯά
• encoding/gob • encoding/binary • protobuf • धཁ͕͋Δ(Ξτϓοτ) • ϒϩάߘ→ొஃ • Ξτϓοτۦಈ։ൃ INPUT OUTPUT -
ࢀߟ 54 ݕࡧΤϯδϯࣗ࡞ೖɹʙखΛಈ͔͠ͳ͕Βݟ͢ݕࡧͷཪ ใݕࡧ ݕࡧΤϯδϯͷ࣮ͱධՁ https://logmi.jp/tech/articles/322211 https://www.slideshare.net/tsubosaka/top-kquery https://artem.krylysov.com/blog/2020/07/28/lets-build-a-full-text-search-engine/ https://github.com/blevesearch/bleve ϦϙδτϦ:
https://github.com/kotaroooo0/stalefish ϒϩάهࣄ: https://kotaroooo0-dev.hatenablog.com/entry/toy-search-engine -
TAATͰͷANDݕࡧ 1. ϙεςΟϯάϦετͷαΠζ͕࠷খͷͷ”ruby”Λબ͠ɺAccumulator࡞ [2, 5] 2. “php”ͷϦετΛࠪ ɾID2ؚ·Ε͍ͯΔ͔?ID5ؚ·Ε͍ͯΔ͔?ͷΈͷνΣοΫͰOK go ruby
php 1 1 2 4 5 5 2 57 “PHP” AND “Ruby” ݕࡧ -
TAATͰͷORݕࡧ 1. ͲͷΩʔͰྑ͍ͷͰAccumlatorΛ࡞ [1,2,5] (php) 2. ॏෳ͠ͳ͍શͯͷIDΛAccumlatorʹՃ ✌︎ (‘ω' ✌︎
) ݪ࢝త ( ✌︎ ’ω') ✌︎ ※࣮ࡍͷݕࡧΤϯδϯͰORݕࡧ࠷దԽ͕ߦΘΕ͍ͯΔ(͜ͷτʔΫͰ৮Ε·ͤΜ) 58 “PHP” OR “Ruby” ݕࡧ ruby php 1 2 5 5 2