Multilingual full-text search building blocks for plain Elixir/Ecto — no Ash required.
Two responsibilities:
SearchCore.Pipeline— turn raw text into normalized, stemmed tokens (viatext_stemmer, French and the full Snowball set included).SearchCore.Tsvector— turn those tokens into thesearch_textyou index and thetsqueryyou search with, both from the same pipeline so index and query never drift apart.SearchCore.Highlight— mark the words of a raw text that match a query, for rendering result excerpts; same pipeline again, so highlighting agrees with what actually matched.
This module is a thin facade over those. See SearchCore.Tsvector for the
Postgres wiring (to_tsvector('simple', …) / to_tsquery('simple', …)).
Every function here is pure and keeps no process state. The one place it hands back
fragments of your text — highlight/4's matched words and the spans around them —
copies each into a standalone binary rather than leaving it a sub-binary, so stashing
the result in long-lived state (a LiveView assign, a GenServer) never pins the whole
source text in memory through a word-sized fragment.
iex> SearchCore.searchable_text("Les chevaux mangent", :fr)
"cheval mangent"
iex> SearchCore.tsquery("chevaux", :fr)
"cheval"
iex> SearchCore.highlight("Les chevaux verts", "cheval", :fr)
[{:text, "Les "}, {:match, "chevaux"}, {:text, " verts"}]