Packages

Idiomatic Elixir client for the mneme embedded vector database core

Current section

Files

Jump to
mnemedb_client lib mneme pool.ex
Raw

lib/mneme/pool.ex

defmodule Mneme.Pool do
@moduledoc """
Optional serialized search wrapper.
In v0.1 this module is intentionally small and non-mandatory. It provides a
stable shape for future pooling work while already giving callers a named
process boundary for search operations.
Note: this module currently serializes requests through a single `GenServer`.
It does not provide true parallel pooling semantics yet.
## Examples
iex> collection = %Mneme.Collection{ref: make_ref(), name: "docs", dimension: 3, metric: :cosine}
iex> {:ok, pool} = Mneme.Pool.start_link(collection: collection)
iex> Mneme.Pool.search(pool, [1.0, 0.0, 0.0], limit: 1)
{:error, %Mneme.Error{code: :native_unavailable, message: "NIF is not loaded"}}
"""
use GenServer
alias Mneme.Collection
@type t :: pid()
@doc """
Starts the serialized search process.
Required options:
- `:collection` - a `%Mneme.Collection{}`
Optional options:
- `:name` - process registration name passed to `GenServer.start_link/3`
## Examples
iex> collection = %Mneme.Collection{ref: make_ref(), name: "docs", dimension: 3, metric: :cosine}
iex> {:ok, pid} = Mneme.Pool.start_link(collection: collection)
iex> is_pid(pid)
true
"""
@spec start_link(keyword()) :: GenServer.on_start()
def start_link(opts) do
{gen_opts, init_opts} = Keyword.split(opts, [:name])
GenServer.start_link(__MODULE__, init_opts, gen_opts)
end
@doc """
Executes a search through the pool process.
This delegates to `Mneme.Collection.search/3` inside the server process.
## Examples
iex> collection = %Mneme.Collection{ref: make_ref(), name: "docs", dimension: 3, metric: :cosine}
iex> {:ok, pool} = Mneme.Pool.start_link(collection: collection)
iex> Mneme.Pool.search(pool, [1.0, 0.0, 0.0], limit: 1)
{:error, %Mneme.Error{code: :native_unavailable, message: "NIF is not loaded"}}
"""
@spec search(t(), [number()], keyword()) ::
{:ok, [Mneme.Result.t()]} | {:error, Mneme.Error.t()}
def search(pool, query, opts \\ []), do: GenServer.call(pool, {:search, query, opts})
@impl true
def init(opts) do
case Keyword.fetch(opts, :collection) do
{:ok, collection} ->
{:ok, %{collection: collection}}
:error ->
{:stop, {:missing_option, :collection}}
end
end
@impl true
def handle_call({:search, query, opts}, _from, state) do
{:reply, Collection.search(state.collection, query, opts), state}
end
end