Fix User search.
Now uses a trigram based search. This is a lot faster and gives better results. Closes #185.
This commit is contained in:
parent
2e9aa16b86
commit
1d4bbec6b3
5 changed files with 54 additions and 13 deletions
|
@ -6,3 +6,4 @@ ALTER DATABASE pleroma_dev OWNER TO pleroma;
|
||||||
\c pleroma_dev;
|
\c pleroma_dev;
|
||||||
--Extensions made by ecto.migrate that need superuser access
|
--Extensions made by ecto.migrate that need superuser access
|
||||||
CREATE EXTENSION IF NOT EXISTS citext;
|
CREATE EXTENSION IF NOT EXISTS citext;
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||||
|
|
|
@ -21,6 +21,7 @@ defmodule Pleroma.User do
|
||||||
field(:local, :boolean, default: true)
|
field(:local, :boolean, default: true)
|
||||||
field(:info, :map, default: %{})
|
field(:info, :map, default: %{})
|
||||||
field(:follower_address, :string)
|
field(:follower_address, :string)
|
||||||
|
field(:search_distance, :float, virtual: true)
|
||||||
has_many(:notifications, Notification)
|
has_many(:notifications, Notification)
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
|
@ -399,19 +400,23 @@ def search(query, resolve) do
|
||||||
User.get_or_fetch_by_nickname(query)
|
User.get_or_fetch_by_nickname(query)
|
||||||
end
|
end
|
||||||
|
|
||||||
q =
|
inner =
|
||||||
from(
|
from(
|
||||||
u in User,
|
u in User,
|
||||||
where:
|
select_merge: %{
|
||||||
fragment(
|
search_distance: fragment(
|
||||||
"(to_tsvector('english', ?) || to_tsvector('english', ?)) @@ plainto_tsquery('english', ?)",
|
"? <-> (? || ?)",
|
||||||
|
^query,
|
||||||
u.nickname,
|
u.nickname,
|
||||||
u.name,
|
u.name
|
||||||
^query
|
)}
|
||||||
),
|
|
||||||
limit: 20
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
q = from(s in subquery(inner),
|
||||||
|
order_by: s.search_distance,
|
||||||
|
limit: 20
|
||||||
|
)
|
||||||
|
|
||||||
Repo.all(q)
|
Repo.all(q)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.AddTrigramExtension do
|
||||||
|
use Ecto.Migration
|
||||||
|
require Logger
|
||||||
|
|
||||||
|
def up do
|
||||||
|
Logger.warn("ATTENTION ATTENTION ATTENTION\n")
|
||||||
|
Logger.warn("This will try to create the pg_trgm extension on your database. If your database user does NOT have the necessary rights, you will have to do it manually and re-run the migrations.\nYou can probably do this by running the following:\n")
|
||||||
|
Logger.warn("sudo -u postgres psql pleroma_dev -c \"create extension if not exists pg_trgm\"\n")
|
||||||
|
execute("create extension if not exists pg_trgm")
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
execute("drop extension if exists pg_trgm")
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,7 @@
|
||||||
|
defmodule Pleroma.Repo.Migrations.CreateUserTrigramIndex do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create index(:users, ["(nickname || name) gist_trgm_ops"], name: :users_trigram_index, using: :gist)
|
||||||
|
end
|
||||||
|
end
|
|
@ -609,16 +609,29 @@ test "unimplemented mutes, follow_requests, blocks, domain blocks" do
|
||||||
|
|
||||||
test "account search", %{conn: conn} do
|
test "account search", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
_user_two = insert(:user, %{nickname: "shp@shitposter.club"})
|
user_two = insert(:user, %{nickname: "shp@shitposter.club"})
|
||||||
user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
|
user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
|
||||||
|
|
||||||
conn =
|
results =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> get("/api/v1/accounts/search", %{"q" => "shp"})
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
result_ids = for result <- results, do: result["acct"]
|
||||||
|
|
||||||
|
assert user_two.nickname in result_ids
|
||||||
|
assert user_three.nickname in result_ids
|
||||||
|
|
||||||
|
results =
|
||||||
conn
|
conn
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> get("/api/v1/accounts/search", %{"q" => "2hu"})
|
|> get("/api/v1/accounts/search", %{"q" => "2hu"})
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
assert [account] = json_response(conn, 200)
|
result_ids = for result <- results, do: result["acct"]
|
||||||
assert account["id"] == to_string(user_three.id)
|
|
||||||
|
assert user_three.nickname in result_ids
|
||||||
end
|
end
|
||||||
|
|
||||||
test "search", %{conn: conn} do
|
test "search", %{conn: conn} do
|
||||||
|
@ -642,7 +655,7 @@ test "search", %{conn: conn} do
|
||||||
|
|
||||||
assert results = json_response(conn, 200)
|
assert results = json_response(conn, 200)
|
||||||
|
|
||||||
[account] = results["accounts"]
|
[account | _] = results["accounts"]
|
||||||
assert account["id"] == to_string(user_three.id)
|
assert account["id"] == to_string(user_three.id)
|
||||||
|
|
||||||
assert results["hashtags"] == []
|
assert results["hashtags"] == []
|
||||||
|
|
Loading…
Reference in a new issue