Merge remote-tracking branch 'origin/feature/elasticsearch' into develop
[akkoma] / lib / pleroma / elasticsearch / store.ex
1 defmodule Pleroma.Elasticsearch do
2 alias Pleroma.Activity
3 alias Pleroma.User
4 alias Pleroma.Object
5 alias Pleroma.Elasticsearch.DocumentMappings
6 alias Pleroma.Config
7 require Logger
8
9 defp url do
10 Config.get([:elasticsearch, :url])
11 end
12
13 defp enabled? do
14 Config.get([:search, :provider]) == Pleroma.Search.Elasticsearch
15 end
16
17 def put_by_id(:activity, id) do
18 id
19 |> Activity.get_by_id_with_object()
20 |> maybe_put_into_elasticsearch()
21 end
22
23 def maybe_put_into_elasticsearch({:ok, item}) do
24 maybe_put_into_elasticsearch(item)
25 end
26
27 def maybe_put_into_elasticsearch(
28 %{data: %{"type" => "Create"}, object: %{data: %{"type" => "Note"}}} = activity
29 ) do
30 if enabled?() do
31 actor = Pleroma.Activity.user_actor(activity)
32
33 activity
34 |> Map.put(:user_actor, actor)
35 |> put()
36 end
37 end
38
39 def maybe_put_into_elasticsearch(%User{actor_type: "Person"} = user) do
40 if enabled?() do
41 put(user)
42 end
43 end
44
45 def maybe_put_into_elasticsearch(_) do
46 {:ok, :skipped}
47 end
48
49 def maybe_bulk_post(data, type) do
50 if enabled?() do
51 bulk_post(data, type)
52 end
53 end
54
55 def put(%Activity{} = activity) do
56 {:ok, _} =
57 Elastix.Document.index(
58 url(),
59 "activities",
60 "activity",
61 DocumentMappings.Activity.id(activity),
62 DocumentMappings.Activity.encode(activity)
63 )
64
65 activity
66 |> Map.get(:object)
67 |> Object.hashtags()
68 |> Enum.map(fn x -> %{id: x, name: x, timestamp: DateTime.to_iso8601(DateTime.utc_now())} end)
69 |> bulk_post(:hashtags)
70 end
71
72 def put(%User{} = user) do
73 {:ok, _} =
74 Elastix.Document.index(
75 url(),
76 "users",
77 "user",
78 DocumentMappings.User.id(user),
79 DocumentMappings.User.encode(user)
80 )
81 end
82
83 def bulk_post(data, :activities) do
84 d =
85 data
86 |> Enum.filter(fn x ->
87 t =
88 x.object
89 |> Map.get(:data, %{})
90 |> Map.get("type", "")
91
92 t == "Note"
93 end)
94 |> Enum.map(fn d ->
95 [
96 %{index: %{_id: DocumentMappings.Activity.id(d)}},
97 DocumentMappings.Activity.encode(d)
98 ]
99 end)
100 |> List.flatten()
101
102 {:ok, %{body: %{"errors" => false}}} =
103 Elastix.Bulk.post(
104 url(),
105 d,
106 index: "activities",
107 type: "activity"
108 )
109 end
110
111
112 def bulk_post(data, :users) do
113 d =
114 data
115 |> Enum.filter(fn x -> x.actor_type == "Person" end)
116 |> Enum.map(fn d ->
117 [
118 %{index: %{_id: DocumentMappings.User.id(d)}},
119 DocumentMappings.User.encode(d)
120 ]
121 end)
122 |> List.flatten()
123
124 Elastix.Bulk.post(
125 url(),
126 d,
127 index: "users",
128 type: "user"
129 )
130 end
131
132 def bulk_post(data, :hashtags) when is_list(data) do
133 d =
134 data
135 |> Enum.map(fn d ->
136 [
137 %{index: %{_id: DocumentMappings.Hashtag.id(d)}},
138 DocumentMappings.Hashtag.encode(d)
139 ]
140 end)
141 |> List.flatten()
142
143 Elastix.Bulk.post(
144 url(),
145 d,
146 index: "hashtags",
147 type: "hashtag"
148 )
149 end
150
151 def bulk_post(_, :hashtags), do: {:ok, nil}
152
153 def search(_, _, _, :skip), do: []
154
155 def search(:raw, index, type, q) do
156 with {:ok, raw_results} <- Elastix.Search.search(url(), index, [type], q) do
157 results =
158 raw_results
159 |> Map.get(:body, %{})
160 |> Map.get("hits", %{})
161 |> Map.get("hits", [])
162
163 {:ok, results}
164 else
165 {:error, e} ->
166 Logger.error(e)
167 {:error, e}
168 end
169 end
170
171 def search(:activities, q) do
172 with {:ok, results} <- search(:raw, "activities", "activity", q) do
173 results
174 |> Enum.map(fn result -> result["_id"] end)
175 |> Pleroma.Activity.all_by_ids_with_object()
176 |> Enum.sort(&(&1.inserted_at >= &2.inserted_at))
177 else
178 e ->
179 Logger.error(e)
180 []
181 end
182 end
183
184 def search(:users, q) do
185 with {:ok, results} <- search(:raw, "users", "user", q) do
186 results
187 |> Enum.map(fn result -> result["_id"] end)
188 |> Pleroma.User.get_all_by_ids()
189 else
190 e ->
191 Logger.error(e)
192 []
193 end
194 end
195
196 def search(:hashtags, q) do
197 with {:ok, results} <- search(:raw, "hashtags", "hashtag", q) do
198 results
199 |> Enum.map(fn result -> result["_source"]["hashtag"] end)
200 else
201 e ->
202 Logger.error(e)
203 []
204 end
205 end
206 end