mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-30 14:57:59 +01:00
somewhat fix random ordering
This commit is contained in:
parent
76b6297a8a
commit
64428907f5
8 changed files with 50 additions and 76 deletions
|
@ -31,7 +31,7 @@ defmodule PhilomenaWeb.ActivityController do
|
||||||
ImageLoader.query(
|
ImageLoader.query(
|
||||||
conn,
|
conn,
|
||||||
%{range: %{first_seen_at: %{gt: "now-3d"}}},
|
%{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}
|
pagination: %{page_number: :rand.uniform(6), page_size: 4}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias PhilomenaWeb.ImageLoader
|
alias PhilomenaWeb.ImageLoader
|
||||||
alias PhilomenaWeb.ImageSorter
|
|
||||||
alias Philomena.Interactions
|
alias Philomena.Interactions
|
||||||
alias Philomena.Images.Image
|
alias Philomena.Images.Image
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
@ -10,14 +9,8 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
|
||||||
def index(conn, params) do
|
def index(conn, params) do
|
||||||
queryable = Image |> preload([:tags, :user, :intensity])
|
queryable = Image |> preload([:tags, :user, :intensity])
|
||||||
user = conn.assigns.current_user
|
user = conn.assigns.current_user
|
||||||
sort = ImageSorter.parse_sort(params)
|
|
||||||
|
|
||||||
case ImageLoader.search_string(conn, params["q"],
|
case ImageLoader.search_string(conn, params["q"], queryable: queryable) do
|
||||||
sorts: sort.sorts,
|
|
||||||
queries: sort.queries,
|
|
||||||
constant_score: sort.constant_score,
|
|
||||||
queryable: queryable
|
|
||||||
) do
|
|
||||||
{:ok, {images, _tags}} ->
|
{:ok, {images, _tags}} ->
|
||||||
interactions = Interactions.user_interactions(images, user)
|
interactions = Interactions.user_interactions(images, user)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ defmodule PhilomenaWeb.GalleryController do
|
||||||
|
|
||||||
alias PhilomenaWeb.ImageLoader
|
alias PhilomenaWeb.ImageLoader
|
||||||
alias PhilomenaWeb.NotificationCountPlug
|
alias PhilomenaWeb.NotificationCountPlug
|
||||||
alias PhilomenaWeb.ImageSorter
|
|
||||||
alias Philomena.Elasticsearch
|
alias Philomena.Elasticsearch
|
||||||
alias Philomena.Interactions
|
alias Philomena.Interactions
|
||||||
alias Philomena.Galleries.Gallery
|
alias Philomena.Galleries.Gallery
|
||||||
|
@ -52,12 +51,11 @@ defmodule PhilomenaWeb.GalleryController do
|
||||||
"sd" => position_order(gallery)
|
"sd" => position_order(gallery)
|
||||||
})
|
})
|
||||||
|
|
||||||
sort = ImageSorter.parse_sort(params)
|
conn = %{conn | params: params}
|
||||||
|
|
||||||
{:ok, {images, _tags}} =
|
{:ok, {images, _tags}} = ImageLoader.search_string(conn, query)
|
||||||
ImageLoader.search_string(conn, query, queries: sort.queries, sorts: sort.sorts)
|
|
||||||
|
|
||||||
{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)
|
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))
|
|> redirect(to: Routes.gallery_path(conn, :index))
|
||||||
end
|
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
|
limit = conn.assigns.image_pagination.page_size
|
||||||
offset = (conn.assigns.image_pagination.page_number - 1) * limit
|
offset = (conn.assigns.image_pagination.page_number - 1) * limit
|
||||||
|
|
||||||
# Inconsistency: Elasticsearch doesn't allow requesting offsets which are less than 0,
|
# 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.
|
# but it does allow requesting offsets which are beyond the total number of results.
|
||||||
|
|
||||||
prev_image = gallery_image(offset - 1, conn, query, sort)
|
prev_image = gallery_image(offset - 1, conn, query)
|
||||||
next_image = gallery_image(offset + limit, conn, query, sort)
|
next_image = gallery_image(offset + limit, conn, query)
|
||||||
|
|
||||||
{prev_image, next_image}
|
{prev_image, next_image}
|
||||||
end
|
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}
|
pagination_params = %{page_number: offset + 1, page_size: 1}
|
||||||
|
|
||||||
{:ok, {image, _tags}} =
|
{:ok, {image, _tags}} =
|
||||||
ImageLoader.search_string(
|
ImageLoader.search_string(conn, query, pagination: pagination_params)
|
||||||
conn,
|
|
||||||
query,
|
|
||||||
pagination: pagination_params,
|
|
||||||
queries: sort.queries,
|
|
||||||
sorts: sort.sorts
|
|
||||||
)
|
|
||||||
|
|
||||||
case Enum.to_list(image) do
|
case Enum.to_list(image) do
|
||||||
[image] -> image
|
[image] -> image
|
||||||
|
|
|
@ -31,21 +31,22 @@ defmodule PhilomenaWeb.Image.RandomController do
|
||||||
defp query(_user, _), do: %{match_all: %{}}
|
defp query(_user, _), do: %{match_all: %{}}
|
||||||
|
|
||||||
defp random_image_id(query, filter) do
|
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(
|
Elasticsearch.search_records(
|
||||||
Image,
|
Image,
|
||||||
%{
|
%{
|
||||||
query: %{
|
query: %{
|
||||||
bool: %{
|
bool: %{
|
||||||
must: List.flatten([sort.queries, query]),
|
must: query,
|
||||||
must_not: [
|
must_not: [
|
||||||
filter,
|
filter,
|
||||||
%{term: %{hidden_from_users: true}}
|
%{term: %{hidden_from_users: true}}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sort: sort.sorts
|
sort: sort
|
||||||
},
|
},
|
||||||
%{page_size: 1},
|
%{page_size: 1},
|
||||||
Image
|
Image
|
||||||
|
|
|
@ -2,18 +2,12 @@ defmodule PhilomenaWeb.SearchController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias PhilomenaWeb.ImageLoader
|
alias PhilomenaWeb.ImageLoader
|
||||||
alias PhilomenaWeb.ImageSorter
|
|
||||||
alias Philomena.Interactions
|
alias Philomena.Interactions
|
||||||
|
|
||||||
def index(conn, params) do
|
def index(conn, params) do
|
||||||
user = conn.assigns.current_user
|
user = conn.assigns.current_user
|
||||||
sort = ImageSorter.parse_sort(params)
|
|
||||||
|
|
||||||
case ImageLoader.search_string(conn, params["q"],
|
case ImageLoader.search_string(conn, params["q"]) do
|
||||||
sorts: sort.sorts,
|
|
||||||
queries: sort.queries,
|
|
||||||
constant_score: sort.constant_score
|
|
||||||
) do
|
|
||||||
{:ok, {images, tags}} ->
|
{:ok, {images, tags}} ->
|
||||||
interactions = Interactions.user_interactions(images, user)
|
interactions = Interactions.user_interactions(images, user)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
defmodule PhilomenaWeb.ImageLoader do
|
defmodule PhilomenaWeb.ImageLoader do
|
||||||
|
alias PhilomenaWeb.ImageSorter
|
||||||
alias Philomena.Elasticsearch
|
alias Philomena.Elasticsearch
|
||||||
alias Philomena.Images.{Image, Query}
|
alias Philomena.Images.{Image, Query}
|
||||||
alias PhilomenaWeb.TextileRenderer
|
alias PhilomenaWeb.TextileRenderer
|
||||||
|
@ -18,11 +19,9 @@ defmodule PhilomenaWeb.ImageLoader do
|
||||||
end
|
end
|
||||||
|
|
||||||
def query(conn, body, options \\ []) do
|
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)
|
pagination = Keyword.get(options, :pagination, conn.assigns.image_pagination)
|
||||||
queryable = Keyword.get(options, :queryable, Image |> preload(:tags))
|
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 =
|
tags =
|
||||||
body
|
body
|
||||||
|
@ -33,7 +32,8 @@ defmodule PhilomenaWeb.ImageLoader do
|
||||||
user = conn.assigns.current_user
|
user = conn.assigns.current_user
|
||||||
filter = conn.assigns.compiled_filter
|
filter = conn.assigns.compiled_filter
|
||||||
filters = create_filters(conn, user, filter)
|
filters = create_filters(conn, user, filter)
|
||||||
body = maybe_constant_score(body, constant_score)
|
|
||||||
|
%{query: query, sorts: sort} = sorts.(body)
|
||||||
|
|
||||||
records =
|
records =
|
||||||
Elasticsearch.search_records(
|
Elasticsearch.search_records(
|
||||||
|
@ -41,11 +41,11 @@ defmodule PhilomenaWeb.ImageLoader do
|
||||||
%{
|
%{
|
||||||
query: %{
|
query: %{
|
||||||
bool: %{
|
bool: %{
|
||||||
must: List.flatten([body, sort_queries]),
|
must: query,
|
||||||
must_not: filters
|
must_not: filters
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sort: sort_sorts
|
sort: sort
|
||||||
},
|
},
|
||||||
pagination,
|
pagination,
|
||||||
queryable
|
queryable
|
||||||
|
@ -95,9 +95,6 @@ defmodule PhilomenaWeb.ImageLoader do
|
||||||
defp maybe_custom_hide(filters, _user, _param),
|
defp maybe_custom_hide(filters, _user, _param),
|
||||||
do: filters
|
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
|
# 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(%{term: %{"namespaced_tags.name" => tag_name}}), do: [tag_name]
|
||||||
defp search_tag_name(_other_query), do: []
|
defp search_tag_name(_other_query), do: []
|
||||||
|
|
|
@ -33,10 +33,11 @@ defmodule PhilomenaWeb.ImageNavigator do
|
||||||
|> Map.merge(empty_fields())
|
|> Map.merge(empty_fields())
|
||||||
|> ElasticsearchIndex.as_json()
|
|> ElasticsearchIndex.as_json()
|
||||||
|
|
||||||
sort_data = ImageSorter.parse_sort(params)
|
%{query: compiled_query, sorts: sort} =
|
||||||
|
ImageSorter.parse_sort(params, compiled_query)
|
||||||
|
|
||||||
{sorts, filters} =
|
{sorts, filters} =
|
||||||
sort_data.sorts
|
sort
|
||||||
|> Enum.map(&extract_filters(&1, image_index, rel))
|
|> Enum.map(&extract_filters(&1, image_index, rel))
|
||||||
|> Enum.unzip()
|
|> Enum.unzip()
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ defmodule PhilomenaWeb.ImageNavigator do
|
||||||
%{
|
%{
|
||||||
query: %{
|
query: %{
|
||||||
bool: %{
|
bool: %{
|
||||||
must: List.flatten([compiled_query, sort_data.queries, filters]),
|
must: List.flatten([compiled_query, filters]),
|
||||||
must_not: [
|
must_not: [
|
||||||
compiled_filter,
|
compiled_filter,
|
||||||
%{term: %{hidden_from_users: true}},
|
%{term: %{hidden_from_users: true}},
|
||||||
|
|
|
@ -16,42 +16,42 @@ defmodule PhilomenaWeb.ImageSorter do
|
||||||
wilson_score
|
wilson_score
|
||||||
)
|
)
|
||||||
|
|
||||||
def parse_sort(params) do
|
def parse_sort(params, query) do
|
||||||
sd = parse_sd(params)
|
sd = parse_sd(params)
|
||||||
|
|
||||||
parse_sf(params, sd)
|
parse_sf(params, sd, query)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_sd(%{"sd" => sd}) when sd in ~W(asc desc), do: sd
|
defp parse_sd(%{"sd" => sd}) when sd in ~W(asc desc), do: sd
|
||||||
defp parse_sd(_params), do: "desc"
|
defp parse_sd(_params), do: "desc"
|
||||||
|
|
||||||
defp parse_sf(%{"sf" => sf}, sd) when sf in @allowed_fields do
|
defp parse_sf(%{"sf" => sf}, sd, query) when sf in @allowed_fields do
|
||||||
%{queries: [], sorts: [%{sf => sd}], constant_score: true}
|
%{query: query, sorts: [%{sf => sd}]}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_sf(%{"sf" => "_score"}, sd) do
|
defp parse_sf(%{"sf" => "_score"}, sd, query) do
|
||||||
%{queries: [], sorts: [%{"_score" => sd}], constant_score: false}
|
%{query: query, sorts: [%{"_score" => sd}]}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_sf(%{"sf" => "random"}, sd) do
|
defp parse_sf(%{"sf" => "random"}, sd, query) do
|
||||||
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" => <<"random:", seed::binary>>}, sd) do
|
defp parse_sf(%{"sf" => <<"random:", seed::binary>>}, sd, query) do
|
||||||
case Integer.parse(seed) do
|
case Integer.parse(seed) do
|
||||||
{seed, _rest} ->
|
{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
|
||||||
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
|
case Integer.parse(gallery) do
|
||||||
{gallery, _rest} ->
|
{gallery, _rest} ->
|
||||||
%{
|
%{
|
||||||
queries: [],
|
query: query,
|
||||||
sorts: [
|
sorts: [
|
||||||
%{
|
%{
|
||||||
"galleries.position" => %{
|
"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
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parse_sf(_params, sd) do
|
defp parse_sf(_params, sd, query) do
|
||||||
%{queries: [], sorts: [%{"created_at" => sd}], constant_score: true}
|
%{query: query, sorts: [%{"created_at" => sd}]}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp random_query(seed, sd) do
|
defp random_query(seed, sd, query) do
|
||||||
%{
|
|
||||||
queries: [
|
|
||||||
%{
|
%{
|
||||||
|
query: %{
|
||||||
function_score: %{
|
function_score: %{
|
||||||
query: %{match_all: %{}},
|
query: query,
|
||||||
random_score: %{seed: seed, field: :id},
|
random_score: %{seed: seed, field: :id},
|
||||||
boost_mode: :replace
|
boost_mode: :replace
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
],
|
sorts: [%{"_score" => sd}]
|
||||||
sorts: [%{"_score" => sd}],
|
|
||||||
constant_score: true
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue