How to implement Meilisearch in an Elixir project?

I am trying to implement Meilisearch in my elixir phoenix project, anyone has done this before any suggestions you have. MeiliSearch Elixir — meilisearch v0.20.0.

1 Like

I’m planning to use meilisearch, haven’t integrated it yet though. This seems like a good library, I was planning to write mine from scratch using Tesla.

Before this I tried using haystack (which uses ets and custom elixir trigram ago I guess) for my use case (fetching data for autocomplete and a few other things). But it is still very new and wasn’t happy with the results.

Just a note, I edited your title as you had a typo in it: Milisearch → Meilisearch

BTW have in mind that this library, while very good (I keep hearing), is not a replacement for an entire search cluster, should you predict that you will need one in the future. So know your tradeoffs.

(Though they have announced a cloud offering some time ago as well so that may be changing.)

3 Likes

I used it in a side project. Millisearch has a very simple API, so I just called that.

Two helper functions to get and post:

def get(url) do
    case HTTPoison.get(url, Authorization: "Bearer aaaaa") do
      {:ok, %{status_code: 200, body: body} = response} ->
        # Logger.debug(response)
        {:ok, 200, body |> Jason.decode!()}

      {:ok, %{status_code: other, body: body} = error} ->
        # Logger.error(error)
        {:error, other, body |> Jason.decode!()}

      {:error, %HTTPoison.Error{} = error} ->
        # Logger.error(Exception.format(:error, error))
        {:error, -1, Exception.format(:error, error)}

      other ->
        Logger.error(other)
        {:error, -1, :unknown}
    end
  end

  defp post(url, body) do
    case HTTPoison.post(url, Jason.encode!(body),
           Authorization: "Bearer aaaaa",
           "Content-Type": "application/json"
         ) do
      {:ok, %{status_code: code, body: body} = response}
      when code == 200 or code == 201 or code == 202 or code == 301 or code == 302 ->
        # Logger.debug(response)
        {:ok, code, body |> Jason.decode!()}

      {:ok, %{status_code: other, body: body} = error} ->
        # Logger.error(error)
        {:error, other, body |> Jason.decode!()}

      {:error, %HTTPoison.Error{} = error} ->
        # Logger.error(Exception.format(:error, error))
        {:error, -1, Exception.format(:error, error)}

      other ->
        # Logger.error(other)
        {:error, -1, :unknown}
    end
  end

And then.

Creating an index:

def create_index(index) do
    case get("http://127.0.0.1:7700/indexes/#{index}/stats") do
      {:ok, _, response} = ok -> # the index is there
        ok

      {:error, _, _} = e ->
        post("http://127.0.0.1:7700/indexes", %{uid: index, primaryKey: :id})
    end
  end

Re-indexing:

defp reindex(documents, index) do
    post("http://127.0.0.1:7700/indexes/#{index}/documents", documents)
end

Search

def search(index, search, opts) do
    limit = opts[:limit] || 20
    page = opts[:page] || 0

    case post("http://127.0.0.1:7700/indexes/#{index}/search", %{
           q: search,
           limit: limit,
           offset: page * limit
         }) do
      {:error, _, e} ->
        # handle error

      {:ok, _, result} ->
         # do something with the result
    end
end

This is basically all you need in most cases

7 Likes

Hi @dimitarvp what do you mean about “is not a replacement for an entire search cluster”?

I mean that so far they don’t offer clustered search cluster functionality. Or they haven’t, last time I checked, which was 4-5 months ago (around the start of the year).

Which means, single server only.

I see what you meant, thanks!

I’m a member of Meilisearch and I query one of my colleagues about that subject…

Here you can see public discussions about it:

We’re working on this matter and I would love to had your insights about your use cases there!

1 Like