PGroongaをプリザンターの横断検索機能に使ってみた

## 横断検索機能 とは
プリザンターには画面右上に検索ボックスがあり、こちらに入力した文字列をもとに各サイト(フォルダ、テーブル等)に登録された情報をサイトをまたいで(横断して)検索する機能があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481749/f3cb1efd-8dad-8a16-9f84-1cd2f50ed378.png)

この機能はデータベースの全文検索の仕組みを用いており、プリザンターではpg_trgmでフルテキストのインデックスを構築し、構築したインデックスをもとに検索を行います。

【参考情報】
- [共通機能：横断検索 | Pleasanter](https://pleasanter.org/manual/crosssearch)
- [pg_trgm — トライグラム一致を使ったテキストの類似度をサポートする](https://www.postgresql.jp/docs/16/pgtrgm.htmlg_trgm)

## PGroonga とは
PGroongaはPostgreSQLを高速に日本語全文検索可能なシステムにする拡張機能です。

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

## インストールして使ってみる
チュートリアルを参考にインストール、インデックス作成、検索してみます。

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

### インストール
環境に合わせてPGroongaのパッケージをインストールする。

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

プリザンターのデータベース(Implem.Pleasanter)に接続し、拡張機能(pgroonga)を追加します。
```sql
Implem.Pleasanter=# create extension pgroonga;
CREATE EXTENSION
Implem.Pleasanter=# \dx
                                              List of installed extensions
   Name   | Version |      Schema       |                                  Description
----------+---------+-------------------+--------------------------------------------------------------------------------
 pg_trgm  | 1.6     | Implem.Pleasanter | text similarity measurement and index searching based on trigrams
 pgcrypto | 1.3     | Implem.Pleasanter | cryptographic functions
 pgroonga | 3.2.0   | Implem.Pleasanter | Super fast and all languages supported full text search index based on Groonga
 plpgsql  | 1.0     | pg_catalog        | PL/pgSQL procedural language
(4 rows)


Implem.Pleasanter=#

```

## インデックス作成
ItemsテーブルのFullTextカラムに対してインデックスを作成します。

```
Implem.Pleasanter=# create index pgroonga_fulltext_index on "Items" using pgroonga ("FullText");
```

作成することができました。

```
Implem.Pleasanter=# select *  from pg_indexes where tablename = 'Items' and indexdef like '%FullText%';
    schemaname     | tablename |        indexname        | tablespace |                                            indexdef
-------------------+-----------+-------------------------+------------+-------------------------------------------------------------------------------------------------
 Implem.Pleasanter | Items     | pgroonga_fulltext_index |            | CREATE INDEX pgroonga_fulltext_index ON "Implem.Pleasanter"."Items" USING pgroonga ("FullText")
(1 row)


Implem.Pleasanter=#
```

## 検索

explainコマンドでクエリの実行計画を見てみると、インデックス(pgroonga_fulltext_index)が使用されていることを確認しました。

```
Implem.Pleasanter=# explain analyze select * from "Items" where "FullText" &@ '東京都';
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.25..46035.26 rows=1000 width=290) (actual time=21.744..273.715 rows=21473 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Bitmap Heap Scan on "Items"  (cost=0.25..44935.26 rows=417 width=290) (actual time=7.293..164.177 rows=7158 loops=3)
         Recheck Cond: ("FullText" &@ '東京都'::text)
         Heap Blocks: exact=8233
         ->  Bitmap Index Scan on pgroonga_fulltext_index  (cost=0.00..0.00 rows=26522 width=0) (actual time=18.608..18.608 rows=21473 loops=1)
               Index Cond: ("FullText" &@ '東京都'::text)
 Planning Time: 82.987 ms
 Execution Time: 276.227 ms
(10 rows)


Implem.Pleasanter=#
```

```
Implem.Pleasanter=# select count(*) from "Items" where "FullText" &@ '東京都';
 count
-------
 21473
(1 row)
```

## ソースコードに手を加えてみる
ソースコードで該当する処理はこちらになります。
https://github.com/Implem/Implem.Pleasanter/blob/8101487bd3452e6106542a5f9e38d0fc69663323/Rds/Implem.PostgreSql/PostgreSqlCommandText.cs#L86

ソースコードを以下のように修正します。「**%>**」を「**&@**」に変更する。

```csharp
public string CreateFullTextWhereItem(
    string itemsTableName,
    string paramName,
    bool negative)
{
    return (negative
        ? $"(not (coalesce(\"{itemsTableName}\".\"FullText\",'') &@ @{paramName}#CommandCount#))"
        : $"(\"{itemsTableName}\".\"FullText\" &@ @{paramName}#CommandCount#)");
}
```

今回は「**&@**」を使用しましたが、全文検索する際に使用できる演算子は他にもあるようです。下記リファレンスの「演算子」に記載があります。

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

## 横断検索機能(PGroonga)試してみる
プリザンターに登録されているサンプルデータをもとに、「東京都」で検索してヒットした件数は、上記のクエリで確認した件数と一致していました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481749/2348180e-6e20-98a3-1f63-bb7d26272036.png)


## さいごに
今回の記事をきっかけに引き続きPGroongaについて深掘りしていきたいと思います！