简体   繁体   English

如何在弹性搜索中进行多重排序

[英]How to do multi sort in Elastic Search

I need to divide my search result into two parts.我需要将我的搜索结果分成两部分。 1 with those goods in which the number> 0 sort them by price and withdraw first. 1 对数量>0 的商品按价格排序,先提货。 2 products whose quantity = 0 sort by price and display at the end, after those products that are in stock. 2个数量=0的产品按价格排序,最后显示在有库存的产品之后。 The main thing is that in the first group of goods (whose quantity> 0) there were no goods from the second group (whose quantity = 0) What unfortunately happens when I sort by two conditions主要是在第一组货物(数量> 0)中没有第二组货物(数量= 0)当我按两个条件排序时不幸发生了什么

Use PHP 7.1 and Elastic Search 6.6.0使用 PHP 7.1 和 Elastic Search 6.6.0

Small example, there is a table of goods小例子,有一张商品表

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

I need to sort first by quantity, and then by price (without losing the first sorting).我需要先按数量排序,然后按价格排序(不丢失第一个排序)。 First sort: ('count'=>'desc') .第一种: ('count'=>'desc') Second sort: ('site_price'=>'asc') .第二类: ('site_price'=>'asc') Should get this result:应该得到这个结果:

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);

@Nikolay, thanks for the help. @Nikolay,感谢您的帮助。 Unfortunately, this did not help.不幸的是,这没有帮助。 I tried rewrote the query - but the result is the same.我尝试重写查询 - 但结果是一样的。 Here is an example: removed too much left only search and sorting这是一个例子:删除了太多只剩下搜索和排序

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);

It looks like that you want to achieve behavior similar to UNION in SQL, since you first want to split the result set into 2 groups, sort each group and then attach one group after another.看起来你想在 SQL 中实现类似于UNION 的行为,因为你首先想将结果集分成 2 组,对每组进行排序,然后一个接一组地附加。

There are a few ways to do it.有几种方法可以做到。

1) By doing 2 queries 1)通过做2个查询

Like in this answer , it is suggested to do 2 queries:就像在这个答案中一样,建议做 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"},
    ]
}

And then joining them on the client side.然后在客户端加入他们。 There is also a way to do it completely on the Elasticsearch side.还有一种方法可以在 Elasticsearch 端完全做到这一点。

2) By using script sorting 2) 通过使用脚本排序

We can use script based sorting and sort first on the availability ( count > 0 ), then by price:我们可以使用基于脚本的排序,首先根据可用性( 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"}
    ]
}

However, scripting always has performance overhead.然而,脚本总是有性能开销。 Solution #1 is more robust, although it performs 2 queries.解决方案#1 更健壮,尽管它执行了 2 个查询。

Here is another solution that uses single query and does not use expensive scripting.这是另一种使用单一查询且不使用昂贵脚本的解决方案。

3) Adding new field - for sorting 3) 添加新字段 - 用于排序

If we add a special field, "available" , we will not need to use script sorting.如果我们添加一个特殊字段"available" ,我们将不需要使用脚本排序。

The documents might look like this:文档可能如下所示:

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

Then the sorting will look like this:然后排序将如下所示:

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

This is a common pattern called denormalization which proves useful when tuning for best performance.这是一种称为非规范化的常见模式,在调整以获得最佳性能时证明是有用的。

Hope that helps!希望有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM