辞書

PostgreSQL 9.1.1文書
前のページ | 巻戻し | 第 12章全文検索 | 早送り | 次のページ

# 12.6. 辞書

辞書は、検索の対象とならない単語(ストップワード)を削除するために使われます。また、同じ単語から派生した異なる形態の単語が照合するようにするために、単語を正規化するためにも使われます。検索の品質を向上するという面以外にも、正規化とストップワードの削除は、`tsvector`表現の文書のサイズを小さくし、結果として性能を向上させます。正規化は常に言語学的な意味を持つとは限らず、通常は用途の意味論に依存します。

正規化の例を示します。

- 言語学的 - Ispell辞書は入力された単語を正規化された形式に変換しようとします。語幹辞書は単語の終了部を削除します。

- 以下のようなURLが同一のURLに一致するように正規化することができます。

  - http://www.pgsql.ru/db/mw/index.html

  - http://www.pgsql.ru/db/mw/

  - http://www.pgsql.ru/db/../db/mw/index.html

- 色の名前は、16進値に変換できます。例： `red, green, blue, magenta -> FF0000, 00FF00, 0000FF, FF00FF`

- 数をインデックス付けする際には、可能な範囲を縮小するために、端数を削除することができます。たとえば、もし正規化後に小数点未満2桁を保持するならば、3.1415926, 3.14は同じことになります。

辞書は、トークンを入力し、以下を返すプログラムです。

- 入力が辞書に登録されていれば語彙素の配列(一つのトークンが一つ以上の語彙素を生成する可能性があることに注意してください)

- 辞書が入力を認識しないが、ストップワードであることは認識する場合は空の配列

- 元々のトークンを新規のトークンに置き換え、それに続く辞書にその新規トークン渡す場合は、`TSL_FILTER`フラグセットを伴う単一の語彙素(このような置き換え機能をもつ辞書はフィルタリング辞書と呼ばれます)

- 辞書が入力トークンを認識しない場合は`NULL`

PostgreSQLは、多くの言語に定義済の辞書を提供しています。また、カスタムパラメータを使った新しい辞書を作るためのテンプレートも利用できます。定義済の辞書のテンプレートについては、以下で述べています。今あるテンプレートが適当でないのなら、新しいものを作ることもできます。例は、PostgreSQLの配布物の`contrib/`をご覧下さい。

テキスト検索設定は、パーサと、パーサの出力トークンを処理する辞書の集合を結び付けます。パーサが返却する各々のトークン型に対して、設定で辞書のリストを指定します。パーサがあるトークン型を見つけると、ある辞書が単語を認識するまでリスト中の辞書が順番に調べられます。ストップワードであるか、あるいはどの辞書もトークンを認識しない場合はそれは捨てられ、インデックス付けや検索の対象となりません。通常、非`NULL`を返す最初の辞書の出力が結果を決めることになり、他の残りの辞書は参照されません。しかし、フィルタリング辞書は与えられたワードを変更し、それを続く辞書へ渡すことができます。

辞書をリストする一般的な方法は、まずもっとも範囲の狭い、特定用途向の辞書を配置し、次にもっと一般的な辞書を置き、最後にSnowball語幹処理や`simple`辞書のような、すべてを認識する非常に一般的な辞書を置くことです。たとえば、天文学向の検索では(`astro_en`設定)では、`asciiword` (ASCII単語)型を天文学用語の同義語辞書、一般的な英語辞書、そしてSnowball英語語幹辞書に結び付けることができます。

    ALTER TEXT SEARCH CONFIGURATION astro_en
        ADD MAPPING FOR asciiword WITH astrosyn, english_ispell, english_stem;

フィルタリング辞書は、リスト中の好きな場所へ配置できます。(役に立たなくなるリストの最後を除きます。)フィルタリング辞書は、後続の辞書の処理を単純化するために、一部の文字の正規化を行うのに有用です。例えば、フィルタリング辞書はunaccentモジュールで実施される様な、アクセント記号が付与された文字からアクセント記号を取り除くのに使用することができます。

## 12.6.1. ストップワード

