From 65aeaefa417d971d05f660a18f683b65d9a7bffb Mon Sep 17 00:00:00 2001 From: Oneric Date: Thu, 2 May 2024 22:44:48 +0200 Subject: [PATCH] =?UTF-8?q?meilisearch:=20respect=20meili=E2=80=99s=20resu?= =?UTF-8?q?lt=20ranking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Meilisearch is already configured to return results sorted by a particular ranking configured in the meilisearch CLI task. Resorting the returned top results by date partially negates this and runs counter to what someone with tweaked settings expects. Issue and fix identified by AdamK2003 in https://akkoma.dev/AkkomaGang/akkoma/pulls/579 But instead of using a O(n^2) resorting, this commit directly retrieves results in the correct order from the database. Closes: https://akkoma.dev/AkkomaGang/akkoma/pulls/579 --- CHANGELOG.md | 3 +++ lib/pleroma/activity.ex | 21 +++++++++++++++++++++ lib/pleroma/search/meilisearch.ex | 4 +--- test/pleroma/activity_test.exs | 20 ++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d3034464..c7a838612 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Added - Implement [FEP-67ff](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md) (federation documentation) +## Fixed +- Meilisearch: order of results returned from our REST API now actually matches how Meilisearch ranks results + ## 2024.04 ## Added diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index bf851f808..f820cbdae 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -258,6 +258,27 @@ defmodule Pleroma.Activity do def get_create_by_object_ap_id(_), do: nil + @doc """ + Accepts a list of `ap__id`. + Returns a query yielding Create activities for the given objects, + in the same order as they were specified in the input list. + """ + @spec get_presorted_create_by_object_ap_id([String.t()]) :: Ecto.Queryable.t() + def get_presorted_create_by_object_ap_id(ap_ids) do + from( + a in Activity, + join: + ids in fragment( + "SELECT * FROM UNNEST(?::text[]) WITH ORDINALITY AS ids(ap_id, ord)", + ^ap_ids + ), + on: + ids.ap_id == fragment("?->>'object'", a.data) and + fragment("?->>'type'", a.data) == "Create", + order_by: [asc: ids.ord] + ) + end + @doc """ Accepts `ap_id` or list of `ap_id`. Returns a query. diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex index cecb7bd00..822c95b4a 100644 --- a/lib/pleroma/search/meilisearch.ex +++ b/lib/pleroma/search/meilisearch.ex @@ -5,7 +5,6 @@ defmodule Pleroma.Search.Meilisearch do alias Pleroma.Activity import Pleroma.Search.DatabaseSearch - import Ecto.Query @behaviour Pleroma.Search.SearchBackend @@ -91,14 +90,13 @@ defmodule Pleroma.Search.Meilisearch do try do hits - |> Activity.create_by_object_ap_id() + |> Activity.get_presorted_create_by_object_ap_id() |> Activity.with_preloaded_object() |> Activity.restrict_deactivated_users() |> maybe_restrict_local(user) |> maybe_restrict_author(author) |> maybe_restrict_blocked(user) |> maybe_fetch(user, query) - |> order_by([object: obj], desc: obj.data["published"]) |> Pleroma.Repo.all() rescue _ -> maybe_fetch([], user, query) diff --git a/test/pleroma/activity_test.exs b/test/pleroma/activity_test.exs index 4f9144f91..1943746cb 100644 --- a/test/pleroma/activity_test.exs +++ b/test/pleroma/activity_test.exs @@ -41,6 +41,26 @@ defmodule Pleroma.ActivityTest do assert activity == found_activity end + test "returns activities by object's AP id in requested presorted order" do + a1 = insert(:note_activity) + o1 = Object.normalize(a1, fetch: false).data["id"] + + a2 = insert(:note_activity) + o2 = Object.normalize(a2, fetch: false).data["id"] + + a3 = insert(:note_activity) + o3 = Object.normalize(a3, fetch: false).data["id"] + + a4 = insert(:note_activity) + o4 = Object.normalize(a4, fetch: false).data["id"] + + found_activities = + Activity.get_presorted_create_by_object_ap_id([o3, o2, o4, o1]) + |> Repo.all() + + assert found_activities == [a3, a2, a4, a1] + end + test "preloading a bookmark" do user = insert(:user) user2 = insert(:user)