Add the meilisearch.stats command
[akkoma] / lib / mix / tasks / pleroma / search / meilisearch.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Mix.Tasks.Pleroma.Search.Meilisearch do
6 require Logger
7 require Pleroma.Constants
8
9 import Mix.Pleroma
10 import Ecto.Query
11
12 import Pleroma.Search.Meilisearch, only: [meili_post!: 2, meili_delete!: 1, meili_get!: 1]
13
14 def run(["index"]) do
15 start_pleroma()
16
17 meili_post!(
18 "/indexes/objects/settings/ranking-rules",
19 [
20 "desc(published)",
21 "typo",
22 "words",
23 "proximity",
24 "attribute",
25 "wordsPosition",
26 "exactness"
27 ]
28 )
29
30 meili_post!(
31 "/indexes/objects/settings/searchable-attributes",
32 [
33 "content"
34 ]
35 )
36
37 chunk_size = 10_000
38
39 Pleroma.Repo.transaction(
40 fn ->
41 query =
42 from(Pleroma.Object,
43 # Only index public posts which are notes and have some text
44 where:
45 fragment("data->>'type' = 'Note'") and
46 fragment("LENGTH(data->>'content') > 0") and
47 fragment("data->'to' \\? ?", ^Pleroma.Constants.as_public()),
48 order_by: [desc: fragment("data->'published'")]
49 )
50
51 count = query |> Pleroma.Repo.aggregate(:count, :data)
52 IO.puts("Entries to index: #{count}")
53
54 Pleroma.Repo.stream(
55 query,
56 timeout: :infinity
57 )
58 |> Stream.map(&Pleroma.Search.Meilisearch.object_to_search_data/1)
59 |> Stream.filter(fn o -> not is_nil(o) end)
60 |> Stream.chunk_every(chunk_size)
61 |> Stream.transform(0, fn objects, acc ->
62 new_acc = acc + Enum.count(objects)
63
64 # Reset to the beginning of the line and rewrite it
65 IO.write("\r")
66 IO.write("Indexed #{new_acc} entries")
67
68 {[objects], new_acc}
69 end)
70 |> Stream.each(fn objects ->
71 result =
72 meili_post!(
73 "/indexes/objects/documents",
74 objects
75 )
76
77 if not Map.has_key?(result, "updateId") do
78 IO.puts("Failed to index: #{inspect(result)}")
79 end
80 end)
81 |> Stream.run()
82 end,
83 timeout: :infinity
84 )
85
86 IO.write("\n")
87 end
88
89 def run(["clear"]) do
90 start_pleroma()
91
92 meili_delete!("/indexes/objects/documents")
93 end
94
95 def run(["show-private-key", master_key]) do
96 start_pleroma()
97
98 endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
99
100 {:ok, result} =
101 Pleroma.HTTP.get(
102 Path.join(endpoint, "/keys"),
103 [{"X-Meili-API-Key", master_key}]
104 )
105
106 decoded = Jason.decode!(result.body)
107
108 if decoded["private"] do
109 IO.puts(decoded["private"])
110 else
111 IO.puts("Error fetching the key, check the master key is correct: #{inspect(decoded)}")
112 end
113 end
114
115 def run(["stats"]) do
116 start_pleroma()
117
118 result = meili_get!("/indexes/objects/stats")
119 IO.puts("Number of entries: #{result["numberOfDocuments"]}")
120 IO.puts("Indexing? #{result["isIndexing"]}")
121 end
122 end