textsearch-ja: Project Home Page

# textsearch_ja : 形態素解析方式 全文検索

Top > textsearch_ja

形態素解析を使用した、組み込み型の日本語全文検索です。

- ダウンロード : ソースコードのほか、Windows 用バイナリもダウンロードできます。
- バグレポート
- メーリングリスト への参加

1. 概要
2. インストール
   - 依存関係
   - MeCab
3. テキスト検索機能
   - インデックス (tsvector, tsquery)
   - 検索結果の強調 (ts_headline)
   - 解析結果の表示 (ts_debug)
   - 類義語 (synonym)
   - ストップワード (stop word)
4. その他の検索用関数
   - Web検索互換クエリ (web_query)
5. 日本語解析機能
   - テキストの正規化 (ja_normalize)
   - 分かち書き (ja_wakachi)
   - mecab による解析 (ja_analyze)
   - ふりがな (furigana)
   - ひらがな変換 (hiragana)
   - カタカナ変換 (katakana)
6. TODO

## 概要

日本語テキストの全文検索を行います。 PostgreSQL 8.3 で追加された組み込みテキスト検索を拡張するため、 英語文書の検索と同様の方法で、日本語文書を検索することができます。 検索は形態素解析を利用した単語単位で行われます。 形態素解析には MeCab を使用しています。

利点として、GIN または GiST インデックスをベースにしているため、全文検索用のインデックスがリカバリ可能であることが挙げられます。 また、既に tsearch2 に対応している欧米言語を対象とした製品を大きく改変することなく、日本語対応できる強みがあります。

非自立語を除外してキーワードを抽出するため、インデックスのサイズを小さく押さえられます。 以下の例では「すもも」と「もも」のみ単語として扱っています。 単語ごとではなく文字ごとの検索が必要な場合には、代わりに textsearch_senna を使用してください。

    =# SELECT to_tsvector('japanese', 'すもももももももものうち');
          to_tsvector
    -----------------------
     'すもも':1 'もも':2,3
    (1 row)

## インストール

### 依存関係

以下の外部プロジェクトに依存しています。

- PostgreSQL : 8.3 以降
- mecab : 0.97 にて動作確認。
- mecab-ipadic : 2.7.0-20070801 にて動作確認。辞書とサーバの文字エンコードを一致させる必要があります。

### MeCab

Windows 版のインストーラを使う場合、辞書の文字コードの選択 で UTF-8 を選んでください。 mecab-dict-index で辞書を再編成することもできます。 詳しくは MeCab のマニュアルを参照してください。

## テキスト検索機能

インストールすると、pg_catalog.japanese という名前のテキスト検索設定が登録されます。 以下の形式で使用します。

- to_tsvector('japanese', '検索対象')
- to_tsquery('japanese', 'クエリ')

入力テキストは、まず、後述の ja_normalize() 関数を使用して正規化されます。 正規化後の文字列に対して、形態素解析で単語を分割してインデックスを張ります。

サーバエンコーディングと、mecab のエンコーディングを一致させる必要があります。 プラットホームによっては、mecab 辞書の再コンパイルが必要になるかもしれません。

### インデックス (tsvector, tsquery)

textsearch では、関数インデックスを使用して直接検索する方式と、 追加した補助カラムをキーとして検索する方式があります。 詳しくはドキュメント Full Text Search/Creating Indexes を参照してください。 補助カラムの自動更新は、tsvector_update_trigger に任せることもできます。

    =# CREATE TABLE test (id serial, t text);
    =# COPY test(t) FROM '...';
    =# CREATE INDEX idx ON test USING gin(to_tsvector('japanese', t));
    =# ANALYZE;
    =# EXPLAIN SELECT * FROM test WHERE to_tsvector('japanese', t) @@ to_tsquery('japanese', 'リレーショナルデータベース');
                                                          QUERY PLAN
    -----------------------------------------------------------------------------------------------------------------------
     Index Scan using idx on test  (cost=0.00..8.27 rows=1 width=248)
       Index Cond: (to_tsvector('japanese'::regconfig, t) @@ '''リレーショナル'' & ''データベース'''::tsquery)
    (2 rows)

### 検索結果の強調 (ts_headline)

