SlideShare a Scribd company logo
textsearch_jaで全文検索

             日本PostgreSQLユーザ会
                 北海道支部
           株式会社サイクル・オブ・フィフス
                  石田朗雄



09/06/20
自己紹介
 ●   id:iakio
      ●    http://postgresql.g.hatena.ne.jp/iakio/
      ●    今日の資料とデモのソースコードは公開します




09/06/20
自己紹介
 ●    代表作
        ●     SQLでボウリングのスコアを計算
 with recursive
 s(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 sof
 window 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つ作るだけで高速な全文検索ができ
     る

 => SELECT title FROM docs_en WHERE body ILIKE '%search%';




 インデックス作成
 => 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');

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
 => select count(*) from docs_en    where to_tsvector('english', body)
  where body ilike '%html%';        @@ to_tsquery('html');
  count                             count
 -------                           -------
    935                                14
 (1 row)                           (1 row)

                                   => select count(*) from docs_en
 => select count(*) from docs_en    where to_tsvector('english', body)
  where body ilike '%query%';       @@ to_tsquery('query');
  count                             count
 -------                           -------
    312                               327
 (1 row)                           (1 row)




09/06/20
tsvectorができるまで




09/06/20
転置インデックス

           1    単語1 単語2                単語1   1,2,4
           2   単語1 単語3 単語5             単語2   1,3
           3   単語2 単語3 単語4             単語3   2,3
           4    単語1 単語5                単語4    3
                                       単語5   2,5


 ●   単語がどの文章に含まれているか(本の索引)
 ●   転置インデックスを作成するためには文章を単語に分
     ける必要がある(日本語の場合はわかち書き)
 ●   GIN(Generalized Inverted Index)
 ●   全文検索の他にも、配列型などにも使われる


09/06/20
to_tsvector
 ●    Parserが文章を23種類のtokenに分解
            a fat cat sat on a mat - it <b>ate</b> a fat rats

     Word, all ASCII       XML tag           Space symbols
            a                 <b>                ' '
           fat               </b>                -
           cat
           sat
           on
           mat
            it
           ate
           rats



09/06/20
to_tsvector
 ●    token種別毎に正規化
                       Stopwordの削除
                         語幹に縮小

     Word, all ASCII                    Space symbols
            a                               ' '
           fat                    fat       -
           cat                    cat
           sat     english_stem   sat                   削除
           on                           XML tag
           mat                    mat      <b>
            it                            </b>
           ate                    ate
           rats                   rat



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、host等は
  email           | simple                         語幹縮小しない
  file            | simple
  float           | simple
  host            | simple
 …
  numword         | simple
  sfloat          | simple                  brankやtagにはDictionaryが
  uint            | simple                        設定されていない
  url             | simple
  url_path        | simple
  version         | simple
  word            | english_stem


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)
 i
 me
 my
 myself
 we
 our
 ours
 ourselves
 you
 your
 ...

