我正在尝试按字段提升查询,然后按日期对它们进行排序:
multiMatchQuery.fields(columnSortOrder());
searchSourceBuilder.trackScores(true);
searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
searchSourceBuilder.sort("updated_time",SortOrder.DESC);
当我执行它时,按列返回结果提升。我想通过两个最高归档订单的组合 按日期排序
提升订单
Field_A^3
Field_B^2
Field_C^1
示例数据:
{
"_source": {
"updated_time": "2020-01-04T01:00:06.870000Z",
"field_A": "Slovakia beyond",
"filed_B": "The properties in Slovakia are beyound...",
"Field_C": "Once you fix the relevance then sorting should work correctly."
}
{
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "**beyond** filed_A",
"filed_B": "The properties in Japan is high",
"Field_C": "Test description for filed_A"
}
{
"_score": 2.56865,
"_source": {
"updated_time": "2020-01-04T01:00:06.870000Z",
"field_A": "Test filed_B",
"filed_B": "**beyond** is search term in filed_B",
"Field_C": "Test description for filed_B"
}
{
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "Test filed_B",
"filed_B": "**beyond** is search term in filed_B Test for Feb",
"Field_C": "Test description for filed_B test for Feb"
}
{
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "Search Term filed_C",
"filed_B": " is the search term for lowest column",
"Field_C": "**beyond** Test description for filed_C "
}
假设搜索词为"超出" 如果在 [field_A,field_B,filed_C] 中找到搜索词 预期结果为:
[第一优先级Field_A按日期排序]
- 2020年1月之后的斯洛伐克
- 2020年2月filed_A日之后
[第二优先级Field_B按日期排序]
- beyond是2020年1月filed_B日的搜索词
- 超越是2020年2月filed_B测试中的搜索词
[第三优先级Field_C按日期排序]
- Beyond 2020 年 2 月 filed_C 日的测试说明
可能是因为这个
对字段进行排序时,不会计算分数。通过将track_scores设置为 true,仍会计算和跟踪分数。
因此,请为您的查询启用track_scores
。
爪哇接口
使用带有参数化变体的曲目分数。
和
当我尝试使用示例数据时,还需要按分数排序。
{
"_score": {
"order": "desc"
}
}
将其添加为第一个排序,然后按 DESC 日期排序。它的工作原理如下。
如果搜索词是多个字段 [field1, field2, field3
] 的一部分,则将计算组合分数。
有几种方法可以做到这一点。使用多个查询(使用多搜索 API(的方法更简洁,对单个查询(使用function_score
查询(使用更复杂的方法。让我解释一下如何。
使用_msearch
的更清洁的方法
简单地说,_msearch
允许发出一个包含多个Elasticsearch查询的HTTP请求。我建议将初始查询拆分为多个查询并按日期排序。这种方法会更简单,因为正如我稍后将向您展示的那样,将其放入一个查询中将需要修改评分,这不是一件容易的事情。
您也可以在不使用_msearch
的情况下提出多个请求,无论您认为合适。
为什么其他方法不起作用?
您已经知道通过将某些字段提升到其他字段之上来简化分数优化,如以下示例multi_match
查询所示:
POST /myscores/_search
{
"query": {
"multi_match": {
"query": "beyond",
"fields": ["field_A^3", "filed_B^2", "Field_C^1"]
}
}
}
如果匹配field_A
,这将简单地取比赛乘以 3 的分数,如果匹配filed_B
则乘以 2,依此类推。
现在,分数只是一个真正的正数,它需要表示我们应该在匹配结果列表中放置特定文档的位置。
正如您已经尝试过的,如果您要求 Elasticsearch 使用updated_time
作为排序度量,它将忽略匹配中的分数,这是不希望的。
吉布斯同事的建议似乎也行不通,因为使用按_score
排序,然后按updated_time
排序(反之亦然(忽略了一个或另一个选项。
有没有办法将_score
和updated_time
结合起来?
有,让我们尝试使用function_score
:
POST /myscores/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "beyond",
"fields": [
"field_A^3",
"filed_B^2",
"Field_C"
]
}
},
"score_mode": "max",
"boost_mode": "multiply", <=== 2
"field_value_factor": { <=== 1
"field": "updated_time",
"factor": 0.00000000001,
"missing": 1
}
}
}
}
function_score
允许您微调查询的分数。
我们从上一节中获取我们已经熟悉multi_match
查询,并尝试对其进行修改。
首先,我们知道我们希望它考虑到updated_time
.我们使用field_value_factor
作为函数来修改分数(上面查询中的第 1 点(。
现在,我们告诉它通过将boost_mode
设置为multiply
来乘以updated_time
的值和查询的分数(第 2 点(。
执行此查询将生成如下所示的内容:
"hits": [
{
...
"_score": 43.121338,
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "**beyond** filed_A",
"filed_B": "The properties in Japan is high",
"Field_C": "Test description for filed_A"
}
},
{
...
"_score": 43.048275,
"_source": {
"updated_time": "2020-01-04T01:00:06.870000Z",
"field_A": "Slovakia beyond",
"filed_B": "The properties in Slovakia are beyound...",
"Field_C": "Once you fix the relevance then sorting should work correctly."
}
},
{
...
"_score": 29.028637,
"_source": {
"updated_time": "2020-01-04T01:00:06.870000Z",
"field_A": "Test filed_B",
"filed_B": "**beyond** is search term in filed_B",
"Field_C": "Test description for filed_B"
}
},
{
...
"_score": 24.44329,
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "Test filed_B",
"filed_B": "**beyond** is search term in filed_B Test for Feb",
"Field_C": "Test description for filed_B test for Feb"
}
},
{
...
"_score": 23.517717,
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "Search Term filed_C",
"filed_B": " is the search term for lowest column",
"Field_C": "**beyond** Test description for filed_C "
}
}
]
请注意,field_A
比赛的分数彼此接近,但与filed_B
的分数稍远。
另请注意,按updated_time
排序的顺序首先是最新的;我们现在将处理相反的顺序。
如何使用updated_time
以相反的顺序排序?
field_value_factor
允许将字段中的原始值乘以某个因子。
在内部,Elasticsearch将日期存储为unix时间戳。它是一个 10 位数字的整数,实际上比 ES 返回我的分数大 ~10 个数量级。所以我选择将它们按可比顺序排列:
"field_value_factor": {
"field": "updated_time",
"factor": 0.00000000001,
"missing": 1
}
现在,这给了我们一个等价物SORT BY updated_time DESC
:
Feb 2020
Jan 2020
但是,如果我们需要它SORT BY updated_time ASC
呢?
Jan 2020
Feb 2020
我们不能乘以负因素,因为 Elasticsearch 中的分数必须是正实数。
相反,我们可以做的是使用1/x
修改原始值,如下所示:
"field_value_factor": {
"field": "updated_time",
"factor": 0.00000000001,
"missing": 1,
"modifier": "reciprocal" <=== 1/x
}
这最终会给我们您在问题中要求的顺序:
"hits": [
{
...
"_score": 0.17285699,
"_source": {
"updated_time": "2020-01-04T01:00:06.870000Z",
"field_A": "Slovakia beyond",
"filed_B": "The properties in Slovakia are beyound...",
"Field_C": "Once you fix the relevance then sorting should work correctly."
}
},
{
...
"_score": 0.1725641,
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "**beyond** filed_A",
"filed_B": "The properties in Japan is high",
"Field_C": "Test description for filed_A"
}
},
{
...
"_score": 0.116562225,
"_source": {
"updated_time": "2020-01-04T01:00:06.870000Z",
"field_A": "Test filed_B",
"filed_B": "**beyond** is search term in filed_B",
"Field_C": "Test description for filed_B"
}
},
{
...
"_score": 0.0978178,
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "Test filed_B",
"filed_B": "**beyond** is search term in filed_B Test for Feb",
"Field_C": "Test description for filed_B test for Feb"
}
},
{
...
"_score": 0.09411382,
"_source": {
"updated_time": "2020-02-04T01:00:06.870000Z",
"field_A": "Search Term filed_C",
"filed_B": " is the search term for lowest column",
"Field_C": "**beyond** Test description for filed_C "
}
}
如何在Java中做到这一点?
虽然我不能为您提供现成的代码,但我相信您可以从 FunctionScoreBuilder 开始,并尝试将其与您现有的代码集成。
希望这有帮助!