Improve hashtag search with multi word queries
This commit is contained in:
parent
26fe604942
commit
93c144e397
4 changed files with 92 additions and 6 deletions
1
changelog.d/hashtag-search.change
Normal file
1
changelog.d/hashtag-search.change
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Hashtag searches return real results based on words in your query
|
||||||
|
|
@ -135,18 +135,28 @@ defmodule Pleroma.Hashtag do
|
||||||
limit = Keyword.get(options, :limit, 20)
|
limit = Keyword.get(options, :limit, 20)
|
||||||
offset = Keyword.get(options, :offset, 0)
|
offset = Keyword.get(options, :offset, 0)
|
||||||
|
|
||||||
|
search_terms =
|
||||||
query
|
query
|
||||||
|> String.downcase()
|
|> String.downcase()
|
||||||
|> String.trim()
|
|> String.trim()
|
||||||
|> then(fn search_term ->
|
|> String.split(~r/\s+/)
|
||||||
|
|> Enum.filter(&(&1 != ""))
|
||||||
|
|
||||||
|
if Enum.empty?(search_terms) do
|
||||||
|
[]
|
||||||
|
else
|
||||||
|
# Use PostgreSQL's ANY operator with array for efficient multi-term search
|
||||||
|
# This is much more efficient than multiple OR clauses
|
||||||
|
search_patterns = Enum.map(search_terms, &"%#{&1}%")
|
||||||
|
|
||||||
from(ht in Hashtag,
|
from(ht in Hashtag,
|
||||||
where: fragment("LOWER(?) LIKE ?", ht.name, ^"%#{search_term}%"),
|
where: fragment("LOWER(?) LIKE ANY(?)", ht.name, ^search_patterns),
|
||||||
order_by: [asc: ht.name],
|
order_by: [asc: ht.name],
|
||||||
limit: ^limit,
|
limit: ^limit,
|
||||||
offset: ^offset
|
offset: ^offset
|
||||||
)
|
)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|> Enum.map(& &1.name)
|
|> Enum.map(& &1.name)
|
||||||
end)
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,35 @@ defmodule Pleroma.HashtagTest do
|
||||||
assert results == []
|
assert results == []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "searches hashtags by multiple words in query" do
|
||||||
|
# Create some hashtags
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("computer")
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("laptop")
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("desktop")
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("phone")
|
||||||
|
|
||||||
|
# Search for "new computer" - should return "computer"
|
||||||
|
results = Hashtag.search("new computer")
|
||||||
|
assert "computer" in results
|
||||||
|
refute "laptop" in results
|
||||||
|
refute "desktop" in results
|
||||||
|
refute "phone" in results
|
||||||
|
|
||||||
|
# Search for "computer laptop" - should return both
|
||||||
|
results = Hashtag.search("computer laptop")
|
||||||
|
assert "computer" in results
|
||||||
|
assert "laptop" in results
|
||||||
|
refute "desktop" in results
|
||||||
|
refute "phone" in results
|
||||||
|
|
||||||
|
# Search for "new phone" - should return "phone"
|
||||||
|
results = Hashtag.search("new phone")
|
||||||
|
assert "phone" in results
|
||||||
|
refute "computer" in results
|
||||||
|
refute "laptop" in results
|
||||||
|
refute "desktop" in results
|
||||||
|
end
|
||||||
|
|
||||||
test "supports pagination" do
|
test "supports pagination" do
|
||||||
{:ok, _} = Hashtag.get_or_create_by_name("alpha")
|
{:ok, _} = Hashtag.get_or_create_by_name("alpha")
|
||||||
{:ok, _} = Hashtag.get_or_create_by_name("beta")
|
{:ok, _} = Hashtag.get_or_create_by_name("beta")
|
||||||
|
|
@ -50,5 +79,20 @@ defmodule Pleroma.HashtagTest do
|
||||||
results = Hashtag.search("a", limit: 2, offset: 1)
|
results = Hashtag.search("a", limit: 2, offset: 1)
|
||||||
assert length(results) == 2
|
assert length(results) == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "handles many search terms efficiently" do
|
||||||
|
# Create hashtags
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("computer")
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("laptop")
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("phone")
|
||||||
|
{:ok, _} = Hashtag.get_or_create_by_name("tablet")
|
||||||
|
|
||||||
|
# Search with many terms - should be efficient with PostgreSQL ANY operator
|
||||||
|
results = Hashtag.search("new fast computer laptop phone tablet device")
|
||||||
|
assert "computer" in results
|
||||||
|
assert "laptop" in results
|
||||||
|
assert "phone" in results
|
||||||
|
assert "tablet" in results
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,37 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
|
||||||
assert results["hashtags"] == []
|
assert results["hashtags"] == []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "searches hashtags by multiple words in query", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, _activity1} = CommonAPI.post(user, %{status: "This is my new #computer"})
|
||||||
|
{:ok, _activity2} = CommonAPI.post(user, %{status: "Check out this #laptop"})
|
||||||
|
{:ok, _activity3} = CommonAPI.post(user, %{status: "My #desktop setup"})
|
||||||
|
{:ok, _activity4} = CommonAPI.post(user, %{status: "New #phone arrived"})
|
||||||
|
|
||||||
|
results =
|
||||||
|
conn
|
||||||
|
|> get("/api/v2/search?#{URI.encode_query(%{q: "new computer"})}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
hashtag_names = Enum.map(results["hashtags"], & &1["name"])
|
||||||
|
assert "computer" in hashtag_names
|
||||||
|
refute "laptop" in hashtag_names
|
||||||
|
refute "desktop" in hashtag_names
|
||||||
|
refute "phone" in hashtag_names
|
||||||
|
|
||||||
|
results =
|
||||||
|
conn
|
||||||
|
|> get("/api/v2/search?#{URI.encode_query(%{q: "computer laptop"})}")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
hashtag_names = Enum.map(results["hashtags"], & &1["name"])
|
||||||
|
assert "computer" in hashtag_names
|
||||||
|
assert "laptop" in hashtag_names
|
||||||
|
refute "desktop" in hashtag_names
|
||||||
|
refute "phone" in hashtag_names
|
||||||
|
end
|
||||||
|
|
||||||
test "supports pagination of hashtags search results", %{conn: conn} do
|
test "supports pagination of hashtags search results", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue