如何在Elastic Search中进行多重排序

时间:2019-04-05 13:46:52

标签: php laravel sorting

我需要将搜索结果分为两部分。 1,其中> 0的商品按价格排序,然后先提取。 2个数量= 0的产品按价格排序,并在库存的那些产品之后显示。最主要的是,在第一类商品(数量> 0)中没有第二类商品(数量= 0),不幸的是,当我根据两个条件进行排序时

使用PHP 7.1 和Elastic Search 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 :(得分:0)

@Nikolay,感谢您的帮助。 不幸的是,这没有帮助。我尝试重写查询-但结果是相同的。这是一个例子:删除过多,只剩下搜索和排序

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

答案 1 :(得分:0)

您似乎想要实现与SQL中的UNION类似的行为,因为您首先要将结果集分成2组,对每个组进行排序,然后将一个组接一个接一个。

有几种方法可以实现。

1)通过执行2个查询

this answer类似,建议执行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)通过使用脚本排序

我们可以使用script based sorting并首先对可用性(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"}
    ]
}

这是一个称为denormalization的通用模式,在调整最佳性能时证明是有用的。

希望有帮助!