ts_headline() に対応しており、一致した箇所を切り出して強調表示できます。

    =# \d document
                             Table "public.document"
     Column |   Type   |                      Modifiers
    --------+----------+-------------------------------------------------------
     id     | integer  | not null default nextval('document_id_seq'::regclass)
     body   | text     |
     tsv    | tsvector |
    Indexes:
        "document_pkey" PRIMARY KEY, btree (id)
        "document_tsv_index" gin (tsv)
    Triggers:
        tsv_trigger BEFORE INSERT OR UPDATE ON document FOR EACH ROW EXECUTE PROCEDURE
          tsvector_update_trigger('tsv', 'pg_catalog.japanese', 'body')

    =# SELECT id, ts_rank_cd(tsv, query) AS rank, ts_headline('japanese', body, query)
         FROM document, to_tsquery('japanese', 'リーフページ') AS query
        WHERE tsv @@ query ORDER BY rank DESC;
     id |   rank   |                                                                 ts_headline
    ----+----------+----------------------------------------------------------------------------------------------------------------------------------------------
      3 | 0.108333 | <b>ページ</b>中で隣接しているキーである。これは非ユニークキーに対しては動作しない ( たとえば、いくつかの<b>リーフ</b><b>ページ</b>にまたがっ
      2 |     0.01 | <b>ページ</b>を指しているはずである。同じ方法で、つまりヒープタプルへのリンクを調査することで、<b>リーフ</b>レベルにある複数の item
    (2 rows)

### 解析結果の表示 (ts_debug)

    =# SELECT * FROM ts_debug('japanese', '日本語とEnglishがmixedな文も解析OKです。');
       alias   |    description    |  token  |  dictionaries  |  dictionary  |  lexemes
    -----------+-------------------+---------+----------------+--------------+-----------
     word      | Word, all letters | 日本語  | {simple}       | simple       | {日本語}
     blank     | Space symbols     | と      | {}             |              |
     asciiword | Word, all ASCII   | English | {english_stem} | english_stem | {english}
     blank     | Space symbols     | が      | {}             |              |
     asciiword | Word, all ASCII   | mixed   | {english_stem} | english_stem | {mix}
     blank     | Space symbols     | な      | {}             |              |
     word      | Word, all letters | 文      | {simple}       | simple       | {文}
     blank     | Space symbols     | も      | {}             |              |
     word      | Word, all letters | 解析    | {simple}       | simple       | {解析}
     asciiword | Word, all ASCII   | OK      | {english_stem} | english_stem | {ok}
     blank     | Space symbols     | です    | {}             |              |
     blank     | Space symbols     | 。      | {}             |              |
    (12 rows)

### 類義語 (synonym)

類義語辞書を使用できます。 `<インストール先>/share/tsearch_data/japanese.syn` というテキストファイルを用意します。 文字エンコーディングは UTF-8 でなければなりません。

     バキューム	vacuum
     ポスグレ	pgsql

類義語辞書は、以下のSQLを使って登録します。

    -- Install japanese synonym dictionary
    CREATE TEXT SEARCH DICTIONARY japanese_syn (
        TEMPLATE = synonym,
        SYNONYMS = japanese
    );
    ALTER TEXT SEARCH CONFIGURATION japanese
        ALTER MAPPING FOR word, hword_part, hword WITH japanese_syn, simple;

類義語は変換して処理されるため、表記に揺れがあっても検索や強調ができます。

    =# SELECT ts_headline('japanese', 'autovacuumを使えばバキュームも手間要らず',  to_tsquery('japanese', 'VACUUM'));
                       ts_headline
    -------------------------------------------------
     autovacuumを使えば<b>バキューム</b>も手間要らず
    (1 row)

同様に、`$PGDATA/share/tsearch_data/english.syn` を用意すれば、 英語の類義語辞書も同時に使用できます。 このとき、英語と日本語で必ずしも *.syn を分ける必要はありませんが、 英数字(半角)には必ず英語辞書が使われ、 日本語文字(全角)には必ず日本語辞書が使われるため、 分割したほうが若干変換速度が向上します。

    -- Install english synonym dictionary
    CREATE TEXT SEARCH DICTIONARY english_syn (
        TEMPLATE = synonym,
        SYNONYMS = english
    );
    ALTER TEXT SEARCH CONFIGURATION japanese
        ALTER MAPPING FOR asciiword, hword_asciipart, asciihword WITH english_syn, english_stem;

### ストップワード (stop word)

現在、以下の品詞はストップワード(blank)とみなし、インデックス化していません。 不必要なインデックス・エントリを減らせるため、単純なスペース区切りによる分かち書きよりも効率が高まります。

- 助詞
- 助動詞
- 記号
- 名詞,代名詞
- 名詞,非自立
- 感動詞
- フィラー
- その他

実際には、類義語辞書と同じ方式で、textsearch 機能のストップワード辞書機能を使うことも可能です。 ただし、既に MeCab により単語区分が分かっているため、辞書よりも先に判定を行っています。 将来のバージョンでは、動作を選択可能にすることを考えています。

## その他の検索用関数

### Web検索互換クエリ (web_query)

textsearch は AND, OR, NOT 検索に &, |, ! を使用しています。 ウェブ検索で一般的に使用される制御演算子とは異なるため、検索フォームへの入力をそのまま条件に使用するには不便です。 関数 web_query() は、AND, OR, NOT 演算子として、スペース, OR (大文字), - を使用します。

    =# SELECT to_tsquery('english', 'Relational Database');
    ERROR:  syntax error in tsquery: "Relational Database"

    =# SELECT to_tsquery('english', web_query('Relational Database'));
         to_tsquery
    ---------------------
     'relat' & 'databas'
    (1 row)

注意: 現在、OR 演算子よりも AND 演算子のほうが結合順序が高いままです。 一般的なウェブ検索では、OR 演算子のほうが高いものが多いようです。

## 日本語解析機能

日本語の文字列を扱う関数と、MeCab を直接利用する関数が登録されます。

### テキストの正規化 (ja_normalize)

ja_normalize(text) は、入力された日本語テキストを正規化します。 大文字小文字は変換しません。

- 全角アルファベット、数字、記号 → 半角
- 半角カタカナ → 全角カタカナ
- 半角・全角文字混じり → 全角文字の前後にスペースを補う

    =# SELECT ja_normalize('ｶﾀｶﾅは全角に、ＡＢＣ１２３は半角に。ﾀﾞｸﾃﾝにも対応。');
                         ja_normalize
    ------------------------------------------------------
     カタカナは全角に、ABC123は半角に。ダクテンにも対応。
    (1 row)

### 分かち書き (ja_wakachi)

ja_wakachi(text) は、入力された日本語テキストを分かち書きします。 入力の正規化は行いません。

    =# SELECT ja_wakachi('分かち書きも使用できます。スペースで区切られます。');
                              ja_wakachi
    ---------------------------------------------------------------
     分かち書き も 使用 でき ます 。 スペース で 区切ら れ ます 。
    (1 row)

### mecab による解析 (ja_analyze)

ja_analyze(text) は、入力された日本語テキストを mecab で解析した結果を返します。

    =# SELECT * FROM ja_analyze('mecabを利用して形態素解析をします。');
      word  |  type  | subtype1 | subtype2 | subtype3 |  conjtype  | conjugation | basic  |    ruby    | pronounce
    --------+--------+----------+----------+----------+------------+-------------+--------+------------+------------
     mecab  | 名詞   | 一般     |          |          |            |             | mecab  | mecab      | mecab
     を     | 助詞   | 格助詞   | 一般     |          |            |             | を     | ヲ         | ヲ
     利用   | 名詞   | サ変接続 |          |          |            |             | 利用   | リヨウ     | リヨー
     し     | 動詞   | 自立     |          |          | サ変・スル | 連用形      | する   | シ         | シ
     て     | 助詞   | 接続助詞 |          |          |            |             | て     | テ         | テ
     形態素 | 名詞   | 一般     |          |          |            |             | 形態素 | ケイタイソ | ケイタイソ
     解析   | 名詞   | サ変接続 |          |          |            |             | 解析   | カイセキ   | カイセキ
     を     | 助詞   | 格助詞   | 一般     |          |            |             | を     | ヲ         | ヲ
     し     | 動詞   | 自立     |          |          | サ変・スル | 連用形      | する   | シ         | シ
     ます   | 助動詞 |          |          |          | 特殊・マス | 基本形      | ます   | マス       | マス
     。     | 記号   | 句点     |          |          |            |             | 。     | 。         | 。
    (11 rows)

### ふりがな (furigana)

MeCab を利用し、ふりがな（発音）をカタカナで取得します。

    =# SELECT furigana('ふりがな（発音）を取得します。');
                    furigana
    ----------------------------------------
     フリガナ（ハツオン）ヲシュトクシマス。
    (1 row)

### ひらがな変換 (hiragana)

半角／全角カタカナをひらがなへ変換します。

    =# SELECT hiragana('ﾀﾞｸﾃﾝとゼンカクをひらがなに変換');
                  hiragana
    ------------------------------------
     だくてんとぜんかくをひらがなに変換
    (1 row)

### カタカナ変換 (katakana)

ひらがなを全角カタカナへ変換します。

    =# SELECT katakana('ひらがなを全角カタカナに変換');
               katakana
    ------------------------------
     ヒラガナヲ全角カタカナニ変換
    (1 row)

## TODO

web_query を一般的なウェブサイト互換にする
  演算子の優先順位、除外、連語などに対応する必要があります。

Top > textsearch_ja
Copyright (c) 2008-2009, NIPPON TELEGRAPH AND TELEPHONE CORPORATION