def autocomplete(conn, %"term" => term) do suggestions = Blog.search_posts(term, []) |> Enum.take(5) |> Enum.map(&%title: &1.title, id: &1.id)
defp apply_filters(query, []), do: query defp apply_filters(query, filters) do Enum.reduce(filters, query, fn :category, category, q -> from p in q, where: p.category == ^category :published_after, date, q -> from p in q, where: p.inserted_at >= ^date end) end uni ecto plugin
defp order_by_relevance(query, nil), do: query defp order_by_relevance(query, term) do from q in query, order_by: [desc: fragment( "ts_rank(to_tsvector('english', ?), plainto_tsquery('english', ?))", fragment("coalesce(?, '') || ' ' || coalesce(?, '')", q.title, q.content), ^term )] end end # lib/my_app_web/controllers/search_controller.ex defmodule MyAppWeb.SearchController do use MyAppWeb, :controller alias MyApp.Blog def autocomplete(conn, %"term" => term) do suggestions =
test "search finds relevant posts" do results = Blog.search_posts("elixir search") assert length(results) > 0 assert Enum.any?(results, &String.contains?(&1.title, "Elixir")) end term) do suggestions = Blog.search_posts(term
defp rank_by_relevance(query, nil), do: query defp rank_by_relevance(query, term) when term == "", do: query defp rank_by_relevance(query, term) do from q in query, select_merge: % coalesce(?, '')", q.title, q.content), ^term ) , order_by: [desc: fragment("relevance")] end end # lib/my_app/blog/blog.ex defmodule MyApp.Blog do import Ecto.Query alias MyApp.Repo alias MyApp.Blog.Post def search_posts(search_term, filters \ []) do Post |> search(search_term) # From plugin |> apply_filters(filters) |> order_by_relevance(search_term) |> Repo.all() end