ElasticSearch多级父子聚合

时间:2014-12-16 17:49:13

标签: sorting elasticsearch aggregation

我有3个级别的父/子结构。让我们说:

  

公司 - >员工 - >可用性

由于此处经常更新可用性(以及员工),因此我选择使用父/子结构来嵌套。搜索功能正常(所有文档都在正确的分片中)。

现在我想对这些结果进行排序。通过公司(第1级)的元数据对它们进行排序很容易。但我需要按第3级(可用性)排序。

我想要按以下方式排序的公司列表:

  • 给定ASC的位置距离
  • 评级DESC
  • 最快的可用性ASC

例如:

A公司距离酒店5英里,评级为4,其中一名员工可在20小时内完成 公司B也在5英里外,也有4级,但最快的一名员工可在5小时内完成。

因此排序结果必须是B,A。

我想对每个数据添加特别的权重,所以我开始编写聚合,以后可以在我的custom_score脚本中使用。

Full gist for creating index, importing data and searching

现在,我设法写了一个实际返回结果的查询,但是可用性聚合桶是空的。 但是,我也得到了过于结构化的结果,我想将它们弄平。

目前我回来了:

  

公司IDS - >员工IDS - >第一次可用性

我希望聚合如下:

  

公司IDS - >第一次可用性

通过这种方式,我可以使用custom_score脚本来计算分数并对其进行正确排序。

更简化的问题:
如何对多级(大)孩子进行排序/聚合,并可能使结果变平。

2 个答案:

答案 0 :(得分:3)

您不需要汇总来执行此操作:

这些是排序标准:

  1. 距离ASC(company.location)
  2. 评级DESC(company.rating_value)
  3. 最快的未来可用性ASC(company.employee.availability.start)
  4. 如果忽略#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(这样我们就可以使用最大互惠时间直到可用每个员工,最大互惠(ly?)可用的每个公司员工。)

    总而言之,我们继续查询公司,但使用公司>员工>可用性生成_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" }
     }
    }
    

答案 1 :(得分:-1)

您应该查看R-Tree数据结构https://en.wikipedia.org/wiki/R-tree