ストップワードは、ほとんどすべての文書に現れるような非常に一般的で、ほかのものと同じようには扱う価値のない単語です。ですから、全文検索の際には無視して構いません。たとえば、すべての英語のテキストは`a`や`the`のような単語を含んでおり、インデックスの中にそれらを入れても役に立ちません。しかし、ストップワードは`tsvector`中の位置に影響を与えるので、結局ランキングにも影響があります。

    SELECT to_tsvector('english','in the list of stop words');
            to_tsvector
    ----------------------------
     'list':3 'stop':5 'word':6

位置1, 2, 4は、ストップワードのために失われています。ストップワード有無により、文書のために計算されたランクは非常に影響を受けます。

    SELECT ts_rank_cd (to_tsvector('english','in the list of stop words'), to_tsquery('list & stop'));
     ts_rank_cd
    ------------
           0.05

    SELECT ts_rank_cd (to_tsvector('english','list stop words'), to_tsquery('list & stop'));
     ts_rank_cd
    ------------
            0.1

ストップワードをどのように扱うかは、特定の辞書に任されています。例えば、`ispell`辞書はまず単語を正規化し、そして、ストップワードのリストを検索します。一方、`Snowball`語幹抽出はまずストップワードのリストを検査します。動作が異なる理由は、ノイズが紛れ込む可能性を減らすことです。

## 12.6.2. simple辞書

`simple`辞書テンプレートは、入力トークンを小文字に変換し、ストップワードのファイルに対してチェックすることによって動作します。もしファイルの中にあれば、空の配列が返却され、そのトークンは捨てられます。そうでないときは、小文字形式の単語が正規化された語彙素として返却されます。別の方法としては、ストップワードではないものは、認識できないものとすることもできます。そうすることにより、それらをリスト中の次の辞書に渡すことができます。

`simple`テンプレートを使った辞書定義の例を示します。

    CREATE TEXT SEARCH DICTIONARY public.simple_dict (
        TEMPLATE = pg_catalog.simple,
        STOPWORDS = english
    );

ここで、`english`は、ストップワードファイルのベースネームです。ファイルのフルネームは、`$SHAREDIR/tsearch_data/english.stop`です。`$SHAREDIR`は、PostgreSQLインストール先の共有データディレクトリです。これは、よく`/usr/local/share/postgresql`に置いてあります。(良くわからない場合は`pg_config --sharedir`を使ってください)。ファイル形式は、単に1行ごとに単語を書くだけです。空行と、後方の空白は無視されます。大文字は小文字に変換されます。このファイルの内容に関する処理はこれだけです。

これで辞書のテストができます。

    SELECT ts_lexize('public.simple_dict','YeS');
     ts_lexize
    -----------
     {yes}

    SELECT ts_lexize('public.simple_dict','The');
     ts_lexize
    -----------
     {}

また、ストップワードファイルの中に見つからないときに、小文字に変換した単語を返す代りに、`NULL`を返すことを選ぶこともできます。この挙動は、辞書の`Accept`パラメータを`false`に設定することで選択されます。 さらに例を続けます。

    ALTER TEXT SEARCH DICTIONARY public.simple_dict ( Accept = false );

    SELECT ts_lexize('public.simple_dict','YeS');
     ts_lexize
    -----------

    SELECT ts_lexize('public.simple_dict','The');
     ts_lexize
    -----------
     {}

デフォルト設定の`Accept` = `true`では、`simple`辞書は、辞書リストの最後に置かなければ意味がありません。なぜなら、後続の辞書にトークンを渡すことがないからです。逆に`Accept` = `false`は、後続の辞書が少なくとも一つはあるときに意味があります。

注意
ほとんどの辞書の形式は、ストップワードファイルのように設定ファイルに依存します。これらのファイルは必ずUTF-8エンコーディングにしてください。サーバのエンコーディングがUTF-8でない場合は、サーバに読み込まれる際に実際のデータベースエンコーディングに変換されます。

注意
通常、辞書はデータベースセッションの中で最初に使われる際に、一度だけ読み込まれます。辞書を変更し、現在使われているセッションの中で新しい内容が読み込まれるようにしたい場合は、その辞書に対して`ALTER TEXT SEARCH DICTIONARY`を発行してください。これは実際にはどんなパラメータ値をも変更しない"ダミー"の更新でよいです。

## 12.6.3. 同義語辞書

