Sorting ElasticSearch多级父子聚合
我有一个3级的父/子结构。让我们说:Sorting ElasticSearch多级父子聚合,sorting,elasticsearch,aggregation,Sorting,elasticsearch,Aggregation,我有一个3级的父/子结构。让我们说: 公司->员工->可用性 由于可用性(以及员工)在这里经常更新,所以我选择对嵌套结构使用父/子结构。搜索功能工作正常(所有文档都在正确的碎片中) 现在我想对这些结果进行排序。通过公司(第一级)的元数据对它们进行排序很容易。但我还需要按第三级(可用性)进行排序 我想要按以下顺序排列的公司列表: 距离给定ASC位置的距离 评级说明 最快可用性ASC 例如: A公司距离我们5英里,评级为4级,最快的一名员工将在20小时内到达 B公司也在5英里之外,也有4级,但最
公司->员工->可用性 由于可用性(以及员工)在这里经常更新,所以我选择对嵌套结构使用父/子结构。搜索功能工作正常(所有文档都在正确的碎片中) 现在我想对这些结果进行排序。通过公司(第一级)的元数据对它们进行排序很容易。但我还需要按第三级(可用性)进行排序 我想要按以下顺序排列的公司列表:
- 距离给定ASC位置的距离
- 评级说明
- 最快可用性ASC
现在,我已经成功编写了一个查询,它实际上返回结果,但可用性聚合桶是空的。 然而,我也得到了过于结构化的结果,我想把它们展平 现在我回来了:
公司ID->员工ID->首次可用 我希望有如下聚合:
公司ID->首次上市 通过这种方式,我可以执行我的
自定义_分数
脚本来计算分数并正确排序
更简单的问题:如何按多级(大)子级排序/聚合并可能展平结果。您应该查看R树数据结构。您不需要聚合来完成此操作: 以下是排序标准:
GET /companies/company/_search
{
"query": { "match_all" : {} },
"sort": {
"_script": {
"params": {
"lat": 51.5186,
"lon": -0.1347
},
"lang": "groovy",
"type": "number",
"order": "asc",
"script": "doc['location'].distanceInMiles(lat,lon)"
},
"rating_value": { "order": "desc" }
}
}
#3是一个棘手的问题,因为您需要找到最接近请求时间的每个公司的可用性(公司>员工>可用性),并将该持续时间用作第三个排序标准
我们将在孙子级别使用函数\u score
查询来获取请求时间和hit\u score
中每个可用性之间的时间差。(然后我们将使用\u评分作为第三个排序标准)
为了联系孙子辈,我们需要在has\u child
查询中使用has\u child
查询
对于每一家公司,我们都需要最快可用的员工(当然还有他们最接近的可用性)。Elasticsearch 2.0将为我们提供一个“分数模式”:“min”
用于此类情况,但目前,由于我们仅限于“分数模式”:“max”
我们将使孙子\u分数
为时差的倒数
"function_score": {
"filter": {
"range": {
"start": {
"gt": "2014-12-22T10:34:18+01:00"
}
}
},
"functions": [
{
"script_score": {
"lang": "groovy",
"params": {
"requested": "2014-12-22T10:34:18+01:00",
"millisPerHour": 3600000
},
"script": "1 / ((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
}
}
]
}
因此,现在每个孙子女(可用性)的\u分数将是1/可用时数
(这样我们可以使用每个员工可用时的最大互惠时间,以及每个公司可用员工的最大互惠时间)
总而言之,我们继续查询公司,但使用公司>员工>可用性生成\u分数
,用作\3排序标准:
GET /companies/company/_search
{
"query": {
"has_child" : {
"type" : "employee",
"score_mode" : "max",
"query": {
"has_child" : {
"type" : "availability",
"score_mode" : "max",
"query": {
"function_score": {
"filter": {
"range": {
"start": {
"gt": "2014-12-22T10:34:18+01:00"
}
}
},
"functions": [
{
"script_score": {
"lang": "groovy",
"params": {
"requested": "2014-12-22T10:34:18+01:00",
"millisPerHour": 3600000
},
"script": "1/((doc['availability.start'].value - new DateTime(requested).getMillis()) / millisPerHour)"
}
}
]
}
}
}
}
}
},
"sort": {
"_script": {
"params": {
"lat": 51.5186,
"lon": -0.1347
},
"lang": "groovy",
"type": "number",
"order": "asc",
"script": "doc['location'].distanceInMiles(lat,lon)"
},
"rating_value": { "order": "desc" },
"_score": { "order": "asc" }
}
}
能否将映射和一些示例文档(带子体)添加到要点中?很难想象如何发明伪造的文档来对您的系统进行充分的测试。为了便于理解,我把它剥去了一点。完整的堆栈中有很多的更多数据:)谢谢!我也有同样的问题。虽然性能可能不太好,但我只是请求所有具有默认DocCount排序的结果。然后,我自己做了递归展平、排序和限制,这并不理想。我已经执行了您的要点,但在搜索时,我得到错误500Query Failed[未能执行主查询];嵌套:NullPointerException代码>。你能在你当地的环境中执行你的要点并确保它是正确的吗?谢谢为什么不为你的结果建立一个方程式呢。你的数据不模糊!您聚合了每个查询。聚合是输入操作,而不是查询或输出。一个问题“您如何检查此结果是否正确(右)?”您可以使用一个而不是一个脚本从时间到可用时间生成\u分数
。默认情况下,Elasticsearch禁用了动态脚本。更好的方法是使用索引脚本。看这里:皮特:你能让它工作吗?我知道这是一个老问题,但是有很多人对你的解决方案感兴趣。Peter Dixon Moses:最终我放弃了,写了两个查询——首先按公司/员工搜索,然后通过可用性搜索前100家公司,然后合并。为什么?仅在ES中构建它花费了太多的时间/精力。花在搜索上的时间是可以接受的。