Your SlideShare is downloading. ×
0
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
pg_trgmと全文検索
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

pg_trgmと全文検索

5,082

Published on

正式版は以下URLをご参照ください。 …

正式版は以下URLをご参照ください。
http://www.slideshare.net/hadoopxnttdata/pgtrgm

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
5,082
On Slideshare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
33
Comments
0
Likes
2
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. つかってみよう”pg_trgm” やってみよう”全文検索” 2013年2月16日 株式会社NTTデータ 基盤システム事業本部 澤田 雅彦Copyright © 2013 NTT DATA Corporation
  • 2. INDEX 01 全文検索とは? 02 pg_trgmってなに? 03 pg_trgmの動きを見てみよう 04 まとめCopyright © 2013NTT DATA Corporation 2
  • 3. 1. 全文検索とは?Copyright © 2013 NTT DATA Corporation 3
  • 4. 1.1 全文検索ってなに?全文検索ってなに? 複数にまたがるテキストからキーワードを含むテキストを見つけ出す事 東京都・・・・ キーワード ・・・・・・・・ 東京都・・・・ ・・・・・・・・・図書館・・・・ 「オープンソース」 ・・・・・・・・ ・・・・・・・・ ・・・・・・・・・図書館・・・・ 東京都で・・・・ ・・・・・・・・・・・・ ・・・・・・・・ ・・・・・・・・ 東京都・・・・ ・・オープンソース・・・ ・・・・・・・・ ・・・・・・・・・・・・ ・・・・・・ ・・・データベース・・・ ・・オープンソース・・・ ・・・・・・・・・図書館・・・・ ・・・・・・・・ ・・・・・・・・ ・・・・・・・・ ・・・・・・・・ ・・・・・ 全文検索 ・・・・・・・・・・・・ ・・・・・・・・本。 ・・・・・・・・・・・・ ・・・・・ ・・・・・ ・学校・・・・・・・・・ ・・・・・・・・本。 オープンソース ・・ ・・・・・・・・ ・・・ ・学校・・・・・・・・・ ・・・・・・・・ ・・・・・ ・・・・・・・・本。 ・学校・・・・・・・・・ Copyright © 2013 NTT DATA Corporation 4
  • 5. 1.2 DBの全文検索ってなに? テキスト型の列を持つテーブルから、キーワードを含むレコードを検索すること  一般的に、「全文検索機能がある」といえば、高速にできることを表す  しかし、全文検索ではBtree等のインデックスを使用できないため遅い!  なので、ツールを用いてインデックスを張る必要がある 全文検索を実現するには。。。  N-gram方式、形態素解析方式がある キーワード:「オープンソース」 DB SQL発行 : : Copyright © 2013 NTT DATA Corporation 5
  • 6. 1.3 N-gram解析と形態素解析 形態素解析 N-gram方式分割方法 単語単位で分割 文字単位で分割インデックスサ ○(単語単位) ×(分割数が多いため)イズ表記の揺れ ○(類義語を定義しやすい) △(表記の揺れに弱い) △(単語の分割精度に依存す検索結果 ○(LIKEに近い検索結果になる) る)どういう時に使 整った文章(論文等)を扱う時 記号や造語を検索する時える? 例)文字列‘今日は寒天の日’ではどうなる? (3-gramの場合)キーワード 「今日」,「寒天」,「日」 「今日は」,「日は寒」,「は寒天」, 「寒天の」,「天の日」 Copyright © 2013 NTT DATA Corporation 6
  • 7. 1.4 PostgreSQLで全文検索でインデックスを使うためのモジュール pg_trgm textsearch_senna textsearch_ja 解析方式 3-gram N-gram 形態素解析 対応バージョン 9.1以降 8.2以降 8.3以降 提供形態 contribモジュール 外部ツール 外部ツール 開発主体 PostgreSQLコミュニティ 板垣さん(個人) 板垣さん(個人) なし Mecab 依存モジュール Senna (PostgreSQLのGin、GiSTを利用) (PostgreSQLのGin、GiSTを利用)レプリケーション対応 ○ × ○ リカバリ対応 ○ × ○ △(ソース内を再設定しないと 日本語対応 ○ ○ いけない) 以下、pg_trgmを扱っていきます Copyright © 2013 NTT DATA Corporation 7
  • 8. 2. pg_trgmとは?Copyright © 2013 NTT DATA Corporation 8
  • 9. 2.1 pg_trgmとは 全文検索はPostgreSQL9.1から対応 contribモジュールとして提供 3-gram方式 GIN,GiSTインデックスに対応 レプリケーション・リカバリに対応 名前 検索 構築・更新 GIN 汎用転置インデックス 速い 遅い GiST 汎用検索ツリー 遅い 速い Copyright © 2013 NTT DATA Corporation 9
  • 10. 2.2 インストール方法インストール方法$ cd $PGSRC/contrib/pg_trgm【ビルド時の注意】日本語対応させるためには。。。trgm.hの #define KEEPONLYALNUM を必ずコメントアウトする!$ make$ make install Copyright © 2013 NTT DATA Corporation 10
  • 11. 2.3 動作確認postgres=# CREATE EXTENSION pg_trgm;postgres=# CREATE TABLE tbl (col1 text);postgres=# CREATE INDEX idx on tbl USING gin (col1 gin_trgm_ops); ←INDEX作成postgres=# INSERT INTO tbl VALUES (test);postgres=# EXPLAIN SELECT * FROM tbl WHERE col1 LIKE %test%; QUERY PLAN-------------------------------------------------------------------- Bitmap Heap Scan on tbl (cost=16.16..26.43 rows=21 width=32) Recheck Cond: (col1 ~~ %test%::text) -> Bitmap Index Scan on idx (cost=0.00..16.16 rows=21 width=0) Index Cond: (col1 ~~ %test%::text)(4 rows) Copyright © 2013 NTT DATA Corporation 11
  • 12. 2.4 インデックスを使ったとき、使わなかったとき 10万件のデータの中から、少量のデータを取り出すケースで検証。インデックス使用postgres=# EXPLAIN ANALYZE SELECT * FROM tbl WHERE col1 LIKE %京都府%; QUERY PLAN--------------------------------------------------------------- Bitmap Heap Scan on tbl (cost=20.08..55.53 rows=10 width=32) (actual time=0.021..0.022 rows=3 loops=1) Recheck Cond: (col1 ~~ %京都府%::text) -> Bitmap Index Scan on idx (cost=0.00..20.07 rows=10 width=0) (actual time=0.013..0.013 rows=3 loops=1) Index Cond: (col1 ~~ %京都府%::text)Total runtime: 0.051 ms インデックス不使用 400倍以上の差postgres=# EXPLAIN ANALYZE SELECT * FROM tbl WHERE col1 LIKE %京都府%; QUERY PLAN---------------------------------------------------------------Seq Scan on tbl (cost=0.00..1662.00 rows=10 width=32) (actual time=22.282..22.284 rows=3 loops=1) Filter: (col1 ~~ %京都府%::text) Total runtime: 22.303 ms Copyright © 2013 NTT DATA Corporation 12
  • 13. 2.5 2文字以下の検索 pg_trgmは、3文字単位で区切るため、2文字以下の検索ではインデックスを効率的に使 えない。  逆にインデックスを使うと「Bitmapの全件アクセス」になるため、SeqScanより遅い。  英語の全文検索では1,2文字はストップワード(inやa)であることが多いので問題な いのかも。。  しかし日本語では「本」、「学校」など1,2文字で全文検索をする可能性は十分ある!postgres=# EXPLAIN ANALYZE SELECT * FROM tbl WHERE col1 LIKE %京%; インデックス使用 QUERY PLAN-----------------------------------------------------------------------------------------------------Bitmap Heap Scan on tbl (cost=938.92..2600.80 rows=99990 width=32) (actual time=96.956..139.761 rows=100003 loops=1) Recheck Cond: (col1 ~~ %京%::text) -> Bitmap Index Scan on idx (cost=0.00..913.92 rows=99990 width=0) (actual time=96.874..96.874 rows=100003 loops=1) Index Cond: (col1 ~~ %京%::text) Total runtime: 160.489 ms(5 rows) インデックスを使った方が遅いpostgres=# EXPLAIN ANALYZE SELECT * tbl WHERE col1 LIKE %京%; インデックス不使用 QUERY PLAN---------------------------------------------------------------------------------------------------- Seq Scan on tbl (cost=0.00..1662.00 rows=99990 width=32) (actual time=0.014..40.286 rows=100003 loops=1) Filter: (col1 ~~ %京%::text) Total runtime: 59.661 ms(3 rows) Copyright © 2013 NTT DATA Corporation 13
  • 14. 3. pg_trgmの動きを見てみようCopyright © 2013 NTT DATA Corporation 14
  • 15. 3.1 どんな動きをするの?(インデックス登録編) ※△=半角空白INSERT INTO tbl VALUES(‘ あいうABC’); TABLE SQL発行 TID データ 1 あいうABC INDEX キー TID Copyright © 2013 NTT DATA Corporation 15
  • 16. 3.1 どんな動きをするの?(インデックス登録編) ※△=半角空白INSERT INTO tbl VALUES(‘ あいうABC’); TABLE SQL発行 TID データ 1 あいうABC ① 3文字単位に INDEX 分割(前後にス キー TID ペースを追加) △△あ △あい あいう いうA うAB ABC BC△ Copyright © 2013 NTT DATA Corporation 16
  • 17. 3.1 どんな動きをするの?(インデックス登録編) ※△=半角空白INSERT INTO tbl VALUES(‘ あいうABC’); TABLE SQL発行 TID データ 1 あいうABC ① ② 3文字単位に 4B以上は3Bに INDEX 分割(前後にス ハッシュ変換 キー TID ペースを追加) + ソート △△あ CRC1 △あい CRC2 あいう CRC3 いうA CRC4 うAB CRC5 ABC ABC BC△ BC△ Copyright © 2013 NTT DATA Corporation 17
  • 18. 3.1 どんな動きをするの?(インデックス登録編) ※△=半角空白INSERT INTO tbl VALUES(‘ あいうABC’); TABLE SQL発行 TID データ 1 あいうABC ① ② ③ 3文字単位に 4B以上は3Bに INT値に変換 INDEX 分割(前後にス ハッシュ変換 キー TID ペースを追加) + ソート △△あ CRC1 INT1 △あい CRC2 INT2 あいう CRC3 INT3 いうA CRC4 INT4 うAB CRC5 INT5 ABC ABC 1111 BC△ BC△ 2222 Copyright © 2013 NTT DATA Corporation 18
  • 19. 3.1 どんな動きをするの?(インデックス登録編) ※△=半角空白INSERT INTO tbl VALUES(‘ あいうABC’); TABLE SQL発行 TID データ 1 あいうABC ① ② ③ 3文字単位に 4B以上は3Bに INT値に変換 INDEX 分割(前後にス ハッシュ変換 キー TID ペースを追加) + ソート INT1 1 △△あ CRC1 INT1 INT2 1 △あい CRC2 INT2 INT3 1 あいう CRC3 INT3 INT4 1 いうA CRC4 INT4 INT5 INT5 1 うAB CRC5 ABC 1111 1111 1 ABC BC△ BC△ 2222 2222 1 Copyright © 2013 NTT DATA Corporation 19
  • 20. 3.2 どんな動きをするの?(インデックス検索編) TABLE TID データSELECT * FROM tbl WHERE col1 LIKE ‘%あいうA%’; 1 あいうABC SQL発行 2 あいうDEF INDEX キー TID あいう 1,2 いうA 1 いうD 2 : : うAB 1 うDE 2 : : ※INT値への変換を省いています Copyright © 2013 NTT DATA Corporation 20
  • 21. 3.2 どんな動きをするの?(インデックス検索編) TABLE TID データSELECT * FROM tbl WHERE col1 LIKE ‘%あいうA%’; 1 あいうABC SQL発行 2 あいうDEF①3文字単位に分割 INDEX キー TID あいう あいう 1,2 いうA いうA 1 いうD 2 : : うAB 1 うDE 2 : : ※INT値への変換を省いています Copyright © 2013 NTT DATA Corporation 21
  • 22. 3.2 どんな動きをするの?(インデックス検索編) TABLE TID データSELECT * FROM tbl WHERE col1 LIKE ‘%あいうA%’; 1 あいうABC SQL発行 2 あいうDEF① ②3文字単位に インデックスを検索分割 INDEX キー TID あいう あいう 1,2 いうA いうA 1 いうD 2 : : うAB 1 うDE 2 : : ※INT値への変換を省いています Copyright © 2013 NTT DATA Corporation 22
  • 23. 3.2 どんな動きをするの?(インデックス検索編) TABLE TID データSELECT * FROM tbl WHERE col1 LIKE ‘%あいうA%’; 1 あいうABC SQL発行 2 あいうDEF① ② ③3文字単位に インデックスを検索 TID決定分割 INDEX キー TID あいう あいう 1,2 「あいう」→1,2 いうA いうA 1 「いうA」→1 いうD 2 より、TID1 : : うAB 1 うDE 2 : : ※INT値への変換を省いています Copyright © 2013 NTT DATA Corporation 23
  • 24. 3.2 どんな動きをするの?(インデックス検索編) TABLE TID データSELECT * FROM tbl WHERE col1 LIKE ‘%あいうA%’; 1 あいうABC SQL発行 2 あいうDEF① ② ③ ④3文字単位に インデックスを検索 TID決定 Recheck処理分割 INDEX キー TID あいう あいう 1,2 「あいう」→1,2 PostgreSQL内部の いうA いうA 1 「いうA」→1 Recheck処理行う いうD 2 より、TID1 : : うAB 1 うDE 2 : : ※INT値への変換を省いています Copyright © 2013 NTT DATA Corporation 24
  • 25. 3.3 Recheck処理の必要性例えばこんな時。。 INDEX キー TID 小学校 1 TABLE 学校長 1検索ワード: 1 小学校と学校長 学校と 1 : :「小学校長」 : : Recheck処理で再検査! Copyright © 2013 NTT DATA Corporation 25
  • 26. 3.3 Recheck処理の必要性例えばこんな時。。 INDEX キー TID 小学校 1 TID決定 INDEXを検索 TABLE 学校長 1検索ワード: 1 小学校と学校長 学校と 1 : :「小学校長」 : : 「小学校」 : TID1 間違った結果を取ってき 「学校長」 : TID1 てしまう Recheck処理で再検査! Copyright © 2013 NTT DATA Corporation 26
  • 27. 3.3 Reckech処理の必要性 Bitmap Index Scanでは1行検出しているが、 Rechek処理により間違った結果を排除している ことがわかる。実際に見てみる。postgres=# EXPLAIN ANALYZE SELECT * FROM tbl2 WHERE col1 LIKE %小学校長%; QUERY PLAN---------------------------------------------------------Bitmap Heap Scan on tbl2 (cost=16.00..20.01 rows=1 width=32) (actualtime=0.019..0.019 rows=0 loops=1) Recheck Cond: (col1 ~~ %小学校長%::text) 1 -> Bitmap Index Scan on tbl2idx (cost=0.00..16.00 rows=1 width=0) (actualtime=0.010..0.010 rows= loops=1) Index Cond: (col1 ~~ %小学校長%::text) Total runtime: 0.046 ms(5 rows) Copyright © 2013 NTT DATA Corporation 27
  • 28. 4. まとめCopyright © 2013 NTT DATA Corporation 28
  • 29. 4. まとめ pg_trgmの強み  pg_trgmを使うことで、全文検索を高速に行う事が出来る。  contribモジュールに入っているため、メンテナンスを破棄される可能 性が低い pg_trgmの弱み  二文字以下の検索では効率的なインデックス検索ができない(日本 語では「本」、「学校」など利用シーンはある)  日本語対応させるためには、ソース内の設定を変更しなくてはいけ ない Copyright © 2013 NTT DATA Corporation 29
  • 30. Copyright © 2011 NTT DATA CorporationCopyright © 2013 NTT DATA Corporation
  • 31. (参考)ワイルドカードの有無による検索の挙動の違い・インデックスに登録するときは先頭に2つ、末尾1つに空白を追加して3文字分割する。 →”cat”の場合は、”△△c”,”△ca”,”cat”,”at△” TID データ キー TID 1 ABC △△A 1,2 2 ABCD △△X 3 3 XABC △AB 1,2 △XA 3 ‘△AB’ 1,2 ‘ABC’→ ’ABC’ → 1,2,3 → 1 ABC 1,2,3 ‘BC△’ 1,3 ‘△△A’ 1,2 BC△ 1,3 BCD 2 CD△ 2 ‘%ABC%’ → ‘ABC’ →1,2,3 XAB 3 Copyright © 2013 NTT DATA Corporation 31
  • 32. (参考)Gin,Gistの更新・構築、検索速度の差○Ginはなぜ更新・構築が遅い?→一つのレコード挿入につき、分割した単語分のインデックスを更新する必要があるため。 (例:1000文字のレコードを1行INSERTするとGINインデックスは最大1000個更新する必要がある)→それに比べ、Gistは一つのレコード挿入につき、インデックスには一つ登録するだけなので、Ginに比べると早い。○Gistはなぜ検索が遅い?→Gistではインデックスに登録された値と文章が非可逆なため、列候補を挙げた後、再チェックする必要があります。そのため、検索が遅くなります。 Copyright © 2013 NTT DATA Corporation 32
  • 33. (参考)CRC処理のソースCRC処理のソース部分。static voidcnt_trigram(trgm *tptr, char *str, int bytelen){ if (bytelen == 3) #define INIT_CRC32(crc) ((crc) = 0xFFFFFFFF) { #define FIN_CRC32(crc) ((crc) ^= 0xFFFFFFFF) CPTRGM(tptr, str); #define COMP_CRC32(crc, data, len)¥ } do { ¥ else const unsigned char *__data = (const unsigned char *)(data); ¥ uint32 __len = (len); ¥ { ¥ pg_crc32 crc; while (__len-- > 0) ¥ {¥ INIT_CRC32(crc); int __tab_index = ((int) ((crc) >> 24) ^ *__data++) & 0xFF; ¥ COMP_CRC32(crc, str, bytelen); (crc) = pg_crc32_table[__tab_index] ^ ((crc) << 8); ¥ FIN_CRC32(crc); }¥ } while (0) /* * use only 3 upper bytes from crc, hope, its good enough hashing */ CPTRGM(tptr, &crc); }} Copyright © 2013 NTT DATA Corporation 33
  • 34. (参考)KEEPONLYALNUMをコメントアウトしなかったら○trgm_op.cのソースの一部#ifdef KEEPONLYALNUM#define iswordchr(c) (t_isalpha(c) || t_isdigit(c)) ←英数字の時にTrue#else#define iswordchr(c) (!t_isspace(c)) ←スペースでないときにTrue#endifstatic char *○trgm_gin.cのソースの一部(データから空白を除いて文字の塊を見つけるところ。例:’today is sunny’→’today’,’is’,’sunny’)find_word(char *str, int lenstr, char **endword, int *charlen){ char *beginword = str; while (beginword - str < lenstr && !iswordchr(beginword)) beginword += pg_mblen(beginword); if (beginword - str >= lenstr) return NULL; *endword = beginword; *charlen = 0; while (*endword - str < lenstr && iswordchr(*endword)) { *endword += pg_mblen(*endword); (*charlen)++; } return beginword;} Copyright © 2013 NTT DATA Corporation 34

×