Два объекта: сбор и продукт. Коллекция является родителем продукта.
Мне нужно искать по условиям продукта и показывать коллекции по 4 товарам каждый.
Коллекции и продукты могут быть частично сопоставлены, но лучше всего соответствовать первым. Если совпадение не заполнено, некоторые термины имеют приоритет.
Пример: поиск "цвет: красный" и "материал: камень" должен сначала отображать красные камни, а другой красный - следующий (это касается соответствия коллекции и соответствия продукта).
Итак, все это разрешено ниже:
{
"query": {
"has_child": {
"type": "products",
"query": {
"bool": {
"should": [
{
"constant_score": {
"filter": {
"match_all": {}
},
"boost": 1
}
},
{
"constant_score": {
"filter": {
"terms": { "_name": "colors", "colors": [5] }
},
"boost": 1.2
}
},
{
"constant_score": {
"filter": {
"terms": { "_name": "materials", "productTypes": [6] }
},
"boost": 1
}
}
]
}
},
"score_mode": "max",
"inner_hits": {
"size": 4,
"sort": [
"_score"
]
}
}
},
"sort": [
"_score"
]
}
Хорошо, теперь проблема.
Нужно сортировать по цене. Как ASC, как DESC. Цена - это свойство продукта.
Нужно сортировать по цене совпадающих продуктов, поэтому не может переместить цену в коллекцию. Необходимо сортировать по цене как коллекцию как продукты. Коллекции отсортированы по минимальной (или максимальной) цене совпадающих продуктов.
Нужно сортировать по цене только 100% сопоставимых продуктов (ну, частично совпадающие могут быть отсортированы тоже, но после). Я имею в виду, сортировка должна быть как ORDER BY _score, цена
Пример, который я хочу получить, сортировка по цене asc, [nn] означает частично согласованный продукт:
Collection1
100 - 200 - 800 - [99]
Collection2
300 - 500 - [10] - [20]
Collection3
400 - 450 - 500 - [100]
Я обнаружил, что сортировка по дочернему не поддерживается. И предложение пересчитать счет. Но я использую счет для сортировки по совпадению. Моя попытка была
{
"query": {
"has_child": {
"type": "products",
"query": {
"function_score": {
"query": {
"bool": {
"should": [
... same query as above ...
]
}
},
"functions": [
{
"script_score": {
"script": "ceil(_score * 100) * 100000 + (99999 - doc['price'].value/100)",
"lang": "expression"
}
}
]
}
},
"score_mode": "max",
"inner_hits": {
"size": 4,
"sort": [
"_score",
{
"price": {
"order": "desc"
}
}
]
}
}
},
"sort": [
"_score"
]
}
Но я действительно сбиваю с толку результаты, которые я вижу в ответ. Запрос на помощь:) Или, может быть, отбросьте это и создайте вложенный индекс?
UPD: найдено, что было ошибкой со счетом. По умолчанию эластичный комбинированный балл и результат script_score. Так что оценка была ceil(_score * 100) * 100000 + (99999 - doc['price'].value/100) * _score
- это может сломать идею, но легко исправить с помощью параметра boost_mode
function_score
. Запрос результата:
{
"query": {
"has_child": {
"type": "products",
"query": {
"function_score": {
"query": {
"bool": {
"should": [
... same query as above ...
]
}
},
"functions": [
{
"script_score": {
"script": "ceil((log10(_score)+10) * 100) * 100000 + (99999 - doc['price'].value)",
"lang": "expression"
}
}
],
"boost_mode": "replace"
}
},
"score_mode": "max",
"inner_hits": {
"size": 4,
"sort": [
"_score",
{
"price": {
"order": "desc"
}
}
]
}
}
},
"sort": [
"_score"
]
}
boost_mode == 'replace
означает "результат использования функции как результат". Кроме того, используется log10, чтобы узнать, сколько цифр в _score.
Для сортировки по цене DESC необходимо изменить формулу на ceil((log10(_score)+10) * 100) * 100000 + (doc['price'].value)
UPD2
Формула ceil((log10(_score)+10) * 100) * 100000 + (99999 - doc['price'].value)
возвращает 100099952
для цены 48
и для цены 50
(boost == 1, queryNorm == 1), поскольку ограничение одиночной точности.
Новая формула ceil((log10(_score)+5) * 100) * 10000 + (9999 - ceil(log10(doc['price'].value) * 1000))
- уменьшено количество цифр для оценки и переключено с цены на lg цены и уменьшено количество цифр. Обратная связь приветствуется.