Search: join on activities instead of objects

This commit is contained in:
rinpatch 2019-09-01 10:27:18 +03:00
parent 6d33c89c4d
commit 84fe16202f
3 changed files with 82 additions and 13 deletions

View File

@ -10,8 +10,11 @@ defmodule Mix.Tasks.Pleroma.Benchmark do
start_pleroma()
Benchee.run(%{
"search" => fn ->
"With joined objects" => fn ->
Pleroma.Activity.search(nil, "cofe")
end,
"With joined activities" => fn ->
Pleroma.Activity.search(nil, "cofe", join_on: :activities)
end
})
end

View File

@ -4,6 +4,7 @@
defmodule Pleroma.Activity.Search do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Object.Fetcher
alias Pleroma.Pagination
alias Pleroma.User
@ -15,38 +16,94 @@ defmodule Pleroma.Activity.Search do
def search(user, search_query, options \\ []) do
index_type = if Pleroma.Config.get([:database, :rum_enabled]), do: :rum, else: :gin
join_on = options[:join_on] || :activities
limit = Enum.min([Keyword.get(options, :limit), 40])
offset = Keyword.get(options, :offset, 0)
author = Keyword.get(options, :author)
Activity
|> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users()
|> restrict_public()
base_query(join_on)
|> restrict_deactivated(join_on)
|> restrict_public(join_on)
|> query_with(index_type, search_query)
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
|> maybe_restrict_author(author, join_on)
|> Pagination.fetch_paginated(%{"offset" => offset, "limit" => limit}, :offset)
|> maybe_transform(join_on)
|> maybe_fetch(user, search_query)
end
def maybe_restrict_author(query, %User{} = author) do
def maybe_restrict_author(query, %User{} = author, :objects) do
from([a, o] in query,
where: a.actor == ^author.ap_id
)
end
def maybe_restrict_author(query, _), do: query
def maybe_restrict_author(query, %User{} = author, :activities) do
from([o] in query,
where: fragment("?->>'actor' = ?", o.data, ^author.ap_id)
)
end
defp restrict_public(q) do
def maybe_restrict_author(query, _, _), do: query
defp restrict_public(q, :objects) do
from([a, o] in q,
where: fragment("?->>'type' = 'Create'", a.data),
where: ^Pleroma.Constants.as_public() in a.recipients
)
end
defp restrict_public(q, :activities) do
from([o, a] in q,
where:
fragment(
"?->'to' \\? ? OR ?->'cc' \\? ?",
o.data,
^Pleroma.Constants.as_public(),
o.data,
^Pleroma.Constants.as_public()
)
)
end
defp base_query(:activities) do
from(o in Object,
as: :object,
join: a in Activity,
as: :activity,
on:
fragment(
"(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')",
o.data,
a.data,
a.data
) and fragment("?->>'type' = 'Create'", a.data),
preload: [create_activity: a]
)
end
defp base_query(:objects) do
from(a in Activity, as: :activity)
|> Activity.with_preloaded_object()
|> where([activity: a], fragment("?->>'type' = 'Create'", a.data))
end
defp restrict_deactivated(query, :activities) do
from(
[object: o] in query,
where:
fragment(
"?->>'actor' not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')",
o.data
)
)
end
defp restrict_deactivated(query, :objects) do
Activity.restrict_deactivated_users(query)
end
defp query_with(q, :gin, search_query) do
from([a, o] in q,
from([object: o] in q,
where:
fragment(
"to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",
@ -57,7 +114,7 @@ defmodule Pleroma.Activity.Search do
end
defp query_with(q, :rum, search_query) do
from([a, o] in q,
from([object: o] in q,
where:
fragment(
"? @@ plainto_tsquery('english', ?)",
@ -79,7 +136,15 @@ defmodule Pleroma.Activity.Search do
end
end
defp restrict_local(q), do: where(q, local: true)
defp restrict_local(q), do: where(q, [activity: a], a.local == true)
defp maybe_transform(activities, :objects), do: activities
defp maybe_transform(objects, :activities) do
Enum.map(objects, fn object ->
Map.put(object.create_activity, :object, object)
end)
end
defp maybe_fetch(activities, user, search_query) do
with true <- Regex.match?(~r/https?:/, search_query),

View File

@ -19,6 +19,7 @@ defmodule Pleroma.Object do
schema "objects" do
field(:data, :map)
has_one(:create_activity, Activity, on_delete: :nothing, foreign_key: :id)
timestamps()
end