diff --git a/lib/bdfr_browser/comment.ex b/lib/bdfr_browser/comment.ex index 6910032..863459b 100644 --- a/lib/bdfr_browser/comment.ex +++ b/lib/bdfr_browser/comment.ex @@ -46,8 +46,6 @@ defmodule BdfrBrowser.Comment do def search(str), do: search(str, nil) def search(str, subreddits) when is_nil(subreddits) do - search_str = "%#{str}%" - from(c in __MODULE__, join: p in assoc(c, :post), join: s in assoc(p, :subreddit), @@ -62,15 +60,15 @@ defmodule BdfrBrowser.Comment do post_title: p.title, post_date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, - where: ilike(c.body, ^search_str), + where: + fragment("? @@ websearch_to_tsquery('english', ?)", c.searchable_content, ^str) or + fragment("? @@ websearch_to_tsquery('german', ?)", c.searchable_content, ^str), order_by: [desc: c.posted_at], group_by: [c.id, p.id, s.name] ) end def search(str, subreddits) when is_list(subreddits) do - search_str = "%#{str}%" - from(c in __MODULE__, join: p in assoc(c, :post), join: s in assoc(p, :subreddit), @@ -85,7 +83,10 @@ defmodule BdfrBrowser.Comment do post_title: p.title, post_date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, - where: s.name in ^subreddits and ilike(c.body, ^search_str), + where: + s.name in ^subreddits and + (fragment("? @@ websearch_to_tsquery('english', ?)", c.searchable_content, ^str) or + fragment("? @@ websearch_to_tsquery('german', ?)", c.searchable_content, ^str)), order_by: [desc: c.posted_at], group_by: [c.id, p.id, s.name] ) diff --git a/lib/bdfr_browser/post.ex b/lib/bdfr_browser/post.ex index 9501618..a0ea877 100644 --- a/lib/bdfr_browser/post.ex +++ b/lib/bdfr_browser/post.ex @@ -123,8 +123,6 @@ defmodule BdfrBrowser.Post do def search(str), do: search(str, nil) def search(str, subreddits) when is_nil(subreddits) do - search_str = "%#{str}%" - from(p in __MODULE__, left_join: c in assoc(p, :comments), join: s in assoc(p, :subreddit), @@ -137,15 +135,15 @@ defmodule BdfrBrowser.Post do subreddit: s.name, date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, - where: ilike(p.title, ^search_str) or ilike(p.selftext, ^search_str), + where: + fragment("? @@ websearch_to_tsquery('english', ?)", p.searchable_content, ^str) or + fragment("? @@ websearch_to_tsquery('german', ?)", p.searchable_content, ^str), order_by: [desc: p.posted_at], group_by: [p.id, s.name] ) end def search(str, subreddits) when is_list(subreddits) do - search_str = "%#{str}%" - from(p in __MODULE__, left_join: c in assoc(p, :comments), join: s in assoc(p, :subreddit), @@ -158,7 +156,10 @@ defmodule BdfrBrowser.Post do subreddit: s.name, date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, - where: s.name in ^subreddits and (ilike(p.title, ^search_str) or ilike(p.selftext, ^search_str)), + where: + s.name in ^subreddits and + (fragment("? @@ websearch_to_tsquery('english', ?)", p.searchable_content, ^str) or + fragment("? @@ websearch_to_tsquery('german', ?)", p.searchable_content, ^str)), order_by: [desc: p.posted_at], group_by: [p.id, s.name] ) diff --git a/priv/repo/migrations/20231009190058_add_post_comment_fulltext_search.exs b/priv/repo/migrations/20231009190058_add_post_comment_fulltext_search.exs new file mode 100644 index 0000000..ff6e601 --- /dev/null +++ b/priv/repo/migrations/20231009190058_add_post_comment_fulltext_search.exs @@ -0,0 +1,53 @@ +defmodule BdfrBrowser.Repo.Migrations.AddPostCommentFulltextSearch do + use Ecto.Migration + + def up do + # Posts + execute """ + ALTER TABLE posts + ADD COLUMN searchable_content tsvector + GENERATED ALWAYS AS ( + setweight(to_tsvector('english', coalesce(title, '')), 'A') || + setweight(to_tsvector('german', coalesce(title, '')), 'A') || + setweight(to_tsvector('english', coalesce(selftext, '')), 'B') || + setweight(to_tsvector('german', coalesce(selftext, '')), 'B') || + setweight(to_tsvector('simple', coalesce(author, '')), 'C') + ) STORED; + """ + + execute """ + CREATE INDEX posts_searchable_content_index ON posts USING gin(searchable_content); + """ + + # Comments + execute """ + ALTER TABLE comments + ADD COLUMN searchable_content tsvector + GENERATED ALWAYS AS ( + setweight(to_tsvector('english', coalesce(body, '')), 'A') || + setweight(to_tsvector('german', coalesce(body, '')), 'A') || + setweight(to_tsvector('simple', coalesce(author, '')), 'B') + ) STORED; + """ + + execute """ + CREATE INDEX comments_searchable_content_index ON comments USING gin(searchable_content); + """ + end + + def down do + # Posts + drop index("posts", [:searchable_content]) + + alter table(:posts) do + remove :searchable_content + end + + # Comments + drop index("comments", [:searchable_content]) + + alter table(:comments) do + remove :searchable_content + end + end +end