Development Tip

ElasticSearch 다단계 부모-자식 집계

yourdevel 2020. 10. 10. 12:08
반응형

ElasticSearch 다단계 부모-자식 집계


나는 3 단계의 부모 / 자식 구조를 가지고 있습니다. 의 말을하자:

회사-> 직원-> 가용성

가용성 (및 직원)이 여기에서 자주 업데이트되므로 중첩에 대해 상위 / 하위 구조를 사용하도록 선택합니다. 그리고 검색 기능이 제대로 작동합니다 (올바른 샤드의 모든 문서).

이제 그 결과를 정렬하고 싶습니다. 회사 (1 단계)의 메타 데이터로 정렬하는 것은 쉽습니다. 하지만 3 단계 (가용성)로도 정렬해야합니다.

다음으로 정렬 된 회사 목록을 원합니다.

  • ASC가 주어진 위치로부터의 거리
  • 평가 DESC
  • 빠른 가용성 ASC

예를 들면 :

회사 A는 5 마일 떨어져 있고 등급 4이며 가장 빠른 직원 중 한 명이 20 시간 내에 이용 가능합니다. 회사 B도 5 마일 떨어져 있으며 등급 4도 있지만 가장 빨리 직원 중 한 명은 5 시간 내에 이용 가능합니다.

따라서 정렬 결과는 B, A 여야합니다.

이 데이터 각각에 특별한 가중치를 추가하고 싶기 때문에 나중에 custom_score 스크립트에서 사용할 수있는 집계 작성을 시작했습니다.

인덱스 생성, 데이터 가져 오기 및 검색에 대한 전체 요점

이제 실제로 결과를 반환하는 쿼리를 작성했지만 가용성 집계 버킷이 비어 있습니다. 그러나 결과가 너무 구조화되어 있으므로 평평하게 만들고 싶습니다.

현재 돌아온다 :

회사 ID-> 직원 ID-> 첫 번째 가용성

다음과 같은 집계를 원합니다.

회사 IDS-> 첫 번째 가용성

이렇게하면 custom_score점수를 계산하고 올바르게 정렬하는 스크립트를 수행 할 수 있습니다.

더 간단한 질문 :
어떻게 다단계 (손자)를 기준으로 정렬 / 집계하고 결과를 평평하게 만들 수 있습니까?


이를 위해 집계가 필요하지 않습니다.

다음은 정렬 기준입니다.

  1. 거리 ASC (회사. 위치)
  2. 등급 DESC (company.rating_value)
  3. 곧 미래 가용성 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(그래서 우리가 사용할 수있는 최대 상호 직원 당 가능하고, 때까지 시간을 최대 상호 (LY?) 회사 당 가능 직원).

Putting it all together, we continue to query company but use company > employee > availabilty to generate the _score to use as the #3 sort criterion:

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" }
 }
}

You should check out R-Tree data structure https://en.wikipedia.org/wiki/R-tree.

참고URL : https://stackoverflow.com/questions/27510798/elasticsearch-multi-level-parent-child-aggregation

반응형