【问题标题】:Conditional ElasticSearch sorting by different fields if in range如果在范围内,则按不同字段进行条件 ElasticSearch 排序
【发布时间】:2018-10-26 21:39:27
【问题描述】:

我确实有产品,其中一些产品在特定日期范围内降价。 (简化)示例产品:

{
  "id": 1,
  "price": 2.0,
  "specialPrice": {
    "fromDate": null,
    "tillDate": null,
    "value": 0,
  },
},
{
  "id": 2,
  "price": 4.0,
  "specialPrice": {
    "fromDate": 1540332000,
    "tillDate": 1571781600,
    "value": 2.5,
  },
},
{
  "id": 3,
  "price": 3.0,
  "specialPrice": {
    "fromDate": null,
    "tillDate": null,
    "value": 0,
  },
}

按价格过滤没问题。我可以用一个简单的布尔查询来做到这一点。

但是我还没有找到一个可以为我指明正确方向的 ElasticSearch 脚本示例,尽管它应该很简单,因为你知道语法。

我的伪代码:price = ('now' between specialPrice.fromDate and specialPrice.tillDate) ? specialPrice.value : price

有没有办法将其转换为可用于 ElasticSearch 排序的内容?

进一步澄清:默认情况下,所有产品都已按多个条件排序。用户还可以搜索任何术语并过滤结果,同时还可以选择多个排序参数。例如,项目可以按标签排序,然后按价格排序,这都是非常动态的,之后它仍然会按其他属性(包括 _score)对这些结果进行排序。 所以仅仅改变 _score 是不好的,因为它已经在一个复杂的问题中计算出来,以显示给定搜索词的最佳结果。

这是我当前的脚本,在第一个 params.currentDate 处确实失败了:

"sort": {
"_script": {
  "type": "number",
  "script": {
    "source": "if(doc['specialPrice.tillDate'] > params.currentDate) {params.currentPrice = doc['specialPrice.value']} return params.currentPrice",
    "params": {
      "currentDate": "now",
      "currentPrice": "doc['price']"
    }
  }
}

现在如何运作: 一个问题是一些属性的嵌套。 所以我的步骤之一是将他们的内容复制到产品的新字段中(我对此并不满意,但无论如何)。 因此,在我的映射中,我为产品创建了新属性(specialFrom、specialTill、specialValue),并在我的 specialPrice“copy_to”属性中为相应的字段提供了新的属性名称。 该部分采用 php 数组语法,因为我使用的是 ruflin/elastica:

            'specialPrice' => [
                'type' => 'nested',
                'properties' => [
                    'fromDate' => [
                        'type' => 'date',
                        'format' => 'epoch_second',
                        'copy_to' => 'specialFrom',
                    ],
                    'tillDate' => [
                        'type' => 'date',
                        'format' => 'epoch_second',
                        'copy_to' => 'specialTill',
                    ],
                    'value' => [
                        'type' => 'float',
                        'copy_to' => 'specialValue',
                    ],
                ],
            ],
            'specialFrom' => [
                'type' => 'date',
                'format' => 'epoch_second',
            ],
            'specialTill' => [
                'type' => 'date',
                'format' => 'epoch_second',
            ],
            'specialValue' => [
                'type' => 'float',
            ],

现在我的排序脚本看起来像这样(在我的测试客户端中,仍在努力在 elastica 中实现它):

"sort": {
"_script": {
  "type": "number",
  "script": {
    "lang": "painless",
    "source": "params.param = ((doc['specialTill'].value - new Date().getTime()) > 0 && (new Date().getTime() - doc['specialFrom'].value) > 0) ? doc['specialValue'].value : doc['price'].value; return params.param;",
    "params": {
      "param": 0.0
    }
  }
}

}

我对此不是 100% 满意,因为我有多余的数据和脚本(在脚本中调用 new Date().getTime() 两次),但它确实有效,这是目前最重要的事情 :)

【问题讨论】:

    标签: sorting elasticsearch


    【解决方案1】:

    我已更新以下查询,发布您的说明。让我知道这是否有效!

    POST dateindex/_search
    {  
       "query":{  
          "match_all":{  // you can ignore this, I used this to test at my end
    
          }
       },
       "sort":{  
          "_script":{  
             "type":"number",
             "script":{  
                "lang":"painless",
                "inline":" params.param = ((doc['specialPrice.tillDate'].value - new Date().getTime()) > 0) ? doc['specialPrice.value'].value : doc['price'].value; return params.param;",
                "params":{  
                   "param":0.0
                }
             },
             "order":"asc"
          }
       }
    }
    

    您可以尝试在上述查询中使用source 而不是inline,因为我一直在我的机器上测试ES5.X 版本。

    希望对你有帮助!

    【讨论】:

    • 谢谢,但我不确定这是否真的对我有帮助。我本来期望是这样的:elastic.co/guide/en/elasticsearch/reference/current/… 根据我对您的回答的理解,每次我想按价格排序时,我都必须更新我所有产品的价格。这对我来说似乎不是很有效;)我会继续试验。
    • @Fanmade 澄清一下,您不想更新价格。只想排序,它应该按照您提供的伪代码工作?
    • 没错。如果用户选择按价格排序,ElasticSearch 应该使用当前日期有效的“特价”,否则使用正常价格:)
    • @Fanmade 现在请检查我的答案。我已经更新了另一个解决方案。如果有帮助,请告诉我!
    • 非常感谢您的帮助和耐心等待! :D 根据您更新的脚本,我终于设法使其与我的数据一起使用,并相应地更新了我的答案。
    猜你喜欢
    • 2018-09-19
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2019-07-15
    • 2016-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多