somewhat fix random ordering

This commit is contained in:
byte[] 2020-05-28 19:43:17 -04:00
parent 76b6297a8a
commit 64428907f5
8 changed files with 50 additions and 76 deletions

View file

@ -31,7 +31,7 @@ defmodule PhilomenaWeb.ActivityController do
ImageLoader.query(
conn,
%{range: %{first_seen_at: %{gt: "now-3d"}}},
sorts: [%{wilson_score: :desc}, %{first_seen_at: :desc}],
sorts: &%{query: &1, sorts: [%{wilson_score: :desc}, %{first_seen_at: :desc}]},
pagination: %{page_number: :rand.uniform(6), page_size: 4}
)

View file

@ -2,7 +2,6 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
use PhilomenaWeb, :controller
alias PhilomenaWeb.ImageLoader
alias PhilomenaWeb.ImageSorter
alias Philomena.Interactions
alias Philomena.Images.Image
import Ecto.Query
@ -10,14 +9,8 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
def index(conn, params) do
queryable = Image |> preload([:tags, :user, :intensity])
user = conn.assigns.current_user
sort = ImageSorter.parse_sort(params)
case ImageLoader.search_string(conn, params["q"],
sorts: sort.sorts,
queries: sort.queries,
constant_score: sort.constant_score,
queryable: queryable
) do
case ImageLoader.search_string(conn, params["q"], queryable: queryable) do
{:ok, {images, _tags}} ->
interactions = Interactions.user_interactions(images, user)

View file

@ -3,7 +3,6 @@ defmodule PhilomenaWeb.GalleryController do
alias PhilomenaWeb.ImageLoader
alias PhilomenaWeb.NotificationCountPlug
alias PhilomenaWeb.ImageSorter
alias Philomena.Elasticsearch
alias Philomena.Interactions
alias Philomena.Galleries.Gallery
@ -52,12 +51,11 @@ defmodule PhilomenaWeb.GalleryController do
"sd" => position_order(gallery)
})
sort = ImageSorter.parse_sort(params)
conn = %{conn | params: params}
{:ok, {images, _tags}} =
ImageLoader.search_string(conn, query, queries: sort.queries, sorts: sort.sorts)
{:ok, {images, _tags}} = ImageLoader.search_string(conn, query)
{gallery_prev, gallery_next} = prev_next_page_images(conn, query, sort)
{gallery_prev, gallery_next} = prev_next_page_images(conn, query)
interactions = Interactions.user_interactions([images, gallery_prev, gallery_next], user)
@ -145,32 +143,26 @@ defmodule PhilomenaWeb.GalleryController do
|> redirect(to: Routes.gallery_path(conn, :index))
end
defp prev_next_page_images(conn, query, sort) do
defp prev_next_page_images(conn, query) do
limit = conn.assigns.image_pagination.page_size
offset = (conn.assigns.image_pagination.page_number - 1) * limit
# Inconsistency: Elasticsearch doesn't allow requesting offsets which are less than 0,
# but it does allow requesting offsets which are beyond the total number of results.
prev_image = gallery_image(offset - 1, conn, query, sort)
next_image = gallery_image(offset + limit, conn, query, sort)
prev_image = gallery_image(offset - 1, conn, query)
next_image = gallery_image(offset + limit, conn, query)
{prev_image, next_image}
end
defp gallery_image(offset, _conn, _query, _sorts) when offset < 0, do: nil
defp gallery_image(offset, _conn, _query) when offset < 0, do: nil
defp gallery_image(offset, conn, query, sort) do
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,
queries: sort.queries,
sorts: sort.sorts
)
ImageLoader.search_string(conn, query, pagination: pagination_params)
case Enum.to_list(image) do
[image] -> image

View file

