Add support for PGroonga

This commit is contained in:
itepechi 2023-08-04 06:27:23 +09:00
parent f03c0bc63f
commit 557fce16e5
13 changed files with 176 additions and 25 deletions

View File

@ -71,8 +71,14 @@ config :pleroma, :rate_limit,
config :pleroma, :http_security, report_uri: "https://endpoint.com"
rum_enabled = System.get_env("RUM_ENABLED") == "true"
config :pleroma, :database, rum_enabled: rum_enabled
pgroonga_enabled = System.get_env("PGROONGA_ENABLED") == "true"
config :pleroma, :database,
rum_enabled: rum_enabled,
pgroonga_enabled: pgroonga_enabled
IO.puts("RUM enabled: #{rum_enabled}")
IO.puts("PGroonga enabled: #{pgroonga_enabled}")
config :pleroma, Pleroma.ReverseProxy.Client, Pleroma.ReverseProxy.ClientMock

View File

@ -689,7 +689,9 @@ config :pleroma, :oauth2,
issue_new_refresh_token: true,
clean_expired_tokens: false
config :pleroma, :database, rum_enabled: false
config :pleroma, :database,
rum_enabled: false,
pgroonga_enabled: false
config :pleroma, :features, improved_hashtag_timeline: :auto

View File

@ -23,7 +23,10 @@ config :pleroma, Pleroma.Repo,
# Configure web push notifications
config :web_push_encryption, :vapid_details, subject: "mailto:#{System.get_env("NOTIFY_EMAIL")}"
config :pleroma, :database, rum_enabled: false
config :pleroma, :database,
rum_enabled: false,
pgroonga_enabled: false
config :pleroma, :instance, static_dir: "/var/lib/akkoma/static"
config :pleroma, Pleroma.Uploaders.Local, uploads: "/var/lib/akkoma/uploads"

View File

@ -98,8 +98,14 @@ config :pleroma, :http_security, report_uri: "https://endpoint.com"
config :pleroma, :http, send_user_agent: false
rum_enabled = System.get_env("RUM_ENABLED") == "true"
config :pleroma, :database, rum_enabled: rum_enabled
pgroonga_enabled = System.get_env("PGROONGA_ENABLED") == "true"
config :pleroma, :database,
rum_enabled: rum_enabled,
pgroonga_enabled: pgroonga_enabled
IO.puts("RUM enabled: #{rum_enabled}")
IO.puts("PGroonga enabled: #{pgroonga_enabled}")
config :joken, default_signer: "yU8uHKq+yyAkZ11Hx//jcdacWc8yQ1bxAAGrplzB0Zwwjkp35v0RK9SO8WTPr6QZ"

View File

@ -4,6 +4,7 @@ version: "3.7"
services:
db:
image: postgres:14-alpine
# image: groonga/pgroonga:3.1.1-alpine-14 # Use this one if you want to use PGroonga
restart: unless-stopped
environment:
POSTGRES_DB: akkoma

View File

@ -54,6 +54,7 @@ The configuration of Akkoma (and Pleroma) has traditionally been managed with a
* config :pleroma, Pleroma.Repo
* config :pleroma, configurable\_from\_database
* config :pleroma, :database, rum_enabled
* config :pleroma, :database, pgroonga_enabled
* config :pleroma, :connections_pool
Here is an example of a server config stripped down after migration:

View File

@ -326,37 +326,50 @@ defmodule Mix.Tasks.Pleroma.Database do
"ALTER DATABASE #{db} SET default_text_search_config = '#{tsconfig}';"
)
# non-exist config will not raise excpetion but only give >0 messages
# non-exist config will not raise exception but only give >0 messages
if length(msg) > 0 do
shell_info("Error: #{inspect(msg, pretty: true)}")
else
rum_enabled = Pleroma.Config.get([:database, :rum_enabled])
shell_info("Recreate index, RUM: #{rum_enabled}")
pgroonga_enabled = Pleroma.Config.get([:database, :pgroonga_enabled])
shell_info("Recreate index, RUM: #{rum_enabled}, PGroonga: #{pgroonga_enabled}")
# Note SQL below needs to be kept up-to-date with latest GIN or RUM index definition in future
if rum_enabled do
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"CREATE OR REPLACE FUNCTION objects_fts_update() RETURNS trigger AS $$ BEGIN
cond do
rum_enabled ->
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"CREATE OR REPLACE FUNCTION objects_fts_update() RETURNS trigger AS $$ BEGIN
new.fts_content := to_tsvector(new.data->>'content');
RETURN new;
END
$$ LANGUAGE plpgsql",
[],
timeout: :infinity
)
[],
timeout: :infinity
)
shell_info("Refresh RUM index")
Ecto.Adapters.SQL.query!(Pleroma.Repo, "UPDATE objects SET updated_at = NOW();")
else
Ecto.Adapters.SQL.query!(Pleroma.Repo, "DROP INDEX IF EXISTS objects_fts;")
shell_info("Refresh RUM index")
Ecto.Adapters.SQL.query!(Pleroma.Repo, "UPDATE objects SET updated_at = NOW();")
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"CREATE INDEX CONCURRENTLY objects_fts ON objects USING gin(to_tsvector('#{tsconfig}', data->>'content')); ",
[],
timeout: :infinity
)
pgroonga_enabled ->
Ecto.Adapters.SQL.query!(Pleroma.Repo, "DROP INDEX IF EXISTS object_content_pgroonga;")
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"CREATE INDEX object_content_pgroonga ON objects USING pgroonga ((data->'content')) WITH (tokenizer='TokenMecab');",
[],
timeout: :infinity
)
true ->
Ecto.Adapters.SQL.query!(Pleroma.Repo, "DROP INDEX IF EXISTS objects_fts;")
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"CREATE INDEX CONCURRENTLY objects_fts ON objects USING gin(to_tsvector('#{tsconfig}', data->>'content'));",
[],
timeout: :infinity
)
end
shell_info('Done.')

