これはPGroonga 2.X and 3.X用のドキュメントです。古いPGroongaを使っているならPGroonga 1.xのドキュメントを見てください。

同義語展開にSudachiの辞書を使う方法

SudachiDictは同義語辞書を提供しています。PGroongaでこれを使うことができます。

検索システムでSudachiDictにある同義語辞書を使う方法を説明します。ここではSudachiDictにある同義語辞書をシステム辞書として使います。さらに自分たちで定義した同義語辞書も使います。

SudachiDictにある同義語辞書の内容を登録する方法

SudachiDictベースのシステム同義語辞書のためのテーブルを作る必要があります。ここではこのテーブルの名前はsystem_thesaurusにします。

CREATE TABLE system_thesaurus (
  term text PRIMARY KEY,
  synonyms text[]
);

このテーブルを同義語辞書として使うにはPGroongaのインデックスが必要です。このインデックスでは、同義語のキーとして使うtermの演算子クラスにpgroonga_text_term_search_ops_v2を指定しなければいけません。

CREATE INDEX system_thesaurus_term_index
  ON system_thesaurus
  USING pgroonga (term pgroonga_text_term_search_ops_v2);

SudachiDictにある同義語辞書の中身をsystem_thesaurusに登録するためにGroonga synonymを使います。

Groonga synonymはRubyで書かれています。そのため、事前にRubyをインストールしておかないといけません。

Groonga synonymをインストールします。

gem install groonga-synonym

次のコマンドラインはSudachiDictにある同義語辞書の内容をsystem_thesaurusに登録するINSERTを生成します。

groonga-synonym-generate --format=pgroonga --table=system_thesaurus --output=system_thesaurus_data.sql

SudachiDictが関連情報を提供しているので生成されたデータには重みがついています。

このデータはpsql内で\iを使ってロードできます。

\i system_thesaurus_data.sql

ユーザー同義語辞書の登録方法

ユーザー同義語辞書用のテーブルを作る必要があります。ここでは同義語グループを使います。なぜなら同義語辞書のメンテナンスはコストが高いタスクだからです。同義語グループの方が単語ごとに同義語を指定するよりもメンテナンスコストが低いです。

ここではこのテーブルの名前をuser_synonym_groupsにします。

CREATE TABLE user_synonym_groups (
  synonyms text[]
);

このテーブルを同義語辞書として使うためにはPGroongaのインデックスが必要です。同義語グループとして使われるsynonymsにはpgroonga_text_array_term_search_ops_v2演算子クラスを指定する必要があります。

CREATE INDEX user_synonym_groups_synonyms_index
          ON user_synonym_groups
       USING pgroonga (synonyms pgroonga_text_array_term_search_ops_v2);

以下はサンプルデータです。

INSERT INTO user_synonym_groups VALUES (ARRAY['pg', 'postgresql']);

この同義語グループデータを使うと、pgで検索してもpostgresqlで検索しても同じ検索結果になります。pgで検索するとクエリーはpg OR postgresqlになりまうs.postgresqlで検索してもクエリーはpg OR postgresqlになります。

同義語辞書を使った検索方法

これらの同義語辞書を使って検索するためにpgroonga_query_expand関数を2回使います。

最初のpgroonga_query_expand()はユーザー同義語辞書を使います。

SELECT
  pgroonga_query_expand(
    'user_synonym_groups',
    'synonyms',
    'synonyms',
    'QUERY'
  );

クエリーにpgを使った場合の例です。

SELECT
  pgroonga_query_expand(
    'user_synonym_groups',
    'synonyms',
    'synonyms',
    'pg'
  );
--  pgroonga_query_expand  
-- ------------------------
--  ((pg) OR (postgresql))
-- (1 row)

pgpostgresqlも検索されます。

2つめのpgroonga_query_expand()は1つめのpgroonga_query_expand()の結果に対してシステム同義語辞書を使います。

SELECT
  pgroonga_query_expand(
    'system_thesaurus',
    'term',
    'synonyms',
    pgroonga_query_expand(
      'user_synonym_groups',
      'synonyms',
      'synonyms',
      'QUERY'
    )
  );

ユーザー同義語辞書にもうひとつ同義語グループを追加します。

INSERT INTO user_synonym_groups VALUES (ARRAY['on-line', 'online']);

新しく追加した同義語グループを確認しましょう。

SELECT
  pgroonga_query_expand(
    'user_synonym_groups',
    'synonyms',
    'synonyms',
    'on-line'
  );
--   pgroonga_query_expand  
-- -------------------------
--  ((on-line) OR (online))
-- (1 row)

クエリーにon-lineを指定してシステム同義語辞書とユーザー同義語辞書を両方使ってみましょう。

SELECT
  pgroonga_query_expand(
    'system_thesaurus',
    'term',
    'synonyms',
	pgroonga_query_expand(
      'user_synonym_groups',
      'synonyms',
      'synonyms',
      'on-line'
    )
  );
--               pgroonga_query_expand               
-- --------------------------------------------------
--  ((on-line) OR (((>-0.2オンライン) OR (online))))
-- (1 row)

このSELECTは次のように動きます。

  1. on-lineはユーザー同義語辞書でon-line OR onlineに展開されます:on-line -> ((on-line)) OR (online))

  2. onlineはシステム同義語辞書で>-0.2オンライン OR onlineに展開されます:((on-line)) OR (online)) -> ((on-line) OR (((>-0.2オンライン) OR (online))))

>-0.2オンライン>-0.2オンラインの重みを調整しています。この場合、重みは0.8 (1 - 0.2)になります。

全文検索でこれらの同義語辞書を使ってみましょう。

CREATE TABLE memos (
  content text
);
INSERT INTO memos VALUES ('Online conference is easy to join');
INSERT INTO memos VALUES ('On-line conference is easy to join');
INSERT INTO memos VALUES ('オンライン conference is easy to join');

CREATE INDEX memos_content_index ON memos USING pgroonga (content);

-- For ensuring using index
SET enable_seqscan = no;

SELECT content, pgroonga_score(tableoid, ctid) AS score
  FROM memos
  WHERE
    content &@~
      pgroonga_query_expand(
        'system_thesaurus',
        'term',
        'synonyms',
        pgroonga_query_expand(
          'user_synonym_groups',
          'synonyms',
          'synonyms',
          'on-line'
        )
      );
--                content                |       score       
-- ---------------------------------------+-------------------
--  On-line conference is easy to join    |                 1
--  オンライン conference is easy to join | 0.800000011920929
--  Online conference is easy to join     |                 1
-- (3 rows)