この辞書テンプレートは、単語を同義語に置き換える辞書を作るために使われます。語句はサポートされていません(そのためには類語テンプレート(項12.6.4)を使ってください)。同義語辞書は、言語学的な問題、たとえば、英語語幹辞書が'Paris'という単語を'pari'に縮小してしまうのを防ぎます。`Paris paris`という行を同義語辞書に登録し、`english_stem`辞書の前に置くようにするだけでよいのです。下記はその例です。

    SELECT * FROM ts_debug('english', 'Paris');
       alias   |   description   | token |  dictionaries  |  dictionary  | lexemes
    -----------+-----------------+-------+----------------+--------------+---------
     asciiword | Word, all ASCII | Paris | {english_stem} | english_stem | {pari}

    CREATE TEXT SEARCH DICTIONARY my_synonym (
        TEMPLATE = synonym,
        SYNONYMS = my_synonyms
    );

    ALTER TEXT SEARCH CONFIGURATION english
        ALTER MAPPING FOR asciiword
        WITH my_synonym, english_stem;

    SELECT * FROM ts_debug('english', 'Paris');
       alias   |   description   | token |       dictionaries        | dictionary | lexemes
    -----------+-----------------+-------+---------------------------+------------+---------
     asciiword | Word, all ASCII | Paris | {my_synonym,english_stem} | my_synonym | {paris}

`synonym`テンプレートに必要なパラメータは`SYNONYMS`だけで、その設定ファイルのベースネームです — 上の例では`my_synonyms`です。ファイルのフルネームは、`$SHAREDIR/tsearch_data/my_synonyms.syn` となります(ここで`$SHAREDIR`は、PostgreSQLをインストールした際の、共有データディレクトリです)。ファイルの形式は、置き換え対象の1単語につき1行で、単語には空白で区切られた同義語が後に続きます。空行、後方の空白は無視されます。

`synonym`テンプレートはまた、`CaseSensitive`というオプションパラメータを持っており、デフォルトは`false`です。`CaseSensitive`が`false`の時は 、同義語辞書内の単語は入力トークンと同様に小文字に変換されます。`true`の時は、単語とトークンは小文字に変換されずそのまま比較されます。

アスタリスク(`*`)は設定ファイル中の同義語の最後に付与することができます。これは同義語を接頭語とすることを意味します。アスタリスクは、エントリが`to_tsvector()`で使用される場合には無視されますが、`to_tsquery()`で使用される場合、結果は前方一致を伴った問い合わせになるでしょう。(詳しくは項12.3.2を見てください。)例えば、`$SHAREDIR/tsearch_data/synonym_sample.syn`に以下の様なエントリをもっていたとします。

    postgres        pgsql
    postgresql      pgsql
    postgre pgsql
    gogle   googl
    indices index*

この場合、次のような結果を得ることになります。

    mydb=# CREATE TEXT SEARCH DICTIONARY syn (template=synonym, synonyms='synonym_sample');
    mydb=# SELECT ts_lexize('syn','indices');
     ts_lexize
    -----------
     {index}
    (1 row)

    mydb=# CREATE TEXT SEARCH CONFIGURATION tst (copy=simple);
    mydb=# ALTER TEXT SEARCH CONFIGURATION tst ALTER MAPPING FOR asciiword WITH syn;
    mydb=# SELECT to_tsvector('tst','indices');
     to_tsvector
    -------------
     'index':1
    (1 row)

    mydb=# SELECT to_tsquery('tst','indices');
     to_tsquery
    ------------
     'index':*
    (1 row)

    mydb=# SELECT 'indexes are very useful'::tsvector;
                tsvector
    ---------------------------------
     'are' 'indexes' 'useful' 'very'
    (1 row)

    mydb=# SELECT 'indexes are very useful'::tsvector @@ to_tsquery('tst','indices');
     ?column?
    ----------
     t
    (1 row)

## 12.6.4. 類語辞書

類語辞書(TZと略されることがあります)は、単語と語句の関係情報を集めたものです。つまり、広義用語(BT)、狭義用語(NT)、優先用語、非優先用語、関連用語などです。

基本的には、類語辞書は、非優先用語を優先用語に置き換え、オプションで元の用語もインデックス付けのため保存します。PostgreSQLの現在の類語辞書の実装は、同義語辞書を拡張し、語句のサポートを追加したものです。類語辞書は、以下のようなフォーマットの設定ファイルを必要とします。

    # this is a comment
    sample word(s) : indexed word(s)
    more sample word(s) : more indexed word(s)
    ...

