我有3个级别的父级/子级结构。比方说:
Company -> Employee -> Availability
由于可用性(以及员工)在这里经常更新,因此我选择对嵌套使用父/子结构。搜索功能也可以正常工作(所有文档都位于正确的分片中)。
现在,我想对这些结果进行排序。按公司(第一级)的元数据对它们进行排序很容易。但是我还需要按3级(可用性)进行排序。
我想要按以下方式排序的公司列表:
给定ASC到位置的距离
评分DESC
尽快供货ASC
例如:
公司A在5英里之外,具有4级,并且最快有20个小时可以找到一名员工
公司B也位于5英里之外,评级也为4,但他们的一名员工最快会在5个小时内上班。
因此排序结果必须为B,A。
我想对每个数据附加特殊的权重,因此我开始编写聚合,以后可以在custom_score脚本中使用。
创建索引,导入数据和搜索的完整依据
现在,我设法编写了一个查询,该查询实际上返回了结果,但是可用性聚合存储桶为空。
但是,我也将结果重新整理得井井有条,我想将它们弄平。
目前我回来了:
Company IDS -> Employee IDS -> first availability
我想要像这样的聚合:
Company IDS -> first availability
这样,我就可以执行custom_score脚本来计算分数并对其进行正确排序。
更简化的问题:
一个如何对多级(大)孩子进行排序/汇总,并可能将结果弄平。
您可以将映射和一些示例文档(带有后代)添加到要点吗?很难看到如何发明可以对系统进行适当测试的伪造文档。
嘿斯隆-Ive添加了映射和示例结果。香港专业教育学院剥离它,以便于理解。全栈中有更多数据:)谢谢!
我在这里有同样的问题。尽管性能可能较低,但我只是请求所有具有默认类型DocCount的结果。然后,我自己进行了递归展平,排序和限制,这并不是理想的选择。
我已经执行了要点,但是搜索时出现错误500 Query Failed [Failed to execute main query]]; nested: NullPointerException;。您能否在本地环境中执行要点并确保一切正常?谢谢!
为什么不为您的结果创建方程式。您的数据不模糊!您汇总每个查询? 。聚合是输入操作,而不是查询或输出。一个问题"如何检查此结果是否为True(正确)?"
使用哪个版本的ElasticSearch?我得到一个" nullPointerException"(我猜是因为我的版本)。我使用的是1.4.5版本。
您不需要进行聚合:
这些是排序标准:
距离ASC(公司位置)
评分DESC(company.rating_value)
不久的将来的可用性ASC(company.employee.availability.start)
如果忽略#3,则可以运行一个相对简单的公司查询,如下所示:
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之所以棘手,是因为您需要深入了解每个公司与请求时间最接近的可用性(公司>员工>可用性),并将该持续时间用作第三排序标准。
我们将在孙级使用function_score查询,以获取请求时间与命中_score中的每个可用性之间的时间差。 (然后,我们将_score作为第三个排序标准)。
为了达到孙辈,我们需要在has_child查询中使用has_child查询。
对于每个公司,我们都希望有最快的员工(当然还有他们最接近的可用性)。对于这样的情况,Elasticsearch 2.0将为我们提供"score_mode":"min",但是现在,由于我们仅限于"score_mode":"max",我们将使孙子_score成为时差的倒数。
"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)"
}
}
]
}
因此,现在每个孙子代的_score(可用性)将为1 / number-of-hours-until-available(以便我们可以使用直到每个员工可用的最大倒数时间,以及每个公司可以使用的最大员工倒数)。
综上所述,我们继续查询公司,但使用公司>雇员>可用性生成_score用作#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" }
}
}
使用线性衰减函数而不是从时间到可用生成_score的脚本,可能会获得更好的性能。
Elasticsearch默认情况下禁用动态脚本。 更好的方法是使用索引脚本。 看到这里:elastic.co/blog/
皮特·米纳斯(Pete Minus):您能使它正常工作吗? 我知道这是一个比较老的问题,但是有很多人对您的解决方案感兴趣。
彼得·迪克森-摩西(Peter Dixon-Moses):最终,我放弃了并写下了两个查询-首先按公司/员工进行搜索,然后通过"可用性"搜索排名前100位的公司,然后合并。 为什么? 仅在ES中构建它要花费太多时间/精力。 搜索所花费的时间是可以接受的。
您应该查看R-Tree数据结构https://en.wikipedia.org/wiki/R-tree。