16b01101acced74ffb55d96f652aaa5b5e2fe6f3
[akkoma] / lib / pleroma / search / elasticsearch.ex
1 # Akkoma: A lightweight social networking server
2 # Copyright © 2022-2022 Akkoma Authors <https://git.ihatebeinga.live/IHBAGang/akkoma/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Search.Elasticsearch do
6 @behaviour Pleroma.Search.SearchBackend
7
8 alias Pleroma.Activity
9 alias Pleroma.Object.Fetcher
10 alias Pleroma.Web.ActivityPub.Visibility
11 alias Pleroma.Search.Elasticsearch.Parsers
12
13 def es_query(:activity, query, offset, limit) do
14 must = Parsers.Activity.parse(query)
15
16 if must == [] do
17 :skip
18 else
19 %{
20 size: limit,
21 from: offset,
22 terminate_after: 50,
23 timeout: "5s",
24 sort: [
25 "_score",
26 %{"_timestamp" => %{order: "desc", format: "basic_date_time"}}
27 ],
28 query: %{
29 bool: %{
30 must: must
31 }
32 }
33 }
34 end
35 end
36
37 defp maybe_fetch(:activity, search_query) do
38 with true <- Regex.match?(~r/https?:/, search_query),
39 {:ok, object} <- Fetcher.fetch_object_from_id(search_query),
40 %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]) do
41 activity
42 else
43 _ -> nil
44 end
45 end
46
47 def search(user, query, options) do
48 limit = Enum.min([Keyword.get(options, :limit), 40])
49 offset = Keyword.get(options, :offset, 0)
50
51 parsed_query =
52 query
53 |> String.trim()
54 |> SearchParser.parse!()
55
56 activity_fetch_task =
57 Task.async(fn ->
58 maybe_fetch(:activity, String.trim(query))
59 end)
60
61 activity_task =
62 Task.async(fn ->
63 q = es_query(:activity, parsed_query, offset, limit)
64
65 :activities
66 |> Pleroma.Search.Elasticsearch.Store.search(q)
67 |> Enum.filter(fn x ->
68 x.data["type"] == "Create" && x.object.data["type"] == "Note" &&
69 Visibility.visible_for_user?(x, user)
70 end)
71 end)
72
73 activity_results = Task.await(activity_task)
74 direct_activity = Task.await(activity_fetch_task)
75
76 activity_results =
77 if direct_activity == nil do
78 activity_results
79 else
80 [direct_activity | activity_results]
81 end
82
83 activity_results
84 end
85
86 @impl true
87 def add_to_index(activity) do
88 Elasticsearch.put_document(Pleroma.Search.Elasticsearch.Cluster, activity, "activities")
89 end
90
91 @impl true
92 def remove_from_index(object) do
93 Elasticsearch.delete_document(Pleroma.Search.Elasticsearch.Cluster, object, "activities")
94 end
95 end