ここで、コロン(`:`)は、語句とその置き換え対象の区切 りです。

類語辞書は、副辞書(辞書設定で指定します)を、一致する語句をチェックする前に入力テキストを正規化するために使います。副辞書はただ一つだけ選べます。副辞書が単語を認識できない場合はエラーが報告されます。その場合は、その単語の利用を止めるか、副辞書にそのことを教えなければなりません。アスタリスク(`*`)をインデックス付けされた単語の先頭に置くことにより、副辞書の適用をスキップできます。しかしながら、すべてのサンプルの単語は、副辞書に認識されなければなりません。

複数の類語が照合するときは、類語辞書はもっとも長いものを選びます。そして、語句は、最後の定義を使って分解されます。

特定のストップワードを副辞書に認識するように指定することはできません。その代り、ストップワードが出現する位置を`?`でマークします。たとえば、`a`と`the`が副辞書によればストップワードだったとします。

    ? one ? two : swsw

は、`a one the two`と`the one a two`に照合します。そして、両方とも`swsw`に置き換えられます。

類語辞書は語句を認識することができるので、状態を記憶してパーサと連携を保たなければなりません。類語辞書は、この機能を使って次の単語を引き続き処理するのか、単語の蓄積を止めるのかを決定します。類語辞書の設定は注意深く行わなければなりません。たとえば、類語辞書が`asciiword`トークンだけを扱うようになっている場合、`one 7`のような類語辞書の定義は、トークン型 `uint`が類語辞書にアサインされていないので動きません。

注意
類語辞書はインデックス付けの際に利用されるので、類語辞書を設定変更すると、再インデックス付けが必要になります。他のほとんどの辞書では、ストップワードを追加あるいは削除するような小さな変更は、インデックス付けを必要としません。

### 12.6.4.1. 類語設定

新しい類語辞書を定義するには、`thesaurus`テンプレートを使います。例を示します。

    CREATE TEXT SEARCH DICTIONARY thesaurus_simple (
        TEMPLATE = thesaurus,
        DictFile = mythesaurus,
        Dictionary = pg_catalog.english_stem
    );

ここで、

- `thesaurus_simple`は新しい辞書の名前です。

- `mythesaurus`は、類語設定ファイルのベースネームです。(フルパスは、`$SHAREDIR/tsearch_data/mythesaurus.ths`となります。ここで、`$SHAREDIR`はインストール時の共有データディレクトリです。)

- 類語正規化で使用する`pg_catalog.english_stem`は副辞書です(ここでは、Snowball英語語幹辞書)。副辞書にはそれ用の設定(たとえばストップワード)があることに注意してください。ここではそれは表示していません。

これで、類語辞書`thesaurus_simple`を、設定中の希望のトークンにバインドすることができるようになります。例を示します。

    ALTER TEXT SEARCH CONFIGURATION russian
        ALTER MAPPING FOR asciiword, asciihword, hword_asciipart
        WITH thesaurus_simple;

### 12.6.4.2. 類語の例

天文学の単語の組合わせを含む単純な天文学用の`thesaurus_astro`類語を考えます。

    supernovae stars : sn
    crab nebulae : crab

以下で辞書を作り、トークン型を天文学類語辞書と英語の語幹辞書に結び付けます。

    CREATE TEXT SEARCH DICTIONARY thesaurus_astro (
        TEMPLATE = thesaurus,
        DictFile = thesaurus_astro,
        Dictionary = english_stem
    );

    ALTER TEXT SEARCH CONFIGURATION russian
        ALTER MAPPING FOR asciiword, asciihword, hword_asciipart
        WITH thesaurus_astro, english_stem;

さあ、これでどのように動くか試せます。`ts_lexize`は類語をテストする目的にはあまり有用ではありません。なぜなら、それは入力を単一のトークンとして扱うからです。その代りに、`plainto_tsquery`と`to_tsvector`を使って入力文字列を複数のトークンに分解します。

    SELECT plainto_tsquery('supernova star');
     plainto_tsquery
    -----------------
     'sn'

    SELECT to_tsvector('supernova star');
     to_tsvector
    -------------
     'sn':1

原則として、引数を引用符で囲めば`to_tsquery`が使えます。

    SELECT to_tsquery('''supernova star''');
     to_tsquery
    ------------
     'sn'

