feat: use PGroonga for full-text search

Co-authored-by: tamaina <tamaina@hotmail.co.jp>
This commit is contained in:
naskya 2023-10-28 20:19:25 +09:00
parent 182882f61d
commit 624f31ffaf
Signed by: naskya
GPG key ID: 164DFF24E2D40139
12 changed files with 149 additions and 44 deletions

View file

@ -14,6 +14,9 @@
## 主要な変更点 ## 主要な変更点
- 全文検索のエンジンを [PGroonga](https://pgroonga.github.io/) に変更
- PGroonga のインストールが必要になります!詳しくは[この投稿](https://post.naskya.net/notes/9ldi29amfanomef5)をご覧ください
- Meilisearch, Elasticsearch, Sonic は非推奨となります
- 「秘密」という公開範囲を追加 - 「秘密」という公開範囲を追加
- 宛先無しのダイレクト投稿を言い換えているだけです - 宛先無しのダイレクト投稿を言い換えているだけです
- 既存の投稿を削除せずに後から秘密にすることもできます - 既存の投稿を削除せずに後から秘密にすることもできます
@ -139,15 +142,14 @@
## インストール ## インストール
[Firefish のインストールスクリプト](https://git.joinfirefish.org/firefish/ubuntu-bash-install)のプロンプトで尋ねられるリポジトリの URL にこのリポジトリの URL を使ってください。 ToDo (#82)
``` 遠回りな方法ですが、公式のインストールスクリプトを使いたい場合にはそれを用いて本家の Firefish をインストールしてから下記の手順でこのフォークに移行できます。
Repository url where you want to install:
> https://code.naskya.net/naskya/firefish
```
## アップデート ## アップデート
重要なお知らせがある場合にはアップデートスクリプトを通じてお伝えするので、必ず `update.sh` を用いてアップデートしてください。
1. サーバーのバックアップを取る 1. サーバーのバックアップを取る
1. サーバーを停止する 1. サーバーを停止する
```sh ```sh
@ -188,6 +190,64 @@ Repository url where you want to install:
$ cp -r calckey.old/custom calckey $ cp -r calckey.old/custom calckey
$ cp -r calckey.old/.config calckey $ cp -r calckey.old/.config calckey
``` ```
1. 全文検索エンジンMeilisearch, Sonic, Elasticsearch のいずれか)を使用している場合には、`.config/default.yml` からその設定を削除またはコメントアウトする
先頭に `#` をつけると設定をコメントアウトできます。
```yaml
#sonic:
# host: localhost
# port: 1491
# auth: SecretPassword
# collection: notes
# bucket: default
```
全文検索エンジンは停止またはアンインストールしてしまってよいです。本家の Firefish に戻るつもりがあるなら停止を、そうでなければアンインストールをおすすめします。
停止コマンドの例
```sh
$ sudo systemctl disable --now sonic
```
1. PostgreSQL のバージョンを確認する
```sh
$ psql --version
```
1. PGroonga をインストールする
インストールコマンドの例(詳しくは[この投稿](https://post.naskya.net/notes/9ldi29amfanomef5)を参考にしてください)
```sh
$ sudo apt install -y software-properties-common
$ sudo add-apt-repository -y universe
$ sudo add-apt-repository -y ppa:groonga/ppa
$ sudo apt install -y wget lsb-release
$ wget https://packages.groonga.org/ubuntu/groonga-apt-source-latest-$(lsb_release --codename --short).deb
$ sudo apt install -y -V ./groonga-apt-source-latest-$(lsb_release --codename --short).deb
$ echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release --codename --short)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
$ sudo apt update
$ sudo apt install -y -V postgresql-14-pgdg-pgroonga
^^^^^^^^^^^^^
for PostgreSQL 14.x
```
1. `.config/default.yml` に書かれているデータベースの名前を確認する(以下の例では `mk1`
```yaml
db:
host: localhost
port: 5432
db: mk1 # <---
```
1. PostgreSQL のプロンプトを起動する(`mk1` の部分は自分のデータベース名に変えて実行)
```sh
$ sudo -iu postgres psql --dbname=mk1
```
以下のような表示が出てコマンドの入力待ちになります。
```
psql (16.0)
Type "help" for help.
mk1=#
```
1. 以下のコマンドを実行して PGroonga の拡張機能を有効にする
```
CREATE EXTENSION pgroonga;
```
1. `\q` というコマンドを実行するか Ctrl+D を押して PostgreSQL のプロンプトを終了する
1. 新しい Firefish のディレクトリに入ってビルドする 1. 新しい Firefish のディレクトリに入ってビルドする
```sh ```sh
$ cd calckey $ cd calckey
@ -218,9 +278,24 @@ Repository url where you want to install:
```sh ```sh
$ ./update.sh $ ./update.sh
``` ```
1. このフォークで加えられたデータベースへの変更を取り消す(`dbname`(以下の例では `mk1`)には `.config/default.yml` に記載されている PostgreSQL のデータベース名(`db:` の後に書かれているもの)を指定する) 1. `.config/default.yml` に書かれているデータベースの名前を確認する(以下の例では `mk1`
```yaml
db:
host: localhost
port: 5432
db: mk1 # <---
```
1. このフォークで加えられたデータベースへの変更を取り消す(`mk1` の部分は自分のデータベース名に変更する)
```sh ```sh
$ sudo -iu postgres psql --dbname=mk1 --file=neko/revert.sql $ sudo -iu postgres psql --file=neko/revert.sql --dbname=mk1
```
1. PGroonga をアンインストールする
アンインストールするコマンドの例
```sh
$ sudo apt purge --remove postgresql-14-pgdg-pgroonga
$ sudo add-apt-repository --remove ppa:groonga/ppa
$ sudo apt-key del ACCC4CF8
$ sudo apt update
``` ```
1. Firefish がインストールされているディレクトリの親ディレクトリ (e.g., `/home/calckey`) に行く 1. Firefish がインストールされているディレクトリの親ディレクトリ (e.g., `/home/calckey`) に行く
```sh ```sh

View file

@ -2,15 +2,13 @@ version: "3"
services: services:
web: web:
image: registry.joinfirefish.org/firefish/firefish image: firefish
build: .
container_name: firefish_web container_name: firefish_web
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- db - db
- redis - redis
### Uncomment one of the following to use a search engine
# - meilisearch
# - sonic
ports: ports:
- "3000:3000" - "3000:3000"
networks: networks:
@ -33,7 +31,7 @@ services:
db: db:
restart: unless-stopped restart: unless-stopped
image: docker.io/postgres:12.2-alpine image: docker.io/groonga/pgroonga:latest-alpine-12
container_name: firefish_db container_name: firefish_db
networks: networks:
- calcnet - calcnet
@ -42,33 +40,6 @@ services:
volumes: volumes:
- ./db:/var/lib/postgresql/data - ./db:/var/lib/postgresql/data
### Only one of the below should be used.
### Meilisearch is better overall, but resource-intensive. Sonic is a very light full text search engine.
# meilisearch:
# container_name: meilisearch
# image: getmeili/meilisearch:v1.1.1
# environment:
# - MEILI_ENV=${MEILI_ENV:-development}
# ports:
# - "7700:7700"
# networks:
# - calcnet
# volumes:
# - ./meili_data:/meili_data
# restart: unless-stopped
# sonic:
# restart: unless-stopped
# image: docker.io/valeriansaliou/sonic:v1.4.0
# logging:
# driver: none
# networks:
# - calcnet
# volumes:
# - ./sonic:/var/lib/sonic/store
# - ./sonic/config.cfg:/etc/sonic.cfg
networks: networks:
calcnet: calcnet:
# web: # web:

4
neko/flags/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View file

@ -0,0 +1,7 @@
-------------------------------------------------------------------------
| This Firefish fork now requires PGroonga (https://pgroonga.github.io/), |
| so PLEASE INSTALL PGroonga BEFORE UPGRADING!!! |
| |
| For the detailed explanation, see: |
| https://post.naskya.net/notes/9ldi29amfanomef5 |
-------------------------------------------------------------------------

View file

@ -1,3 +1,9 @@
-- pgroonga
DROP INDEX "public"."IDX_f27f5d88941e57442be75ba9c8";
DROP INDEX "public"."IDX_065d4d8f3b5adb4a08841eae3c";
DROP INDEX "public"."IDX_fcb770976ff8240af5799e3ffc";
DROP EXTENSION pgroonga CASCADE;
-- emoji-moderator -- emoji-moderator
ALTER TABLE "user" DROP COLUMN "emojiModPerm"; ALTER TABLE "user" DROP COLUMN "emojiModPerm";
DROP TYPE "public"."user_emojimodperm_enum"; DROP TYPE "public"."user_emojimodperm_enum";

View file

@ -0,0 +1,27 @@
export class Pgroonga1698420787202 {
name = "Pgroonga1698420787202";
async up(queryRunner) {
await queryRunner.query(
`CREATE INDEX "IDX_f27f5d88941e57442be75ba9c8" ON "note" USING "pgroonga" ("text")`,
);
await queryRunner.query(
`CREATE INDEX "IDX_065d4d8f3b5adb4a08841eae3c" ON "user" USING "pgroonga" ("name" pgroonga_varchar_full_text_search_ops_v2)`,
);
await queryRunner.query(
`CREATE INDEX "IDX_fcb770976ff8240af5799e3ffc" ON "user_profile" USING "pgroonga" ("description" pgroonga_varchar_full_text_search_ops_v2) `,
);
}
async down(queryRunner) {
await queryRunner.query(
`DROP INDEX "public"."IDX_fcb770976ff8240af5799e3ffc"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_065d4d8f3b5adb4a08841eae3c"`,
);
await queryRunner.query(
`DROP INDEX "public"."IDX_f27f5d88941e57442be75ba9c8"`,
);
}
}

View file

@ -61,6 +61,7 @@ export class Note {
}) })
public threadId: string | null; public threadId: string | null;
@Index() // USING pgroonga
@Column("text", { @Column("text", {
nullable: true, nullable: true,
}) })

View file

@ -38,6 +38,7 @@ export class UserProfile {
}) })
public birthday: string | null; public birthday: string | null;
@Index() // USING pgroonga pgroonga_varchar_full_text_search_ops_v2
@Column("varchar", { @Column("varchar", {
length: 2048, length: 2048,
nullable: true, nullable: true,

View file

@ -64,6 +64,7 @@ export class User {
}) })
public usernameLower: string; public usernameLower: string;
@Index() // USING pgroonga pgroonga_varchar_full_text_search_ops_v2
@Column("varchar", { @Column("varchar", {
length: 128, length: 128,
nullable: true, nullable: true,

View file

@ -91,7 +91,7 @@ export default define(meta, paramDef, async (ps, me) => {
} }
query query
.andWhere("note.text ILIKE :q", { q: `%${sqlLikeEscape(ps.query)}%` }) .andWhere("note.text &@~ :q", { q: `${sqlLikeEscape(ps.query)}` })
.andWhere("note.visibility = 'public'") .andWhere("note.visibility = 'public'")
.innerJoinAndSelect("note.user", "user") .innerJoinAndSelect("note.user", "user")
.leftJoinAndSelect("user.avatar", "avatar") .leftJoinAndSelect("user.avatar", "avatar")

View file

@ -78,8 +78,8 @@ export default define(meta, paramDef, async (ps, me) => {
const nameQuery = Users.createQueryBuilder("user") const nameQuery = Users.createQueryBuilder("user")
.where( .where(
new Brackets((qb) => { new Brackets((qb) => {
qb.where("user.name ILIKE :query", { qb.where("user.name &@~ :query", {
query: `%${sqlLikeEscape(ps.query)}%`, query: `${sqlLikeEscape(ps.query)}`,
}); });
// Also search username if it qualifies as username // Also search username if it qualifies as username
@ -115,8 +115,8 @@ export default define(meta, paramDef, async (ps, me) => {
if (users.length < ps.limit) { if (users.length < ps.limit) {
const profQuery = UserProfiles.createQueryBuilder("prof") const profQuery = UserProfiles.createQueryBuilder("prof")
.select("prof.userId") .select("prof.userId")
.where("prof.description ILIKE :query", { .where("prof.description &@~ :query", {
query: `%${sqlLikeEscape(ps.query)}%`, query: `${sqlLikeEscape(ps.query)}`,
}); });
if (ps.origin === "local") { if (ps.origin === "local") {

View file

@ -62,6 +62,18 @@ else
say "This script seems to be up-to-date!\n" say "This script seems to be up-to-date!\n"
fi fi
## show messages
for message in neko/messages/*; do
file=$(basename -- "${message}")
if [[ ! -f "neko/flags/${file}" ]]; then
say "There is an important notice!"
cat "${message}"
touch "neko/flags/${file}"
say "To read this again, run: \$ cat ${message}"
exit 1
fi
done
## write version info ## write version info
say "Writing version info to package.json..." say "Writing version info to package.json..."