ElasticSearch 다단계 부모-자식 집계


79

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

회사-> 직원-> 가용성

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

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

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

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

예를 들면 :

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

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

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

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

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

현재 돌아온다 :

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

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

회사 IDS-> 첫 번째 가용성

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

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


요점에 매핑과 몇 가지 예제 문서 (후손 포함)를 추가 할 수 있습니까? 시스템을 적절하게 테스트 할 수있는 가짜 문서를 만드는 방법을보기는 어렵습니다.
Sloan Ahrens

Hey Sloan-매핑 및 샘플 결과를 추가했습니다. 이해하기 쉽도록 조금 벗겼습니다. 풀 스택에는 더 많은 데이터가 있습니다. :) 감사합니다!
Pete Minus 2014

나는 여기서 같은 질문을 했다 . 성능이 떨어질 수 있지만 기본 종류의 DocCount가있는 모든 결과를 요청합니다. 그런 다음 내 자신의 재귀 적 평면화, 정렬 및 제한을 수행했지만 이상적이지 않았습니다.
Matt Traynham

1
요점을 실행했지만 검색하면 오류 500이 발생 Query Failed [Failed to execute main query]]; nested: NullPointerException;합니다. 로컬 환경에서 요점을 실행하고 정상인지 확인할 수 있습니까? 감사!
Val

결과에 대한 방정식을 작성하지 마십시오. 데이터가 흐릿하지 않습니다! 모든 쿼리를 집계합니까? . 집계는 쿼리 나 출력이 아니라 입력 작업입니다. "이 결과를 확인하는 방법이 True (오른쪽)입니까?"라는 질문
dsgdfg

답변:


3

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

다음은 정렬 기준입니다.

  1. 거리 ASC (회사. 위치)
  2. 등급 DESC (company.rating_value)
  3. Soonest Future Availability 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?) 회사 당 가능 직원).

모두 합쳐서 회사를 계속 쿼리 하지만 company> employee> availabilty_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" }
 }
}

time-until-available 에서 생성하는 스크립트보다는 선형 감쇠 함수를 사용하면 약간 더 나은 성능을 얻을 수 있습니다 . _score
Peter Dixon-Moses

Elasticsearch는 기본적으로 동적 스크립팅을 비활성화했습니다. 색인 된 스크립트를 사용하는 것이 더 좋습니다. 여기를 참조하십시오 : elastic.co/blog/...
schellingerht

Pete Minus :이 작업을 수행 할 수 있었습니까? 나는 이것이 오래된 질문이라는 것을 알고 있지만 많은 사람들이 귀하의 솔루션에 관심을 가지고 있습니다.
Peter Dixon-Moses

Peter Dixon-Moses : 결국 저는 포기하고 두 개의 쿼리를 작성했습니다. 먼저 회사 / 직원으로 검색 한 다음 가용성을 통해 상위 100 개 회사를 검색 한 다음 병합했습니다. 왜? ES로만 구축하는 데 너무 많은 시간과 노력이 들었습니다. 검색에 소요되는 시간은 허용됩니다.
Pete Minus

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.