use elastic multi search API for specific pages

This commit is contained in:
byte[] 2020-08-23 16:53:25 -04:00
parent 3fce31b658
commit 75de5f867d
6 changed files with 117 additions and 50 deletions

View file

@ -183,6 +183,26 @@ defmodule Philomena.Elasticsearch do
results
end
def msearch(definitions) do
msearch_body =
Enum.flat_map(definitions, fn def ->
[
%{index: index_for(def.module).index_name()},
def.body
]
end)
{:ok, %{body: results, status_code: 200}} =
Elastix.Search.search(
elastic_url(),
"_all",
[],
msearch_body
)
results["responses"]
end
def search_definition(module, elastic_query, pagination_params \\ %{}) do
page_number = pagination_params[:page_number] || 1
page_size = pagination_params[:page_size] || 25
@ -203,8 +223,7 @@ defmodule Philomena.Elasticsearch do
}
end
def search_results(definition) do
results = search(definition.module, definition.body)
defp process_results(results, definition) do
time = results["took"]
count = results["hits"]["total"]["value"]
entries = Enum.map(results["hits"]["hits"], &{String.to_integer(&1["_id"]), &1})
@ -221,6 +240,16 @@ defmodule Philomena.Elasticsearch do
}
end
def search_results(definition) do
process_results(search(definition.module, definition.body), definition)
end
def msearch_results(definitions) do
Enum.map(Enum.zip(msearch(definitions), definitions), fn {result, definition} ->
process_results(result, definition)
end)
end
defp load_records_from_results(results, ecto_queries) do
Enum.map(Enum.zip(results, ecto_queries), fn {page, ecto_query} ->
{ids, hits} = Enum.unzip(page.entries)
@ -241,10 +270,22 @@ defmodule Philomena.Elasticsearch do
page
end
def msearch_records_with_hits(definitions, ecto_queries) do
load_records_from_results(msearch_results(definitions), ecto_queries)
end
def search_records(definition, ecto_query) do
page = search_records_with_hits(definition, ecto_query)
{records, _hits} = Enum.unzip(page.entries)
%{page | entries: records}
end
def msearch_records(definitions, ecto_queries) do
Enum.map(load_records_from_results(msearch_results(definitions), ecto_queries), fn page ->
{records, _hits} = Enum.unzip(page.entries)
%{page | entries: records}
end)
end
end

View file

@ -35,12 +35,9 @@ defmodule PhilomenaWeb.ActivityController do
pagination: %{page_number: :rand.uniform(6), page_size: 4}
)
images = Elasticsearch.search_records(images, preload(Image, :tags))
top_scoring = Elasticsearch.search_records(top_scoring, preload(Image, :tags))
comments =
Comment
|> Elasticsearch.search_definition(
Elasticsearch.search_definition(
Comment,
%{
query: %{
bool: %{
@ -57,7 +54,6 @@ defmodule PhilomenaWeb.ActivityController do
},
%{page_number: 1, page_size: 6}
)
|> Elasticsearch.search_records(preload(Comment, [:user, image: [:tags]]))
watched =
if !!user do
@ -68,11 +64,12 @@ defmodule PhilomenaWeb.ActivityController do
pagination: %{conn.assigns.image_pagination | page_number: 1}
)
watched_images = Elasticsearch.search_records(watched_images, preload(Image, :tags))
if Enum.any?(watched_images), do: watched_images
watched_images
end
[images, top_scoring, comments, watched] =
multi_search(images, top_scoring, comments, watched)
featured_image =
Image
|> join(:inner, [i], f in ImageFeature, on: [image_id: i.id])
@ -142,4 +139,26 @@ defmodule PhilomenaWeb.ActivityController do
)
)
end
defp multi_search(images, top_scoring, comments, nil) do
responses =
Elasticsearch.msearch_records(
[images, top_scoring, comments],
[preload(Image, :tags), preload(Image, :tags), preload(Comment, [:user, image: :tags])]
)
responses ++ [nil]
end
defp multi_search(images, top_scoring, comments, watched) do
Elasticsearch.msearch_records(
[images, top_scoring, comments, watched],
[
preload(Image, :tags),
preload(Image, :tags),
preload(Comment, [:user, image: :tags]),
preload(Image, :tags)
]
)
end
end

View file

