Upload
akio-ishida
View
6.442
Download
7
Embed Size (px)
DESCRIPTION
PostgreSQLの全文検索機能に関するosc2009 hokkaido での発表資料です。
Citation preview
09/06/20
textsearch_jaで全文検索
日本PostgreSQLユーザ会北海道支部
株式会社サイクル・オブ・フィフス石田朗雄
09/06/20
自己紹介
● id:iakio● http://postgresql.g.hatena.ne.jp/iakio/● 今日の資料とデモのソースコードは公開します
09/06/20
自己紹介
● 代表作● SQLでボウリングのスコアを計算
with recursives(idx, pins1, pins2, pins3) as ( select s1.idx, s1.pins, s2.pins, s3.pins from score s1 left join score s2 on (s2.idx = s1.idx + 1) left join score s3 on (s3.idx = s1.idx + 2)),f(idx, pins1, pins2, pins3) as ( select idx, pins1, pins2, pins3 from s where idx = 1 union all select s.idx, s.pins1, s.pins2, s.pins3 from s join f on (s.idx = f.idx + case when f.pins1 = 10 then 1 else 2 end)),sof(idx, pins1, pins2, pins3, score_of_frame) as ( select idx , pins1, pins2, pins3 , case when pins1 = 10 then pins1 + pins2 + pins3 when pins1 + pins2 = 10 then pins1 + pins2 + pins3 else pins1 + pins2 end as score_of_frame from f)select row_number() over w as frame , pins1 , pins2 , case row_number() over w when 10 then pins3 else null end as pins3 , score_of_frame , sum(score_of_frame) over w from sofwindow w as (order by idx)
09/06/20
告知など
● PostgreSQL的な話● 8.4RC1が6/14に出ました
● JPUG北海道支部的な話● 5/13に勉強会を開催
● 次は7/8?● JPUG的な話
● JPUG 10th Anniversary Conference(11/20~21)
09/06/20
PostgreSQLと全文検索
09/06/20
PostgreSQLでの全文検索
● PostgreSQL8.2以前● contrib/tsearch2
● PostgreSQL8.3● 全文検索機能が本体に含まれるようになった。
● 日本語は未対応
● textsearch_ja● 日本語で全文検索を行なうための拡張モジュール
● http://textsearch-ja.projects.postgresql.org/● textsearch_sennaの話は今日はありません
09/06/20
資料に自信が無いのでとりあえずデモ
09/06/20
デモの構成
● PostgreSQL 8.4RC1(8.3でも同じです)● データベースエンコーディングはutf-8● PostgreSQLのドキュメントを格納したテーブル(html)● レコード数:900くらい
● 詳しくはブースで!!=> \d docs_en
カラム | 型 |--------+----------+------------ id | integer | path | text | title | text | body | text |
09/06/20
とりあえず検索する方法
09/06/20
方法1:関数インデックス
● インデックスを1つ作るだけで高速な全文検索ができる
インデックス作成=> CREATE INDEX docs_en_idx ON docs_en USING GIN(to_tsvector('english', body));CREATE INDEX
検索=> SELECT title FROM docs_en WHERE to_tsvector('english', body) @@ to_tsquery('english', 'search');
=> SELECT title FROM docs_en WHERE body ILIKE '%search%';
09/06/20
全文検索の基本
● tsvector、tsqueryはそれぞれデータ型
● to_tsvector、(plain)to_tsqueryはtext型をtsvector、tsqueryに変換する関数
tsvector @@ tsquery(検索対象) (検索式)
=> True / False
09/06/20
方法2:tsvector用の列を追加
● 高速。特にスコアによるソートをする場合
● 本文が更新された時にtsvectorは自動的に更新されない(トリガやバッチを使う必要がある)
● 容量は大きくなる
=> ALTER TABLE docs_en ADD vec tsvector;ALTER TABLE=> UPDATE docs_en SET vec = to_tsvector('english', body);UPDATE 936=> CREATE INDEX docs_en_idx2 ON docs_en USING GIN(vec);CREATE INDEX
検索=> SELECT title FROM docs_en WHERE vec @@ to_tsquery('english', 'search');
09/06/20
LIKEと全文検索の違い
=> select count(*) from docs_en where body ilike '%html%'; count------- 935(1 row)
=> select count(*) from docs_en where body ilike '%query%'; count------- 312(1 row)
=> select count(*) from docs_en where to_tsvector('english', body) @@ to_tsquery('html'); count------- 14(1 row)
=> select count(*) from docs_en where to_tsvector('english', body) @@ to_tsquery('query'); count------- 327(1 row)
09/06/20
tsvectorができるまで
09/06/20
転置インデックス
● 単語がどの文章に含まれているか(本の索引)● 転置インデックスを作成するためには文章を単語に分
ける必要がある(日本語の場合はわかち書き)● GIN(Generalized Inverted Index)● 全文検索の他にも、配列型などにも使われる
1 単語1 単語2
2 単語1 単語3 単語5
3 単語2 単語3 単語4
4 単語1 単語5
単語1
単語2
単語3
単語4
1,2,4
1,3
2,3
3
単語5 2,5
09/06/20
to_tsvector
● Parserが文章を23種類のtokenに分解
a fat cat sat on a mat - it <b>ate</b> a fat rats
a
fat
cat
sat
on
mat
it
ate
rats
Word, all ASCII XML tag
<b>
</b>
Space symbols
' '
-
09/06/20
to_tsvector
● token種別毎に正規化
a
fat
cat
sat
on
mat
it
ate
rats
Word, all ASCII
XML tag
<b>
</b>
Space symbols
' '
-
削除english_stem
fat
cat
sat
mat
ate
rat
Stopwordの削除語幹に縮小
09/06/20
token=> select * from ts_token_type('default'); tokid | alias | description-------+-----------------+------------------------------------------ 1 | asciiword | Word, all ASCII 2 | word | Word, all letters 3 | numword | Word, letters and digits 4 | email | Email address 5 | url | URL 6 | host | Host 7 | sfloat | Scientific notation 8 | version | Version number 9 | hword_numpart | Hyphenated word part, letters and digits 10 | hword_part | Hyphenated word part, all letters 11 | hword_asciipart | Hyphenated word part, all ASCII 12 | blank | Space symbols 13 | tag | XML tag 14 | protocol | Protocol head... 23 | entity | XML entity(23 rows)
09/06/20
Dictionaries
=> \dF+ english Text search configuration "pg_catalog.english"Parser: "pg_catalog.default" Token | Dictionaries-----------------+------------------------------- asciihword | english_stem asciiword | english_stem email | simple file | simple float | simple host | simple… numword | simple sfloat | simple uint | simple url | simple url_path | simple version | simple word | english_stem
brankやtagにはDictionaryが設定されていない
email、host等は語幹縮小しない
09/06/20
Dictionary
● ストップワード● インデックスに格納しないトークンの削除("a","the")
● Snowball● 語幹縮小"queries" => "queri"
=> select to_tsvector('query queries'); to_tsvector------------- 'queri':1,2(1 row)
=> select to_tsvector('http://www.postgresql.org/about/history'); to_tsvector-------------------------------------------------------------------------------- '/about/history':3 'www.postgresql.org':2 'www.postgresql.org/about/history':1(1 row)
09/06/20
Dictionary
● Simple、Sysnonym、Ispell、Thesaurus、Snowball● share/tsearch_data/● どのtoken typeにどの辞書を適用するかは変更可能
(ALTER TEXT SEARCH CONFIG...)(share/tsearch_data/english.stop)imemymyselfweouroursourselvesyouyour...
09/06/20
LIKEと全文検索の違い
=> select count(*) from docs_en where body ilike '%html%'; count------- 935(1 row)
=> select count(*) from docs_en where body ilike '%query%'; count------- 312(1 row)
=> select count(*) from docs_en where to_tsvector('english', body) @@ to_tsquery('html'); count------- 14(1 row)
=> select count(*) from docs_en where to_tsvector('english', body) @@ to_tsquery('query'); count------- 327(1 row)
09/06/20
ここまでのまとめ
● Token種別"tag"に対してDictionaryが設定されていないので、htmlタグはtsvectorでは無視される
● Token種別"asciiword"に対して設定された辞書"english_stem"により、文字列"query"も"queries"も"queri"と認識される
09/06/20
全文検索の機能
09/06/20
問い合わせ式 - tsquery
● to_tsquery()● '&'(AND)、'|'(OR)、'!'(NOT)、括弧● 詳細な検索条件が指定できるが、構文エラーに注意
● plainto_tsquery()● Tokenを'&'で結合する
● tsquery同士を演算子(&&、||)で結合することができる
=> select to_tsquery('fat & cat') && !! plainto_tsquery('sat mat'); ?column?------------------------------------ 'fat' & 'cat' & !( 'sat' & 'mat' )(1 row)
09/06/20
ts_rank
● ts_rank([weights float4[], ] vector tsvector, query tsquery[, normalization]) returns float4● 色々オプションがあるらしい
● ts_rankの引数にはtsvectorが必要
SELECT … ts_rank(to_tsvector(body), …)=> 1000件ヒットすると、1000回to_tsvector()が呼ばれる
SELECT … ts_rank(vec, …)=> あらかじめtsvectorの列を用意しておく
09/06/20
ts_headline
● ts_headline([regconfig, ]text, tsquery[, text])● 結果の強調表示
● StartSel、StopSel等設定可能
=> select ts_headline('fat cat sat mat', to_tsquery('cat')); ts_headline------------------------ fat <b>cat</b> sat mat(1 row)
09/06/20
configuration
● 全文検索で使う関数のふるまいをまとめたもの
● 省略された場合、default_text_search_configが使われる(postgresql.confやsetコマンドで指定できる)
to_tsvector('english', body)to_tsvector('simple', body)to_tsvector(body)
=> \dF
List of text search configurations Schema | Name | Description------------+------------+--------------------------------------- pg_catalog | danish | configuration for danish language pg_catalog | dutch | configuration for dutch language pg_catalog | english | configuration for english language
09/06/20
textsearch_ja
09/06/20
textsearch_ja
● default parserではわかち書きできない
● http://textsearch-ja.projects.postgresql.org/● Mecabを使って形態素解析
● 8.3、8.4に対応。Windows用バイナリ有り=> select to_tsvector('日本語を使ったfull text searchの例'); to_tsvector------------------------------------------------ 'searchの例':3 'text':2 '日本語を使ったfull':1(1 row)
=> select to_tsvector('japanese', '日本語を使ったfull text searchの例'); to_tsvector--------------------------------------------------------- 'full':3 'search':5 'text':4 '使う':2 '例':6 '日本語':1(1 row)
09/06/20
textsearch_jaのparser
● 非自立語を削除
● 動詞、助動詞を正規化● 「使った」->「使う」
● 英数はdefault parserでparseする(htmlは削除される)● tsqueryは、単語のANDになる
=> select to_tsquery('japanese', '全文検索'); to_tsquery----------------- '全文' & '検索'(1 row)
09/06/20
textsearch_jaと他の全文検索
● textsearch_jaはPostgreSQL本体の全文検索機能の拡張として実装されている● クラッシュリカバリやPITRを使うことができる
● tsearch2に対応したアプリをそのまま使える(MeidaWikiとか)
● 「PostgreSQL上にMeidaWiki環境を構築」http://lets.postgresql.jp/documents/tutorial/mediawiki/
09/06/20
その他のtextsearch_jaの機能
● というかmecabの機能● テキストの正規化(ja_normalize)● ふりがな(furigana)● ひらがな<->カタカナ(hiragana,katakana)● 等々
09/06/20
おまけ
09/06/20
参考
● Building search.postgresql.org(PGCon 2008)● http://www.pgcon.org/2008/schedule/events/75.en.html● www.postgresql.orgで使われているコードは
pgweb.postgresql.orgで公開されている
● https://pgweb.postgresql.org/browser/trunk/portal/tools/search
09/06/20
● Some recent advences in full-text search(PGcon 2009)● http://www.pgcon.org/2009/schedule/events/119.en.html● 8.4での新機能
– 前方一致検索等
● 8.5以降で実装予定の機能等
– フレーズ検索等