Search_ash 0.5.0 - synonym support + memory leak fix

Just published search_ash 0.5.0 (with search_core 0.4.0) on Hex.

What’s new: synonyms

You can now declare a synonym dictionary per language:

elixir

synonyms %{en: %{"cat" => ["kitten"]}}

Typing cat now builds a tsquery like (cat | kitten), matching documents whose search_text contains either. A few things worth knowing:

  • It’s dictionary-based, not semantic — the library doesn’t “know” cat and kitten are related, it applies exactly the mapping you give it.
  • It’s one-directional: "cat" => ["kitten"] means typing cat also finds kitten, not the reverse — add both directions if you want symmetry.
  • Stemming still applies on both sides, so plurals/inflections are handled automatically.
  • Synonyms only expand the full-text match + ranking (search_text/ts_rank) — they deliberately don’t affect the global-search label ranking tiers or fuzzy/typo matching, so an exact title match still ranks first.

This turns out to be pretty handy for domain acronyms too ("bl" => ["bon de livraison"], etc.) — not just lexical synonyms.

What’s fixed: a memory leak

Also fixed a subtle memory retention issue related to how Elixir handles large binaries — a small referenced binary was keeping a much larger one alive longer than necessary. Fixed by forcing a copy at the right point in the pipeline instead of holding a sub-binary reference.

Feedback welcome, as always — especially on the synonym API shape if anyone has strong opinions on bidirectional-by-default vs explicit.

repo: https://github.com/nseaSeb/search_ash

7 Likes

Oh wow! Pretty nice!

1 Like

0.7.0 published

Added

  • counts_by/4 numeric ranges — a :montant/amount-like column can now be faceted with ranges: [0, 100, 500] (at least two strictly increasing breakpoints), counted per half-open interval {low, high} (a value equal to a breakpoint falls in the upper interval). Completes the facet kinds started in 0.6.0 (scalar, array, date bucket). Ranges are always caller-declared, never discovered from data — unlike the other kinds’ :values discovery, there is nothing to read to find them, so no memory/latency cost on a broad query. Mutually exclusive with :bucket and :values.
2 Likes