From 1b6a18b473e0edec71bd4223cacf7682f677fc01 Mon Sep 17 00:00:00 2001 From: itepechi Date: Fri, 3 May 2024 05:44:07 +0900 Subject: [PATCH] Improve search results by implementing filtering on the Meilisearch side You will need to rerun the `search.meilisearch index` task in order to support this. If you do not, Akkoma will only be able to filter for newer posts than this commit and will return an error for advanced searches if you did not update the `filterable-attributes` attribute on the `objects` index manually. --- lib/mix/tasks/pleroma/search/meilisearch.ex | 10 +++ lib/pleroma/search/meilisearch.ex | 86 ++++++++++++++++++--- 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex index 299fb5b14..07c0deea0 100644 --- a/lib/mix/tasks/pleroma/search/meilisearch.ex +++ b/lib/mix/tasks/pleroma/search/meilisearch.ex @@ -48,6 +48,16 @@ def run(["index"]) do ] ) + {:ok, _} = + meili_put( + "/indexes/objects/settings/filterable-attributes", + [ + "media", + "local", + "author" + ] + ) + IO.puts("Created indices. Starting to insert posts.") chunk_size = Pleroma.Config.get([Pleroma.Search.Meilisearch, :initial_indexing_chunk_size]) diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex index 47265844b..e44c2d62a 100644 --- a/lib/pleroma/search/meilisearch.ex +++ b/lib/pleroma/search/meilisearch.ex @@ -3,8 +3,9 @@ defmodule Pleroma.Search.Meilisearch do require Pleroma.Constants alias Pleroma.Activity + alias Pleroma.User + alias Pleroma.Search.DatabaseSearch - import Pleroma.Search.DatabaseSearch import Ecto.Query @behaviour Pleroma.Search.SearchBackend @@ -86,10 +87,23 @@ def search(user, query, options \\ []) do only_media = Keyword.get(options, :only_media, false) only_local = Keyword.get(options, :local, false) + filter = + [] + |> maybe_restrict_local(user, only_local) + |> maybe_restrict_author(author) + |> maybe_restrict_blocked(user) + |> maybe_restrict_following(user, following) + |> maybe_restrict_media(only_media) + res = meili_post( "/indexes/objects/search", - %{q: query, offset: offset, limit: limit} + %{ + q: query, + offset: offset, + limit: limit, + filter: filter + } ) with {:ok, result} <- res do @@ -100,16 +114,11 @@ def search(user, query, options \\ []) do |> Activity.create_by_object_ap_id() |> Activity.with_preloaded_object() |> Activity.restrict_deactivated_users() - |> maybe_restrict_local(user, only_local) - |> maybe_restrict_author(author) - |> maybe_restrict_blocked(user) - |> maybe_restrict_following(user, following) - |> maybe_restrict_media(only_media) - |> maybe_fetch(user, query) + |> DatabaseSearch.maybe_fetch(user, query) |> order_by([object: obj], desc: obj.data["published"]) |> Pleroma.Repo.all() rescue - _ -> maybe_fetch([], user, query) + _ -> DatabaseSearch.maybe_fetch([], user, query) end end end @@ -141,6 +150,9 @@ def object_to_search_data(object) do %{ id: object.id, content: content, + media: length(data["attachment"]) > 0, + local: Pleroma.Object.local?(object), + author: data["actor"], ap: data["id"], published: published |> DateTime.to_unix() } @@ -174,4 +186,60 @@ def add_to_index(activity) do def remove_from_index(object) do meili_delete!("/indexes/objects/documents/#{object.id}") end + + defp maybe_restrict_local(f, user, only_local) do + limit = Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated) + + case {only_local, limit, user} do + {true, _, _} -> restrict_local(f) + {_, :all, _} -> restrict_local(f) + {_, :unauthenticated, %User{}} -> f + {_, :unauthenticated, _} -> restrict_local(f) + {_, false, _} -> f + end + end + + defp restrict_local(f) do + ["local = true" | f] + end + + defp maybe_restrict_author(f, %User{ap_id: ap_id}) do + [~s"author = #{Jason.encode!(ap_id)}" | f] + end + + defp maybe_restrict_author(f, _), do: f + + defp maybe_restrict_blocked(f, user) do + blocked_users = User.blocked_users_ap_ids(user) + + case blocked_users do + [] -> f + _ -> restrict_blocked(f, blocked_users) + end + end + + defp restrict_blocked(f, blocked_users) do + [~s"author NOT IN #{Jason.encode!(blocked_users)}" | f] + end + + defp maybe_restrict_following(f, %User{} = user, true) do + following_users = User.following_ap_ids(user) + + case following_users do + [] -> f + _ -> restrict_following(f, following_users) + end + end + + defp maybe_restrict_following(f, _, _), do: f + + defp restrict_following(f, following_users) do + [~s"author IN #{Jason.encode!(following_users)}" | f] + end + + defp maybe_restrict_media(f, true) do + ["media = true" | f] + end + + defp maybe_restrict_media(f, _), do: f end