@ -31,21 +31,22 @@ defmodule PhilomenaWeb.Image.RandomController do
defp query(_user, _), do: %{match_all: %{}}
defp random_image_id(query, filter) do
sort = ImageSorter.parse_sort(%{"sf" => "random"})
%{query: query, sorts: sort} =
ImageSorter.parse_sort(%{"sf" => "random"}, query)
Elasticsearch.search_records(
Image,
%{
query: %{
bool: %{
must: List.flatten([sort.queries, query]),
must: query,
must_not: [
filter,
%{term: %{hidden_from_users: true}}
]
}
},
sort: sort.sorts
sort: sort
},
%{page_size: 1},
Image

View file

@ -2,18 +2,12 @@ defmodule PhilomenaWeb.SearchController do
use PhilomenaWeb, :controller
alias PhilomenaWeb.ImageLoader
alias PhilomenaWeb.ImageSorter
alias Philomena.Interactions
def index(conn, params) do
user = conn.assigns.current_user
sort = ImageSorter.parse_sort(params)
case ImageLoader.search_string(conn, params["q"],
sorts: sort.sorts,
queries: sort.queries,
constant_score: sort.constant_score
) do
case ImageLoader.search_string(conn, params["q"]) do
{:ok, {images, tags}} ->
interactions = Interactions.user_interactions(images, user)

View file

@ -1,4 +1,5 @@
defmodule PhilomenaWeb.ImageLoader do
alias PhilomenaWeb.ImageSorter
alias Philomena.Elasticsearch
alias Philomena.Images.{Image, Query}
alias PhilomenaWeb.TextileRenderer
@ -18,11 +19,9 @@ defmodule PhilomenaWeb.ImageLoader do
end
def query(conn, body, options \\ []) do
sort_queries = Keyword.get(options, :queries, [])
sort_sorts = Keyword.get(options, :sorts, [%{created_at: :desc}])
pagination = Keyword.get(options, :pagination, conn.assigns.image_pagination)
queryable = Keyword.get(options, :queryable, Image |> preload(:tags))
constant_score = Keyword.get(options, :constant_score, true)
sorts = Keyword.get(options, :sorts, &ImageSorter.parse_sort(conn.params, &1))
tags =
body
@ -33,7 +32,8 @@ defmodule PhilomenaWeb.ImageLoader do
user = conn.assigns.current_user
filter = conn.assigns.compiled_filter
filters = create_filters(conn, user, filter)
body = maybe_constant_score(body, constant_score)
%{query: query, sorts: sort} = sorts.(body)
records =
Elasticsearch.search_records(
@ -41,11 +41,11 @@ defmodule PhilomenaWeb.ImageLoader do
%{
query: %{
bool: %{
must: List.flatten([body, sort_queries]),
must: query,
must_not: filters
}
},
sort: sort_sorts
sort: sort
},
pagination,
queryable
@ -95,9 +95,6 @@ defmodule PhilomenaWeb.ImageLoader do
defp maybe_custom_hide(filters, _user, _param),
do: filters
defp maybe_constant_score(body, false), do: body
defp maybe_constant_score(body, _), do: %{bool: %{filter: body}}
# TODO: the search parser should try to optimize queries
defp search_tag_name(%{term: %{"namespaced_tags.name" => tag_name}}), do: [tag_name]
defp search_tag_name(_other_query), do: []

View file

@ -33,10 +33,11 @@ defmodule PhilomenaWeb.ImageNavigator do
|> Map.merge(empty_fields())
|> ElasticsearchIndex.as_json()
sort_data = ImageSorter.parse_sort(params)
%{query: compiled_query, sorts: sort} =
ImageSorter.parse_sort(params, compiled_query)
{sorts, filters} =
sort_data.sorts
sort
|> Enum.map(&extract_filters(&1, image_index, rel))
|> Enum.unzip()
@ -48,7 +49,7 @@ defmodule PhilomenaWeb.ImageNavigator do
%{
query: %{
bool: %{
must: List.flatten([compiled_query, sort_data.queries, filters]),
must: List.flatten([compiled_query, filters]),
must_not: [
compiled_filter,
%{term: %{hidden_from_users: true}},

View file

@ -16,42 +16,42 @@ defmodule PhilomenaWeb.ImageSorter do
wilson_score
)
def parse_sort(params) do
def parse_sort(params, query) do
sd = parse_sd(params)
parse_sf(params, sd)
parse_sf(params, sd, query)
end
defp parse_sd(%{"sd" => sd}) when sd in ~W(asc desc), do: sd
defp parse_sd(_params), do: "desc"
defp parse_sf(%{"sf" => sf}, sd) when sf in @allowed_fields do
%{queries: [], sorts: [%{sf => sd}], constant_score: true}
defp parse_sf(%{"sf" => sf}, sd, query) when sf in @allowed_fields do
%{query: query, sorts: [%{sf => sd}]}
end
defp parse_sf(%{"sf" => "_score"}, sd) do
%{queries: [], sorts: [%{"_score" => sd}], constant_score: false}
defp parse_sf(%{"sf" => "_score"}, sd, query) do
%{query: query, sorts: [%{"_score" => sd}]}
end
defp parse_sf(%{"sf" => "random"}, sd) do
random_query(:rand.uniform(4_294_967_296), sd)
defp parse_sf(%{"sf" => "random"}, sd, query) do
random_query(:rand.uniform(4_294_967_296), sd, query)
end
defp parse_sf(%{"sf" => <<"random:", seed::binary>>}, sd) do
defp parse_sf(%{"sf" => <<"random:", seed::binary>>}, sd, query) do
case Integer.parse(seed) do
{seed, _rest} ->
random_query(seed, sd)
random_query(seed, sd, query)
_ ->
random_query(:rand.uniform(4_294_967_296), sd)
random_query(:rand.uniform(4_294_967_296), sd, query)
end
end
defp parse_sf(%{"sf" => <<"gallery_id:", gallery::binary>>}, sd) do
defp parse_sf(%{"sf" => <<"gallery_id:", gallery::binary>>}, sd, query) do
case Integer.parse(gallery) do
{gallery, _rest} ->
%{
queries: [],
query: query,
sorts: [
%{
"galleries.position" => %{
@ -65,31 +65,27 @@ defmodule PhilomenaWeb.ImageSorter do
}
}
],
constant_score: true
}
_ ->
%{queries: [%{match_none: %{}}], sorts: [], constant_score: true}
%{query: query, sorts: []}
end
end
defp parse_sf(_params, sd) do
%{queries: [], sorts: [%{"created_at" => sd}], constant_score: true}
defp parse_sf(_params, sd, query) do
%{query: query, sorts: [%{"created_at" => sd}]}
end
defp random_query(seed, sd) do
%{
queries: [
defp random_query(seed, sd, query) do
%{
query: %{
function_score: %{
query: %{match_all: %{}},
query: query,
random_score: %{seed: seed, field: :id},
boost_mode: :replace
}
}
],
sorts: [%{"_score" => sd}],
constant_score: true
},
sorts: [%{"_score" => sd}]
}
end
end