diff options
Diffstat (limited to 'lib/mix')
| -rw-r--r-- | lib/mix/tasks/pleroma/search/meilisearch.ex | 145 | 
1 files changed, 145 insertions, 0 deletions
| diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex new file mode 100644 index 000000000..8379a0c25 --- /dev/null +++ b/lib/mix/tasks/pleroma/search/meilisearch.ex @@ -0,0 +1,145 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.Search.Meilisearch do +  require Pleroma.Constants + +  import Mix.Pleroma +  import Ecto.Query + +  import Pleroma.Search.Meilisearch, +    only: [meili_post: 2, meili_put: 2, meili_get: 1, meili_delete: 1] + +  def run(["index"]) do +    start_pleroma() +    Pleroma.HTML.compile_scrubbers() + +    meili_version = +      ( +        {:ok, result} = meili_get("/version") + +        result["pkgVersion"] +      ) + +    # The ranking rule syntax was changed but nothing about that is mentioned in the changelog +    if not Version.match?(meili_version, ">= 0.25.0") do +      raise "Meilisearch <0.24.0 not supported" +    end + +    {:ok, _} = +      meili_post( +        "/indexes/objects/settings/ranking-rules", +        [ +          "published:desc", +          "words", +          "exactness", +          "proximity", +          "typo", +          "attribute", +          "sort" +        ] +      ) + +    {:ok, _} = +      meili_post( +        "/indexes/objects/settings/searchable-attributes", +        [ +          "content" +        ] +      ) + +    IO.puts("Created indices. Starting to insert posts.") + +    chunk_size = Pleroma.Config.get([Pleroma.Search.Meilisearch, :initial_indexing_chunk_size]) + +    Pleroma.Repo.transaction( +      fn -> +        query = +          from(Pleroma.Object, +            # Only index public and unlisted posts which are notes and have some text +            where: +              fragment("data->>'type' = 'Note'") and +                (fragment("data->'to' \\? ?", ^Pleroma.Constants.as_public()) or +                   fragment("data->'cc' \\? ?", ^Pleroma.Constants.as_public())), +            order_by: [desc: fragment("data->'published'")] +          ) + +        count = query |> Pleroma.Repo.aggregate(:count, :data) +        IO.puts("Entries to index: #{count}") + +        Pleroma.Repo.stream( +          query, +          timeout: :infinity +        ) +        |> Stream.map(&Pleroma.Search.Meilisearch.object_to_search_data/1) +        |> Stream.filter(fn o -> not is_nil(o) end) +        |> Stream.chunk_every(chunk_size) +        |> Stream.transform(0, fn objects, acc -> +          new_acc = acc + Enum.count(objects) + +          # Reset to the beginning of the line and rewrite it +          IO.write("\r") +          IO.write("Indexed #{new_acc} entries") + +          {[objects], new_acc} +        end) +        |> Stream.each(fn objects -> +          result = +            meili_put( +              "/indexes/objects/documents", +              objects +            ) + +          with {:ok, res} <- result do +            if not Map.has_key?(res, "uid") do +              IO.puts("\nFailed to index: #{inspect(result)}") +            end +          else +            e -> IO.puts("\nFailed to index due to network error: #{inspect(e)}") +          end +        end) +        |> Stream.run() +      end, +      timeout: :infinity +    ) + +    IO.write("\n") +  end + +  def run(["clear"]) do +    start_pleroma() + +    meili_delete("/indexes/objects/documents") +  end + +  def run(["show-keys", master_key]) do +    start_pleroma() + +    endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url]) + +    {:ok, result} = +      Pleroma.HTTP.get( +        Path.join(endpoint, "/keys"), +        [{"Authorization", "Bearer #{master_key}"}] +      ) + +    decoded = Jason.decode!(result.body) + +    if decoded["results"] do +      Enum.each(decoded["results"], fn %{"description" => desc, "key" => key} -> +        IO.puts("#{desc}: #{key}") +      end) +    else +      IO.puts("Error fetching the keys, check the master key is correct: #{inspect(decoded)}") +    end +  end + +  def run(["stats"]) do +    start_pleroma() + +    {:ok, result} = meili_get("/indexes/objects/stats") +    IO.puts("Number of entries: #{result["numberOfDocuments"]}") +    IO.puts("Indexing? #{result["isIndexing"]}") +  end +end | 
