我有以下索引数据
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 7992,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "test_index",
"_id": "33952",
"default_fee": 12,
"custom_dates": [
{
"date": "2023-11-01",
"price": 100
},
{
"date": "2023-11-02",
"price": 50
}
],
"options": [
{
"id": 95,
"cost": 5,
"type": [
"Car"
]
}
]
}
]
}
}
字符串
我已经添加了一个脚本字段作为总计算总运行时如下
{
script_fields: {
total: {
script: {
source: "
DateTimeFormatter formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd');
def from = LocalDate.parse(params.checkin, formatter);
def to = LocalDate.parse(params.checkout, formatter);
def stay = params.total_stay;
def custom_price_dates = [];
if (params['_source']['custom_dates'] != null && !params['_source']['custom_dates'].isEmpty()) {
custom_price_dates = params['_source']['custom_dates'].stream()
.filter(filter_doc -> {
def date = LocalDate.parse(filter_doc.start_date, formatter);
return !date.isBefore(from) && !date.isAfter(to.minusDays(1));
})
.collect(Collectors.toList());
}
def custom_price = custom_price_dates.stream().mapToDouble(custom_doc -> custom_doc.price).sum();
def default_price = stay == custom_price_dates.size() ? 0 : (stay - custom_price_dates.size()) * params['_source']['default_fee'];
def calc_price = default_price + custom_price;
return calc_price;
",
params: {
checkin: Date.current.to_s,
checkout: Date.current.to_s,
total_stay: 2
}
}
}
},
_source: ["*"]
}
型
这将返回脚本字段上的总计。现在我想根据上述总计的范围进行过滤。我如何实现它?我尝试使用脚本查询如下,但它不会通过自定义日期循环,因为它是嵌套类型。
此外,我不能索引总前入住和退房日期是动态的,可能会有自定义的价格在给定的入住和退房日期。请建议。
1条答案
按热度按时间5f0d552i1#
这是可以做到的,但它很复杂。首先,我们需要了解这个搜索是在两个阶段执行的-查询和获取。在查询阶段,每个分片收集前10个点击及其排序键。(默认为_score),在获取阶段,协调节点从所有分片收集这些ID和排序键,从它们中选择前10个,然后要求每个分片返回那里的文档。脚本字段是在获取阶段计算的,因此过滤器无法访问它们。
更糟糕的是,您将自定义日期作为嵌套对象进行索引。在内部,嵌套对象作为单独的对象进行索引,将信息从它们传递到主查询的唯一方法是通过_score。所以,基本上,为了实现你试图用嵌套对象实现的目标,你需要将price编码到_score。为了简化计算,我们需要在嵌套对象中存储价格差而不是实际价格。因此,如果默认价格是12,特价是100,我们需要存储88。
然后我们可以找到所有与我们的日期范围匹配的嵌套对象:
字符串
然后我们可以将其 Package 到脚本score中,它将score替换为price:
型
然后我们可以使用另一个
script_score
来计算默认价格:型
然后我们可以把它们合并组合成两个should子句来增加分数。
所以,现在我们让_score等于分配给每条记录的价格。最后一步是通过_score过滤记录,这可以通过另一个
script_score
和min_score
参数来完成:型
如果我们把这些放在一起,我们会得到这样的东西:
型
这个有用吗是的,在一定程度上。在elasticsarch分数是非负的32位浮点数。所以,那里没有太多的精度,如果你的调整是负的,它会使事情变得更加复杂。
我会在生产环境中做这样的事情吗?我不会。我会做的是将特殊日期以某种易于解析的格式存储在主文档中,以便我可以在查询阶段访问它。然后在
script
查询和script_field
中从主文档解析它。是的,您需要解析两次,但正如我在回答的开头提到的,我们对此无能为力,因为这些操作是在不同的阶段执行的。最简单的方法是将其存储为多值关键字字段。基本上,你可以这样做:型