`english_stem`語幹辞書を同義語辞書の定義時に指定したので、`supernova star`が`thesaurus_astro`中の`supernovae stars`に照合していることに注意してください。語幹処理が`e`と`s`を削除しています。

置き換え後の語句とオリジナルの語句の両方をインデックス付けするには、定義の右項にオリジナルを追加するだけで良いです。

    supernovae stars : sn supernovae stars

    SELECT plainto_tsquery('supernova star');
           plainto_tsquery
    -----------------------------
     'sn' & 'supernova' & 'star'

## 12.6.5. Ispell辞書

Ispell辞書テンプレートは、形態論辞書を提供します。これによって、言語学的に多様な単語の形態を同じ語彙素に変換することができます。たとえば、英語Ispell辞書は、検索語`bank`の語形変化と活用変化、たとえば`banking`, `banked`, `banks`, `banks'`, and `bank's`に 照合します。

PostgreSQLの標準配布には、Ispellの設定ファイルは含まれていません。多くの言語用の辞書がIspellで入手できます。また、より新しい辞書のフォーマットもサポートされています — MySpell (OO < 2.0.1) と Hunspell (OO >= 2.0.2)。多数の辞書のリストが OpenOffice Wikiで入手できます。

Ispell辞書を作るには、組み込みの`ispell`テンプレートを使い、いくつかパラメータを指定します。

    CREATE TEXT SEARCH DICTIONARY english_ispell (
        TEMPLATE = ispell,
        DictFile = english,
        AffFile = english,
        StopWords = english
    );

ここで、`DictFile`, `AffFile`, および`StopWords`は、辞書のベースネーム、接辞ファイル、ストップワードファイルを指定します。ストップワードファイルは、上で説明した`simple`辞書と同じ形式です。ほかのファイルの形式はここでは説明されませんが、上にあげたウェブサイトに説明があります。

Ispell辞書は通常限られた数の単語を認識します。ですので、なんでも認識できるSnowball辞書のような、より適用範囲の広い辞書による後処理が必要です。

Ispell辞書を使って複合語を分割することができます。これはPostgreSQLがサポートする優れた機能です。接辞ファイルは、複合語形式の候補になる辞書中の単語に印を付ける`compoundwords controlled`文を使う特別なフラグを指定しなければならないことに注意してください。

    compoundwords  controlled z

ノルウェー語の例をいくつか示します。

    SELECT ts_lexize('norwegian_ispell', 'overbuljongterningpakkmesterassistent');
       {over,buljong,terning,pakk,mester,assistent}
    SELECT ts_lexize('norwegian_ispell', 'sjokoladefabrikk');
       {sjokoladefabrikk,sjokolade,fabrikk}

> 注意: MySpellは複合語をサポートしていません。Hunspellは複合語の高度なサポートを提供しています。いまのところ、PostgreSQLはHunspellの基本的な複合語操作しかサポートしていません。

## 12.6.6. Snowball辞書

Snowball辞書テンプレートは、有名な「英語用のポーターの語幹アルゴリズム」を発明したMartin Porterのプロジェクトに基づいています。Snowballは今では多くの言語用の語幹アルゴリズムを提供しています(詳細はSnowballのサイトを参照してください)。各々のアルゴリズムにより、その言語において単語の共通部分を取りだし、基本部もしくは語幹の綴りに縮退させることができます。Snowball辞書には、どの語幹処理を使うかを識別する`言語`パラメータが必須で、加えて、オプションで無視すべき単語のリストを保持する`ストップワード`ファイルを指定することもできます。(PostgreSQLの標準的なストップワードファイルもまたSnowball projectから提供されています)。たとえば、以下と同じ組み込みの定義があります。

    CREATE TEXT SEARCH DICTIONARY english_stem (
        TEMPLATE = snowball,
        Language = english,
        StopWords = english
    );

ストップワードファイルの形式はすでに説明されているものと同じです。

Snowball辞書は、単純化できるかどうかに関係なく、すべての単語を認識するので、辞書リストの最後に置く必要があります。他の辞書の前に置くのは意味がありません。Snowball辞書は決してトークンを次の辞書に渡さないからです。

前のページ | ホーム | 次のページ
パーサ | 上に戻る | 設定例