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 results
end 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 def search_definition(module, elastic_query, pagination_params \\ %{}) do
page_number = pagination_params[:page_number] || 1 page_number = pagination_params[:page_number] || 1
page_size = pagination_params[:page_size] || 25 page_size = pagination_params[:page_size] || 25
@ -203,8 +223,7 @@ defmodule Philomena.Elasticsearch do
} }
end end
def search_results(definition) do defp process_results(results, definition) do
results = search(definition.module, definition.body)
time = results["took"] time = results["took"]
count = results["hits"]["total"]["value"] count = results["hits"]["total"]["value"]
entries = Enum.map(results["hits"]["hits"], &{String.to_integer(&1["_id"]), &1}) entries = Enum.map(results["hits"]["hits"], &{String.to_integer(&1["_id"]), &1})
@ -221,6 +240,16 @@ defmodule Philomena.Elasticsearch do
} }
end 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 defp load_records_from_results(results, ecto_queries) do
Enum.map(Enum.zip(results, ecto_queries), fn {page, ecto_query} -> Enum.map(Enum.zip(results, ecto_queries), fn {page, ecto_query} ->
{ids, hits} = Enum.unzip(page.entries) {ids, hits} = Enum.unzip(page.entries)
@ -241,10 +270,22 @@ defmodule Philomena.Elasticsearch do
page page
end 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 def search_records(definition, ecto_query) do
page = search_records_with_hits(definition, ecto_query) page = search_records_with_hits(definition, ecto_query)
{records, _hits} = Enum.unzip(page.entries) {records, _hits} = Enum.unzip(page.entries)
%{page | entries: records} %{page | entries: records}
end 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 end

View file

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

View file

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

View file

@ -53,9 +53,6 @@ defmodule PhilomenaWeb.ProfileController do
pagination: %{page_number: 1, page_size: 4} 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) tags = tags(conn.assigns.user.public_links)
all_tag_ids = all_tag_ids =
@ -78,8 +75,8 @@ defmodule PhilomenaWeb.ProfileController do
recent_artwork = recent_artwork(conn, tags) recent_artwork = recent_artwork(conn, tags)
recent_comments = recent_comments =
Comment Elasticsearch.search_definition(
|> Elasticsearch.search_definition( Comment,
%{ %{
query: %{ query: %{
bool: %{ bool: %{
@ -97,17 +94,10 @@ defmodule PhilomenaWeb.ProfileController do
}, },
%{page_size: 3} %{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 = recent_posts =
Post Elasticsearch.search_definition(
|> Elasticsearch.search_definition( Post,
%{ %{
query: %{ query: %{
bool: %{ bool: %{
@ -123,8 +113,26 @@ defmodule PhilomenaWeb.ProfileController do
}, },
%{page_size: 6} %{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) about_me = TextileRenderer.render_one(%{body: user.description || ""}, conn)
@ -214,7 +222,9 @@ defmodule PhilomenaWeb.ProfileController do
defp tags([]), do: [] defp tags([]), do: []
defp tags(links), do: Enum.map(links, & &1.tag) |> Enum.reject(&is_nil/1) 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 defp recent_artwork(conn, tags) do
{images, _tags} = {images, _tags} =
@ -224,7 +234,7 @@ defmodule PhilomenaWeb.ProfileController do
pagination: %{page_number: 1, page_size: 4} pagination: %{page_number: 1, page_size: 4}
) )
Elasticsearch.search_records(images, preload(Image, :tags)) images
end end
defp set_admin_metadata(conn, _opts) do defp set_admin_metadata(conn, _opts) do

View file

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

View file

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