Как сделать мульти сортировку в Elastic Search - PullRequest
0 голосов
/ 05 апреля 2019

Мне нужно разделить результаты поиска на две части. 1 с теми товарами, в которых число> 0 сортирует их по цене и снимает первым. 2 товара, количество которых = 0, отсортировать по цене и показать в конце после тех товаров, которые есть в наличии. Главное, чтобы в первой группе товаров (чье количество> 0) не было товаров из второй группы (чье количество = 0) Что, к сожалению, происходит, когда я сортирую по двум условиям

Использование PHP 7.1 и упругий поиск 6.6.0

Небольшой пример, есть таблица товаров

id | site_price | count
 1 | 10         |  0
 2 | 5          |  5
 3 | 15         |  2
 4 | 20         | 10
 5 | 15         |  0

Мне нужно отсортировать сначала по количеству, а затем по цене (без потери первой сортировки). Первый сорт: ('count'=>'desc'). Второй сорт: ('site_price'=>'asc'). Должен получить такой результат:

id | site_price | count
 2 |  5         | 10
 3 | 15         |  5
 4 | 20         |  2
 1 | 10         |  0
 5 | 15         |  0


$this->params['body'] = array(
    'from' => ($filters['page'] - 1) * 15,
    'size' => 15,
    'query' => array(
        'bool' => array(
            'must' => array(
                "query_string" => array(
                    'query' => "*" . $filters['text'] . "*",
                )
            ),
        )
    ),
    'sort' => array(
        array("shops_count" => "desc"),
        array("site_price" => "asc")
    )
);
$result = $this->client->search($this->params);

Ответы [ 2 ]

0 голосов
/ 11 апреля 2019

Похоже, что вы хотите добиться поведения, аналогичного UNION в SQL, поскольку сначала вы хотите разделить результирующий набор на 2 группы, отсортировать каждую группу, а затем присоединить одну группу за другой.

Есть несколько способов сделать это.

1) Выполнив 2 запроса

Как и в этот ответ , предлагается сделать 2 запроса:

POST /orders/_search
{
    "query": {
        "range": {
            "count": {
                "gt": 0
            }
        }
    },
    "sort" : [
        {"site_price": "asc"},
    ]
}

POST /orders/_search
{
    "query": {
        "range": {
            "count": {
                "gte": 0,
                "lte": 0
            }
        }
    },
    "sort" : [
        {"site_price": "asc"},
    ]
}

И затем присоединение к ним на стороне клиента.Есть также способ сделать это полностью на стороне Elasticsearch.

2) Используя сортировку скриптов

Мы можем использовать сортировку на основе скриптов и сортировать сначала по доступности(count > 0), затем по цене:

POST /orders/_search
{
    "sort" : [
        {
            "_script" : {
                "type" : "number",
                "script" : {
                    "lang": "painless",
                    "source": "if (doc['count'].value > 0) { 1 } else { 0 } "
                },
                "order" : "desc"
            }
        },
        {"site_price": "asc"}
    ]
}

Однако выполнение сценариев всегда приводит к снижению производительности.Решение № 1 является более надежным, хотя и выполняет 2 запроса.

Вот еще одно решение, которое использует один запрос и не использует дорогостоящие сценарии.

3) Добавление нового поля - для сортировки

Если мы добавим специальное поле "available", нам не нужно будет использовать сортировку скриптов.

Документы могут выглядеть следующим образом:

doc1 = {
    "id": 1,
    "site_price": 10,
    "count": 0,
    "available": 0
}
doc2 = {
    "id": 2,
    "site_price": 5,
    "count": 5,
    "available": 1
}

Тогда сортировка будетвыглядят так:

POST /orders/_search
{
    "sort" : [
        {"available": "desc"},
        {"site_price": "asc"}
    ]
}

Это общий шаблон, называемый денормализация , который оказывается полезным при настройке на лучшую производительность.

Надеюсь, это поможет!

0 голосов
/ 10 апреля 2019

@ Николай, спасибо за помощь. К сожалению, это не помогло. Я попытался переписать запрос - но результат тот же. Вот пример: убрано слишком много осталось только поиск и сортировка

enter code here
$this->params['body'] = array(
        'from' => ($filters['page'] - 1) * 15,
        'size' => 15,
        'query' => array(
            'bool' => array(
                'must' => array(
                    "query_string" => array(
                        'query' => "*" . $filters['text'] . "*",
                    )
                ),
            )
        ),
        'sort' => array(
            array("shops_count" => "desc"),
            array("site_price" => "asc")
        )
    );
        $result = $this->client->search($this->params);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...