Resolve conflicts

This commit is contained in:
Roman Chvanikov 2019-06-29 00:52:50 +03:00
commit 657277ffc0
548 changed files with 7933 additions and 1976 deletions

View file

@ -7,74 +7,97 @@ defmodule Pleroma.User.Search do
alias Pleroma.User
import Ecto.Query
def search(query, opts \\ []) do
@similarity_threshold 0.25
@limit 20
def search(query_string, opts \\ []) do
resolve = Keyword.get(opts, :resolve, false)
following = Keyword.get(opts, :following, false)
result_limit = Keyword.get(opts, :limit, @limit)
offset = Keyword.get(opts, :offset, 0)
for_user = Keyword.get(opts, :for_user)
# Strip the beginning @ off if there is a query
query = String.trim_leading(query, "@")
query_string = String.trim_leading(query_string, "@")
maybe_resolve(resolve, for_user, query)
maybe_resolve(resolve, for_user, query_string)
{:ok, results} =
Repo.transaction(fn ->
Ecto.Adapters.SQL.query(Repo, "select set_limit(0.25)", [])
Ecto.Adapters.SQL.query(
Repo,
"select set_limit(#{@similarity_threshold})",
[]
)
query
|> search_query(for_user)
query_string
|> search_query(for_user, following)
|> paginate(result_limit, offset)
|> Repo.all()
end)
results
end
defp maybe_resolve(true, %User{}, query) do
User.get_or_fetch(query)
end
defp maybe_resolve(true, _, query) do
unless restrict_local?(), do: User.get_or_fetch(query)
end
defp maybe_resolve(_, _, _), do: :noop
defp search_query(query, for_user) do
query
|> union_query()
defp search_query(query_string, for_user, following) do
for_user
|> base_query(following)
|> search_subqueries(query_string)
|> union_subqueries
|> distinct_query()
|> boost_search_rank_query(for_user)
|> subquery()
|> order_by(desc: :search_rank)
|> limit(20)
|> maybe_restrict_local(for_user)
end
defp restrict_local? do
Pleroma.Config.get([:instance, :limit_unauthenticated_to_local_content], true)
defp base_query(_user, false), do: User
defp base_query(user, true), do: User.get_followers_query(user)
defp paginate(query, limit, offset) do
from(q in query, limit: ^limit, offset: ^offset)
end
defp union_query(query) do
fts_subquery = fts_search_subquery(query)
trigram_subquery = trigram_search_subquery(query)
defp union_subqueries({fts_subquery, trigram_subquery}) do
from(s in trigram_subquery, union_all: ^fts_subquery)
end
defp search_subqueries(base_query, query_string) do
{
fts_search_subquery(base_query, query_string),
trigram_search_subquery(base_query, query_string)
}
end
defp distinct_query(q) do
from(s in subquery(q), order_by: s.search_type, distinct: s.id)
end
# unauthenticated users can only search local activities
defp maybe_restrict_local(q, %User{}), do: q
defp maybe_restrict_local(q, _) do
if restrict_local?() do
where(q, [u], u.local == true)
else
q
defp maybe_resolve(true, user, query) do
case {limit(), user} do
{:all, _} -> :noop
{:unauthenticated, %User{}} -> User.get_or_fetch(query)
{:unauthenticated, _} -> :noop
{false, _} -> User.get_or_fetch(query)
end
end
defp maybe_resolve(_, _, _), do: :noop
defp maybe_restrict_local(q, user) do
case {limit(), user} do
{:all, _} -> restrict_local(q)
{:unauthenticated, %User{}} -> q
{:unauthenticated, _} -> restrict_local(q)
{false, _} -> q
end
end
defp limit, do: Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated)
defp restrict_local(q), do: where(q, [u], u.local == true)
defp boost_search_rank_query(query, nil), do: query
defp boost_search_rank_query(query, for_user) do
@ -103,7 +126,8 @@ defmodule Pleroma.User.Search do
)
end
defp fts_search_subquery(term, query \\ User) do
@spec fts_search_subquery(User.t() | Ecto.Query.t(), String.t()) :: Ecto.Query.t()
defp fts_search_subquery(query, term) do
processed_query =
term
|> String.replace(~r/\W+/, " ")
@ -145,9 +169,10 @@ defmodule Pleroma.User.Search do
|> User.restrict_deactivated()
end
defp trigram_search_subquery(term) do
@spec trigram_search_subquery(User.t() | Ecto.Query.t(), String.t()) :: Ecto.Query.t()
defp trigram_search_subquery(query, term) do
from(
u in User,
u in query,
select_merge: %{
# ^1 gives 'Postgrex expected a binary, got 1' for some weird reason
search_type: fragment("?", 1),