09/06/20
LIKEと全文検索の違い

                                   => select count(*) from docs_en
 => select count(*) from docs_en    where to_tsvector('english', body)
  where body ilike '%html%';        @@ to_tsquery('html');
  count                             count
 -------                           -------
    935                                14
 (1 row)                           (1 row)

                                   => select count(*) from docs_en
 => select count(*) from docs_en    where to_tsvector('english', body)
  where body ilike '%query%';       @@ to_tsquery('query');
  count                             count
 -------                           -------
    312                               327
 (1 row)                           (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
 to_tsvector('english', body)
 to_tsvector('simple', body)
 to_tsvector(body)

 ●   全文検索で使う関数のふるまいをまとめたもの
 ●   省略された場合、default_text_search_configが使われ
     る(postgresql.confやsetコマンドで指定できる)
 => 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以降で実装予定の機能等
            –   フレーズ検索等




09/06/20

More Related Content

PDF
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
PDF
MySQL・PostgreSQLだけで作る高速あいまい全文検索システム
PPTX
DevOps勉強会
PDF
Railsで作るBFFの功罪
PDF
Apache Sparkにおけるメモリ - アプリケーションを落とさないメモリ設計手法 -
PPTX
Deep Dive into the Linux Kernel - メモリ管理におけるCompaction機能について
PDF
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
PDF
【18-A-2】ゲーミフィケーション・エバンジェリストが見る「あなたの技術力が“ワクワクするサービス”に変わる未来」
[CEDEC 2021] 運用中タイトルでも怖くない! 『メルクストーリア』におけるハイパフォーマンス・ローコストなリアルタイム通信技術の導入事例
MySQL・PostgreSQLだけで作る高速あいまい全文検索システム
DevOps勉強会
Railsで作るBFFの功罪
Apache Sparkにおけるメモリ - アプリケーションを落とさないメモリ設計手法 -
Deep Dive into the Linux Kernel - メモリ管理におけるCompaction機能について
ホットペッパービューティーにおけるモバイルアプリ向けAPIのBFF/Backend分割
【18-A-2】ゲーミフィケーション・エバンジェリストが見る「あなたの技術力が“ワクワクするサービス”に変わる未来」

What's hot (20)

PDF
1日5分でPostgreSQLに詳しくなるアプリの開発 ~PostgRESTを使ってみた~(第38回PostgreSQLアンカンファレンス@オンライン 発...
PDF
[Cloud OnAir] GCP 上でストリーミングデータ処理基盤を構築してみよう! 2018年9月13日 放送
PDF
継続的なモデルモニタリングを実現するKubernetes Operator
PPTX
ARマーカーを利用したHoloLens同士の位置合わせ
PDF
PostgreSQLでpg_bigmを使って日本語全文検索 (MySQLとPostgreSQLの日本語全文検索勉強会 発表資料)
PDF
Kuberneteの運用を支えるGitOps
PDF
Yahoo! JAPANのIaaSを支えるKubernetesクラスタ、アップデート自動化への挑戦 #yjtc
PDF
こんなに使える!今どきのAPIドキュメンテーションツール
PPTX
世界一わかりやすいClean Architecture
PDF
マイクロにしすぎた結果がこれだよ!
PDF
Apache Kafka 0.11 の Exactly Once Semantics
PPTX
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)
PDF
Using eBPF for High-Performance Networking in Cilium
PDF
AWS X-Rayによるアプリケーションの分析とデバッグ
PPTX
Amazon Kinesis Video Streams WebRTC 使ってみた
PDF
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
PDF
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
PDF
AWS市場動向と求められる人材、その育成方法について
PPTX
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
PDF
クラウドネイティブ時代の分散トレーシング - Distributed Tracing in a Cloud Native Age
1日5分でPostgreSQLに詳しくなるアプリの開発 ~PostgRESTを使ってみた~(第38回PostgreSQLアンカンファレンス@オンライン 発...
[Cloud OnAir] GCP 上でストリーミングデータ処理基盤を構築してみよう! 2018年9月13日 放送
継続的なモデルモニタリングを実現するKubernetes Operator
ARマーカーを利用したHoloLens同士の位置合わせ
PostgreSQLでpg_bigmを使って日本語全文検索 (MySQLとPostgreSQLの日本語全文検索勉強会 発表資料)
Kuberneteの運用を支えるGitOps
Yahoo! JAPANのIaaSを支えるKubernetesクラスタ、アップデート自動化への挑戦 #yjtc
こんなに使える!今どきのAPIドキュメンテーションツール
世界一わかりやすいClean Architecture
マイクロにしすぎた結果がこれだよ!
Apache Kafka 0.11 の Exactly Once Semantics
大量のデータ処理や分析に使えるOSS Apache Spark入門(Open Source Conference 2021 Online/Kyoto 発表資料)
Using eBPF for High-Performance Networking in Cilium
AWS X-Rayによるアプリケーションの分析とデバッグ
Amazon Kinesis Video Streams WebRTC 使ってみた
続・PFN のオンプレML基盤の取り組み / オンプレML基盤 on Kubernetes 〜PFN、ヤフー〜 #2
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
AWS市場動向と求められる人材、その育成方法について
Kubernetesでの性能解析 ~なんとなく遅いからの脱却~(Kubernetes Meetup Tokyo #33 発表資料)
クラウドネイティブ時代の分散トレーシング - Distributed Tracing in a Cloud Native Age
Ad

Similar to textsearch_jaで全文検索 (20)

PPTX
PHP AST 徹底解説
PDF
Rubysapporo Stringsearch
PDF
RとSQLiteで気軽にデータベース作成
PPTX
Prosym2012
PDF
Exgettextの話
PDF
Hello Dark-Side C# (Part. 1)
PDF
Rのデータ構造とメモリ管理
PDF
Tokyo r sqldf
PDF
Elasticsearch入門 pyfes 201207
PDF
つくってあそぼ ラムダ計算インタプリタ
PDF
入門機械学習1,2章
PDF
PostgreSQL 12の話
PDF
Write good parser in perl
PPTX
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
PDF
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
PDF
20181110 fok2018-pg-extension
PDF
PostgreSQL Unconference #29 Unicode IVS
PPT
Uart受信設計2013
KEY
Clojure programming-chapter-2
PPT
Maatkit で MySQL チューニング
PHP AST 徹底解説
Rubysapporo Stringsearch
RとSQLiteで気軽にデータベース作成
Prosym2012
Exgettextの話
Hello Dark-Side C# (Part. 1)
Rのデータ構造とメモリ管理
Tokyo r sqldf
Elasticsearch入門 pyfes 201207
つくってあそぼ ラムダ計算インタプリタ
入門機械学習1,2章
PostgreSQL 12の話
Write good parser in perl
JJUG CCC 2017 Fall オレオレJVM言語を作ってみる
Intel AVX-512/富岳SVE用SIMDコード生成ライブラリsimdgen
20181110 fok2018-pg-extension
PostgreSQL Unconference #29 Unicode IVS
Uart受信設計2013
Clojure programming-chapter-2
Maatkit で MySQL チューニング
Ad

More from Akio Ishida (11)

PDF
Prophecyを使ったユニットテスト
PDF
よりよいPHPUnitの実行方法を求めて
PDF
phpspecで学ぶLondon School TDD
PDF
PostgreSQLの範囲型と排他制約
PDF
Getting start with knockout.js
PDF
XIDを周回させてみよう
PDF
Local php-100828 2
PDF
Ruby Postgres 2009
PDF
使いこなそうGUC
PDF
PostgreSQLで学ぶBoyer-Moore-Horspoolアルゴリズム
PDF
Ruby Postgres
Prophecyを使ったユニットテスト
よりよいPHPUnitの実行方法を求めて
phpspecで学ぶLondon School TDD
PostgreSQLの範囲型と排他制約
Getting start with knockout.js
XIDを周回させてみよう
Local php-100828 2
Ruby Postgres 2009
使いこなそうGUC
PostgreSQLで学ぶBoyer-Moore-Horspoolアルゴリズム
Ruby Postgres

textsearch_jaで全文検索

  • 1. textsearch_jaで全文検索 日本PostgreSQLユーザ会 北海道支部 株式会社サイクル・オブ・フィフス 石田朗雄 09/06/20
  • 2. 自己紹介 ● id:iakio ● http://postgresql.g.hatena.ne.jp/iakio/ ● 今日の資料とデモのソースコードは公開します 09/06/20
  • 3. 自己紹介 ● 代表作 ● SQLでボウリングのスコアを計算 with recursive s(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 sof window w as (order by idx) 09/06/20
  • 4. 告知など ● PostgreSQL的な話 ● 8.4RC1が6/14に出ました ● JPUG北海道支部的な話 ● 5/13に勉強会を開催 ● 次は7/8? ● JPUG的な話 ● JPUG 10th Anniversary Conference(11/20~21) 09/06/20
  • 6. PostgreSQLでの全文検索 ● PostgreSQL8.2以前 ● contrib/tsearch2 ● PostgreSQL8.3 ● 全文検索機能が本体に含まれるようになった。 ● 日本語は未対応 ● textsearch_ja ● 日本語で全文検索を行なうための拡張モジュール ● http://textsearch-ja.projects.postgresql.org/ ● textsearch_sennaの話は今日はありません 09/06/20
  • 7. 資料に自信が無いので とりあえずデモ 09/06/20
  • 8. デモの構成 ● PostgreSQL 8.4RC1(8.3でも同じです) ● データベースエンコーディングはutf-8 ● PostgreSQLのドキュメントを格納したテーブル(html) ● レコード数:900くらい ● 詳しくはブースで!! => d docs_en カラム | 型 | --------+----------+------------ id | integer | path | text | title | text | body | text | 09/06/20
  • 10. 方法1:関数インデックス ● インデックスを1つ作るだけで高速な全文検索ができ る => SELECT title FROM docs_en WHERE body ILIKE '%search%'; インデックス作成 => 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'); 09/06/20
  • 11. 全文検索の基本 ● tsvector、tsqueryはそれぞれデータ型 ● to_tsvector、(plain)to_tsqueryはtext型をtsvector、 tsqueryに変換する関数 tsvector @@ tsquery (検索対象) (検索式) => True / False 09/06/20
  • 12. 方法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
  • 13. LIKEと全文検索の違い => select count(*) from docs_en => select count(*) from docs_en where to_tsvector('english', body) where body ilike '%html%'; @@ to_tsquery('html'); count count ------- ------- 935 14 (1 row) (1 row) => select count(*) from docs_en => select count(*) from docs_en where to_tsvector('english', body) where body ilike '%query%'; @@ to_tsquery('query'); count count ------- ------- 312 327 (1 row) (1 row) 09/06/20
  • 15. 転置インデックス 1 単語1 単語2 単語1 1,2,4 2 単語1 単語3 単語5 単語2 1,3 3 単語2 単語3 単語4 単語3 2,3 4 単語1 単語5 単語4 3 単語5 2,5 ● 単語がどの文章に含まれているか(本の索引) ● 転置インデックスを作成するためには文章を単語に分 ける必要がある(日本語の場合はわかち書き) ● GIN(Generalized Inverted Index) ● 全文検索の他にも、配列型などにも使われる 09/06/20
  • 16. to_tsvector ● Parserが文章を23種類のtokenに分解 a fat cat sat on a mat - it <b>ate</b> a fat rats Word, all ASCII XML tag Space symbols a <b> ' ' fat </b> - cat sat on mat it ate rats 09/06/20
  • 17. to_tsvector ● token種別毎に正規化 Stopwordの削除 語幹に縮小 Word, all ASCII Space symbols a ' ' fat fat - cat cat sat english_stem sat 削除 on XML tag mat mat <b> it </b> ate ate rats rat 09/06/20
  • 18. 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
  • 19. Dictionaries => dF+ english Text search configuration "pg_catalog.english" Parser: "pg_catalog.default" Token | Dictionaries -----------------+------------------------------- asciihword | english_stem asciiword | english_stem email、host等は email | simple 語幹縮小しない file | simple float | simple host | simple … numword | simple sfloat | simple brankやtagにはDictionaryが uint | simple 設定されていない url | simple url_path | simple version | simple word | english_stem 09/06/20
  • 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
  • 21. Dictionary ● Simple、Sysnonym、Ispell、Thesaurus、Snowball ● share/tsearch_data/ ● どのtoken typeにどの辞書を適用するかは変更可能 (ALTER TEXT SEARCH CONFIG...) (share/tsearch_data/english.stop) i me my myself we our ours ourselves you your ... 09/06/20
  • 22. LIKEと全文検索の違い => select count(*) from docs_en => select count(*) from docs_en where to_tsvector('english', body) where body ilike '%html%'; @@ to_tsquery('html'); count count ------- ------- 935 14 (1 row) (1 row) => select count(*) from docs_en => select count(*) from docs_en where to_tsvector('english', body) where body ilike '%query%'; @@ to_tsquery('query'); count count ------- ------- 312 327 (1 row) (1 row) 09/06/20
  • 23. ここまでのまとめ ● Token種別"tag"に対してDictionaryが設定されていない ので、htmlタグはtsvectorでは無視される ● Token種別"asciiword"に対して設定された辞 書"english_stem"により、文字 列"query"も"queries"も"queri"と認識される 09/06/20
  • 25. 問い合わせ式 - 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
  • 26. 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
  • 27. 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
  • 28. configuration to_tsvector('english', body) to_tsvector('simple', body) to_tsvector(body) ● 全文検索で使う関数のふるまいをまとめたもの ● 省略された場合、default_text_search_configが使われ る(postgresql.confやsetコマンドで指定できる) => 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
  • 30. 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
  • 31. textsearch_jaのparser ● 非自立語を削除 ● 動詞、助動詞を正規化 ● 「使った」->「使う」 ● 英数はdefault parserでparseする(htmlは削除される) ● tsqueryは、単語のANDになる => select to_tsquery('japanese', '全文検索'); to_tsquery ----------------- '全文' & '検索' (1 row) 09/06/20
  • 32. textsearch_jaと他の全文検索 ● textsearch_jaはPostgreSQL本体の全文検索機能の拡 張として実装されている ● クラッシュリカバリやPITRを使うことができる ● tsearch2に対応したアプリをそのまま使える(MeidaWikiと か) ● 「PostgreSQL上にMeidaWiki環境を構築」 http://lets.postgresql.jp/documents/tutorial/mediawiki/ 09/06/20
  • 33. その他のtextsearch_jaの機能 ● というかmecabの機能 ● テキストの正規化(ja_normalize) ● ふりがな(furigana) ● ひらがな<->カタカナ(hiragana,katakana) ● 等々 09/06/20
  • 35. 参考 ● 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
  • 36. Some recent advences in full-text search(PGcon 2009) ● http://www.pgcon.org/2009/schedule/events/119.en.html ● 8.4での新機能 – 前方一致検索等 ● 8.5以降で実装予定の機能等 – フレーズ検索等 09/06/20