View Source Fuzler
Fuzler
is a lightweight, reusable cache built on top of an ETS table and wrapped in a GenServer
, with built‑in fuzzy text search powered by a Rust NIF for high-performance similarity scoring.
features
Features
- Named ETS table: Give any atom as
:table
. - Public reads / protected writes: ETS is
:public
with concurrency options; only the GenServer process can write. - O(1) lookup: Table name → ETS table mapping stored in
:persistent_term
, avoiding extra GenServer calls. - Hot reload:
reload/1
clears and repopulates from your loader function. - Insert / Get / Stream: Standard cache operations.
- Fuzzy full-text search:
text_search/3
returns top‑N{key, value, score}
suggestions using a SIMD‑accelerated Rust NIF.
installation
Installation
Add fuzler
to your dependencies in mix.exs
:
def deps do
[
{:fuzler, git: "https://github.com/elchemista/fuzler.git"}
]
end
Then fetch and compile:
mix deps.get
mix compile
Make sure you have Rust installed; the Rustler NIF will compile automatically.
quickstart
Quickstart
1-start-the-cache
1. Start the cache
loader = fn ->
[
{"apple", %{id: 1}},
{"banana", %{id: 2}},
{"cantaloupe", %{id: 3}}
]
end
{:ok, _pid} =
Fuzler.start_link(
table: :fruit_cache,
loader: loader,
name: :my_cache
)
2-basic-operations
2. Basic operations
# Get a value
Fuzler.get("banana")
#⇒ %{id: 2}
# Insert a new item
Fuzler.insert({"durian", %{id: 4}})
Fuzler.get("durian")
#⇒ %{id: 4}
# Reload all data
Fuzler.reload(:my_cache)
# Stream entries matching predicate
Fuzler.stream(fn %{id: id} -> id <= 2 end)
|> Enum.map(&elem(&1, 0))
#⇒ ["apple", "banana"]
3-fuzzy-text-search
3. Fuzzy text search
# Suggest keys similar to "ap"
Fuzler.text_search("ap", limit: 5)
#⇒ [
# {"apple", %{id: 1}, 1.0},
# {"grape", %{id: 7}, 0.75},
# ...
#]
- Options:
:limit
– maximum results (default: 15):threshold
– minimum score (default: 0.10):keys
– pre-collected list of keys to search (avoids re-scanning ETS)
module-api
Module API
@spec start_link(opts :: keyword()) :: GenServer.on_start()
@spec reload(server \ server()) :: :ok
@spec insert({key, value}, server) :: :ok
@spec get(key, server) :: value | nil
@spec stream((value -> boolean), server) :: Enumerable.t()
@spec text_search(String.t(), keyword(), server) :: [{key, value, float()}]
running-tests
Running tests
mix test # runs Elixir tests
license
License
MIT License