@ -53,21 +53,22 @@ defmodule PhilomenaWeb.GalleryController do
"sd" => position_order(gallery)
})
conn = %{conn | params: params}
{:ok, {images, _tags}} = ImageLoader.search_string(conn, query)
images = Elasticsearch.search_records_with_hits(images, preload(Image, :tags))
{gallery_prev, gallery_next} = prev_next_page_images(conn, query)
[images, gallery_prev, gallery_next] =
Elasticsearch.msearch_records_with_hits(
[images, gallery_prev, gallery_next],
[preload(Image, :tags), preload(Image, :tags), preload(Image, :tags)]
)
interactions = Interactions.user_interactions([images, gallery_prev, gallery_next], user)
watching = Galleries.subscribed?(gallery, user)
prev_image = if gallery_prev, do: [gallery_prev], else: []
next_image = if gallery_next, do: [gallery_next], else: []
gallery_images =
Enum.to_list(gallery_prev) ++ Enum.to_list(images) ++ Enum.to_list(gallery_next)
gallery_images = prev_image ++ Enum.to_list(images) ++ next_image
gallery_json = Jason.encode!(Enum.map(gallery_images, &elem(&1, 0).id))
Galleries.clear_notification(gallery, user)
@ -81,8 +82,8 @@ defmodule PhilomenaWeb.GalleryController do
layout_class: "layout--wide",
watching: watching,
gallery: gallery,
gallery_prev: gallery_prev,
gallery_next: gallery_next,
gallery_prev: Enum.any?(gallery_prev),
gallery_next: Enum.any?(gallery_next),
gallery_images: gallery_images,
images: images,
interactions: interactions
@ -159,20 +160,16 @@ defmodule PhilomenaWeb.GalleryController do
{prev_image, next_image}
end
defp gallery_image(offset, _conn, _query) when offset < 0, do: nil
defp gallery_image(offset, _conn, _query) when offset < 0 do
Elasticsearch.search_definition(Image, %{query: %{match_none: %{}}})
end
defp gallery_image(offset, conn, query) do
pagination_params = %{page_number: offset + 1, page_size: 1}
{:ok, {image, _tags}} =
ImageLoader.search_string(conn, query, pagination: pagination_params)
{:ok, {image, _tags}} = ImageLoader.search_string(conn, query, pagination: pagination_params)
image = Elasticsearch.search_records_with_hits(image, preload(Image, :tags))
case Enum.to_list(image) do
[image] -> image
[] -> nil
end
image
end
defp parse_search(%{"gallery" => gallery_params}) do

View file

@ -53,9 +53,6 @@ defmodule PhilomenaWeb.ProfileController do
pagination: %{page_number: 1, page_size: 4}
)
recent_uploads = Elasticsearch.search_records(recent_uploads, preload(Image, :tags))
recent_faves = Elasticsearch.search_records(recent_faves, preload(Image, :tags))
tags = tags(conn.assigns.user.public_links)
all_tag_ids =
@ -78,8 +75,8 @@ defmodule PhilomenaWeb.ProfileController do
recent_artwork = recent_artwork(conn, tags)
recent_comments =
Comment
|> Elasticsearch.search_definition(
Elasticsearch.search_definition(
Comment,
%{
query: %{
bool: %{
@ -97,17 +94,10 @@ defmodule PhilomenaWeb.ProfileController do
},
%{page_size: 3}
)
|> Elasticsearch.search_records(preload(Comment, user: [awards: :badge], image: :tags))
|> Enum.filter(&Canada.Can.can?(current_user, :show, &1.image))
recent_comments =
recent_comments
|> TextileRenderer.render_collection(conn)
|> Enum.zip(recent_comments)
recent_posts =
Post
|> Elasticsearch.search_definition(
Elasticsearch.search_definition(
Post,
%{
query: %{
bool: %{
@ -123,8 +113,26 @@ defmodule PhilomenaWeb.ProfileController do
},
%{page_size: 6}
)
|> Elasticsearch.search_records(preload(Post, user: [awards: :badge], topic: :forum))
|> Enum.filter(&Canada.Can.can?(current_user, :show, &1.topic))
[recent_uploads, recent_faves, recent_artwork, recent_comments, recent_posts] =
Elasticsearch.msearch_records(
[recent_uploads, recent_faves, recent_artwork, recent_comments, recent_posts],
[
preload(Image, :tags),
preload(Image, :tags),
preload(Image, :tags),
preload(Comment, user: [awards: :badge], image: :tags),
preload(Post, user: [awards: :badge], topic: :forum)
]
)
recent_posts = Enum.filter(recent_posts, &Canada.Can.can?(current_user, :show, &1.topic))
recent_comments =
recent_comments
|> Enum.filter(&Canada.Can.can?(current_user, :show, &1.image))
|> TextileRenderer.render_collection(conn)
|> Enum.zip(recent_comments)
about_me = TextileRenderer.render_one(%{body: user.description || ""}, conn)
@ -214,7 +222,9 @@ defmodule PhilomenaWeb.ProfileController do
defp tags([]), do: []
defp tags(links), do: Enum.map(links, & &1.tag) |> Enum.reject(&is_nil/1)
defp recent_artwork(_conn, []), do: []
defp recent_artwork(_conn, []) do
Elasticsearch.search_definition(Image, %{query: %{match_none: %{}}})
end
defp recent_artwork(conn, tags) do
{images, _tags} =
@ -224,7 +234,7 @@ defmodule PhilomenaWeb.ProfileController do
pagination: %{page_number: 1, page_size: 4}
)
Elasticsearch.search_records(images, preload(Image, :tags))
images
end
defp set_admin_metadata(conn, _opts) do

View file

@ -51,7 +51,7 @@ h3 Visibility
h3 Associated tag
= if @user_link.tag do
p
.tag-list
= render PhilomenaWeb.TagView, "_tag.html", tag: @user_link.tag, conn: @conn
- else
p There is no tag associated with this link.

View file

@ -12,10 +12,10 @@ defmodule PhilomenaWeb.GalleryView do
|> Enum.join(" ")
end
def sortable_prev(list, nil), do: list
def sortable_prev(list, false), do: list
def sortable_prev(list, _), do: ["js-sortable-has-prev" | list]
def sortable_next(list, nil), do: list
def sortable_next(list, false), do: list
def sortable_next(list, _), do: ["js-sortable-has-next" | list]
def show_subscription_link?(%{id: id}, %{id: id}), do: false