View File

@ -28,6 +28,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
dbuser: :string,
dbpass: :string,
rum: :string,
pgroonga: :string,
indexable: :string,
db_configurable: :string,
uploads_dir: :string,
@ -127,6 +128,18 @@ defmodule Mix.Tasks.Pleroma.Instance do
"n"
) === "y"
pgroonga_enabled =
if rum_enabled do
false
else
get_option(
options,
:pgroonga,
"Would you like to use PGroonga to index and search?",
"n"
) === "y"
end
listen_port =
get_option(
options,
@ -225,6 +238,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
static_dir: static_dir,
uploads_dir: uploads_dir,
rum_enabled: rum_enabled,
pgroonga_enabled: pgroonga_enabled,
listen_ip: listen_ip,
listen_port: listen_port,
upload_filters:

View File

@ -24,6 +24,7 @@ defmodule Pleroma.ApplicationRequirements do
|> check_migrations_applied!()
|> check_welcome_message_config!()
|> check_rum!()
|> check_pgroonga!()
|> check_repo_pool_size!()
|> handle_result()
end
@ -162,6 +163,55 @@ defmodule Pleroma.ApplicationRequirements do
end
end
# Checks for settings of PGroonga.
#
defp check_pgroonga!(:ok) do
{_, res, _} =
Ecto.Migrator.with_repo(Pleroma.Repo, fn repo ->
# TODO: check migrate
migrate =
from(o in "pg_indexes",
where: o.indexname == "object_content_pgroonga"
)
|> repo.exists?()
setting = Pleroma.Config.get([:database, :pgroonga_enabled], false)
do_check_pgroonga!(setting, migrate)
end)
res
end
defp check_pgroonga!(result), do: result
defp do_check_pgroonga!(setting, migrate) do
case {setting, migrate} do
{true, false} ->
Logger.error(
"PGroonga is enabled, but no migrations have been applied for it.\n" <>
"If you want to start Akkoma without using PGroonga, set `config :pleroma, :database, pgroonga_enabled: false`.\n" <>
"Otherwise apply the following migrations:\n" <>
"`mix ecto.migrate --migrations-path priv/repo/optional_migrations/pgroonga/`"
)
{:error, "Unapplied PGroonga Migrations detected"}
{false, true} ->
Logger.error(
"Detected applied migrations to use PGroonga to search, but it is not enabled in the settings.\n" <>
"If you want to use PGroonga, set `config :pleroma, :database, pgroonga_enabled: true`.\n" <>
"Otherwise apply the following migrations:\n" <>
"`mix ecto.rollback --migrations-path priv/repo/optional_migrations/pgroonga/`"
)
{:error, "PGroonga Migrations detected"}
_ ->
:ok
end
end
defp check_system_commands!(:ok) do
filter_commands_statuses = [
check_filter(Pleroma.Upload.Filter.Exiftool, "exiftool"),

View File

@ -16,7 +16,13 @@ defmodule Pleroma.Search.DatabaseSearch do
@behaviour Pleroma.Search.SearchBackend
def search(user, search_query, options \\ []) do
index_type = if Pleroma.Config.get([:database, :rum_enabled]), do: :rum, else: :gin
index_type =
cond do
Pleroma.Config.get([:database, :rum_enabled]) -> :rum
Pleroma.Config.get([:database, :pgroonga_enabled]) -> :pgroonga
true -> :gin
end
limit = Enum.min([Keyword.get(options, :limit), 40])
offset = Keyword.get(options, :offset, 0)
author = Keyword.get(options, :author)
@ -132,6 +138,18 @@ defmodule Pleroma.Search.DatabaseSearch do
)
end
defp query_with(q, :pgroonga, search_query, _) do
# PGroonga only supports PostgreSQL version 11 or newer
from([a, o] in q,
where:
fragment(
"?->'content' &@~ ?",
o.data,
^search_query
)
)
end
def maybe_restrict_local(q, user) do
limit = Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated)

View File

@ -0,0 +1,29 @@
defmodule Pleroma.Repo.Migrations.CreatePgroongaIndex do
use Ecto.Migration
def up do
execute("CREATE EXTENSION IF NOT EXISTS pgroonga")
drop_if_exists(
index(:objects, ["(to_tsvector('english', data->>'content'))"],
using: :gin,
name: :objects_fts
)
)
execute(
"CREATE INDEX object_content_pgroonga ON objects USING pgroonga ((data->'content')) WITH (tokenizer='TokenMecab')"
)
end
def down do
execute("DROP INDEX IF EXISTS object_content_pgroonga")
create_if_not_exists(
index(:objects, ["(to_tsvector('english', data->>'content'))"],
using: :gin,
name: :objects_fts
)
)
end
end

View File

@ -41,7 +41,10 @@ config :web_push_encryption, :vapid_details,
public_key: "<%= web_push_public_key %>",
private_key: "<%= web_push_private_key %>"
config :pleroma, :database, rum_enabled: <%= rum_enabled %>
config :pleroma, :database,
rum_enabled: <%= rum_enabled %>,
pgroonga_enabled: <%= pgroonga_enabled %>
config :pleroma, :instance, static_dir: "<%= static_dir %>"
config :pleroma, Pleroma.Uploaders.Local, uploads: "<%= uploads_dir %>"

View File

@ -10,3 +10,8 @@ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
else
""
end %>
<%= if pgroonga_enabled do
"CREATE EXTENSION IF NOT EXISTS pgroonga;"
else
""
end %>