PGroongaのチュートリアルをやってみた 

# 概要

Postgresqlで全文検索を行うための拡張機能である[PGroonga](https://pgroonga.github.io/ja/)をキャッチアップするため、下記のチュートリアルをやってみました。

https://pgroonga.github.io/ja/tutorial/

DockerHubにPGroongaのイメージがあったので、これをベースにチュートリアルを行うためのdockerコンテナを作成しました。本記事では大まかに下記の2点について記載します。

- PGroongaのチュートリアル実施用のコンテナの作成
- チュートリアルをやってみる

# 環境

VirtualBoxにUbuntuのVMを構築してそこにdockerをインストールしてコンテナを立てました。バージョン情報は下記になります。

```
Ubuntu         : 22.04 LTS
Docker         : 26.1.1
Docker Compose : v2.27.0
```

ここでは、DockerをインストールしたUbuntuのVMが用意されている前提で、コンテナの作成から記載します。

# チュートリアル用のコンテナの作成

コンテナの作成は、`groonga/pgroonga:3.2.4-alpine-17-slim`のイメージをベースに実施しました。

```
Postgresql : 17
PGroonga   : 3.2.4
```

コードは下記のリポジトリに置いてあります。

https://github.com/taka194/pgroonga-tutorial-db

## 作成手順

下記の記事を参考に作成を進めました。

https://zenn.dev/ayano_sakai/articles/42e64d873bf7df

https://zenn.dev/re24_1986/articles/b76c3fd8f76aec

これらの記事からの変更点は、ベースのイメージをpostgresからpgroongaのものへ変更したことくらいです。

## テーブルやデータの作成

`/docker-entrypoint-initdb.d/`以下に配置したshやsqlファイルはコンテナの初回起動時に名前順で実行されます。今回は3つのsqlファイルを作成し、それぞれ下記の役割を担わせました。

1. pgroongaのextensionをcreate（01_init.sql）
1. チュートリアルで利用するテーブルの作成（02_create_table.sql）
1. チュートリアルで利用するテーブルにデータを登録（03_insert_data.sql）

## PGroonga独自の要素

PGroonga独自の要素は大きく分けて2つありました。1つはpgroongaのextensionをcreateすることです。

```sql
create extension if not exists pgroonga;
```

2つめは、全文検索を行うカラムにpgroonga専用のインデックスを貼ることです。

```sql
create table memos (
  id integer,
  content text
);

create index pgroonga_content_index on memos using pgroonga (content);
```

# チュートリアルをやってみた

ここからは、作成したDBを利用してチュートリアルを進めます。

## 検索してみる

チュートリアルに書かれている検索を実施してみます。

### 全文検索演算子

`&@`演算子では1つのキーワードで全文検索できるようです。

```terminal
postgres=# SELECT * FROM memos WHERE content &@ '全文検索';

 id |                      content
----+---------------------------------------------------
  2 | Groongaは日本語対応の高速な全文検索エンジンです。
(1 row)
```

`&@~`演算子では複数のキーワードを使って全文検索できるようです。

キーワードをORでつなぐとOR条件で検索されます。

```terminal
postgres=# SELECT * FROM memos WHERE content &@~ 'PGroonga OR PostgreSQL';

 id |                                  content
----+---------------------------------------------------------------------------
  1 | PostgreSQLはリレーショナル・データベース管理システムです。
  3 | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。
(2 rows)
```

キーワードをスペースでつなぐとAND条件で検索されます。

```terminal
postgres=# SELECT * FROM memos WHERE content &@~ 'PGroonga PostgreSQL';

 id |                                  content
----+---------------------------------------------------------------------------
  3 | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。
(1 row)
```

### スコア

PGroongaではマッチした度合いを数値で取得することができます。Oracleの全文検索のOracleTextにも同様の機能がありますね。  
スコアの大きい順に並べると、マッチ度の高い順に表示することができます。

```terminal
postgres=# SELECT *, pgroonga_score(tableoid, ctid) AS score FROM score_memos WHERE content &@ 'PGroonga' OR content &@ 'PostgreSQL';

 id |                                  content                                  | score
----+---------------------------------------------------------------------------+-------
  1 | PostgreSQLはリレーショナル・データベース管理システムです。                    |     1
  3 | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。     |     2
(2 rows)
```

### その他の検索

チュートリアルに記載されているそのほかの検索は、カラムの型が違うだけであまり変わらないなという所感でしたので割愛します。

## 複数のカラムを横断した検索

チュートリアルでは取り扱っていませんでしたが、触ってみました。

https://pgroonga.github.io/ja/reference/operators/query-v2.html

こちらにサンプルがあったので、これを利用します。ここで扱っているテーブル名が`memos`でチュートリアルと重複してしまうため、ここでは`notes`という名前に変更します。

```sql
create table notes (
  title text,
  content text
);

create index pgroonga_notes_index on notes using pgroonga ((array[title, content]));

insert into notes values ('PostgreSQL', 'PostgreSQLはリレーショナル・データベース管理システムです。');
insert into notes values ('Groonga', 'Groongaは日本語対応の高速な全文検索エンジンです。');
insert into notes values ('PGroonga', 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。');
insert into notes values ('コマンドライン', 'groongaコマンドがあります。');
```

検索対象とするカラムの配列にインデックスを貼り、検索を実行するときもインデックスを指定してクエリを実行する形で利用するようです。

OR条件とAND条件でそれぞれ検索を実施してみました。Tokenizerが裏で動いているため単純な部分一致とは異なる動きをしていました。

### OR条件

```terminal
postgres=# SELECT *, pgroonga_score(tableoid, ctid) AS score FROM notes WHERE ARRAY[title, content] &@~ pgroonga_condition('Groonga OR PostgreSQL', index_name => 'pgroonga_notes_index') ORDER BY score DESC;
     title      |                                  content                                  | score
----------------+---------------------------------------------------------------------------+-------
 Groonga        | Groongaは日本語対応の高速な全文検索エンジンです。                         |     2
 PGroonga       | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。 |     2
 PostgreSQL     | PostgreSQLはリレーショナル・データベース管理システムです。                |     2
 コマンドライン | groongaコマンドがあります。                                               |     1
(4 rows)
```

### AND条件

```terminal
postgres=# SELECT *, pgroonga_score(tableoid, ctid) AS score FROM notes WHERE ARRAY[title, content] &@~ pgroonga_condition('Groonga PostgreSQL', index_name => 'pgroonga_notes_index') ORDER BY score DESC;
  title   |                                  content                                  | score
----------+---------------------------------------------------------------------------+-------
 PGroonga | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。 |     2
(1 row)
```

# 参考

- https://pgroonga.github.io/ja/
- https://github.com/pgroonga/docker
- https://zenn.dev/ayano_sakai/articles/42e64d873bf7df
- https://zenn.dev/re24_1986/articles/b76c3fd8f76aec