web-dev-qa-db-ja.com

ElasticSearchマルチレベルの親子集約

私は3つのレベルで親/子構造を持っています。まあ言ってみれば:

会社->従業員->可用性

ここでは可用性(および従業員も)が頻繁に更新されるため、ネストに対して親/子構造を使用することを選択します。そして、検索機能は正常に動作します(すべてのドキュメントが正しいシャードにあります)。

次に、これらの結果を並べ替えます。それらを会社(第1レベル)からのメタデータでソートするのは簡単です。ただし、3番目のレベル(可用性)でも並べ替える必要があります。

以下でソートされた会社のリストが必要です。

  • 指定されたASCからの距離
  • 評価DESC
  • 最も早い可用性ASC

例えば:

会社Aは5マイルの距離にあり、評価4で最も早い従業員の1人が20時間以内に対応可能です。会社Bも5マイルの距離にあり、評価4ですが、従業員の1人が5時間以内に対応可能です。

したがって、ソート結果はB、Aである必要があります。

この各データに特別な重みを追加したいので、後でcustom_scoreスクリプトで使用できる集計を作成し始めました。

インデックスの作成、データのインポート、および検索の完全な要点

これで、実際に結果を返すクエリを作成できましたが、可用性の集計バケットが空です。ただし、構造化された結果も返されているので、それらを平坦化したいと思います。

現在私は戻ってきます:

会社IDS->従業員IDS->最初の可用性

次のような集計が必要です。

会社IDS->最初の可用性

このようにしてcustom_scoreスクリプトでスコアを計算し、適切に並べ替えます。

より簡単な質問:
どのようにして、マルチレベル(大)の子供によってソート/集約し、結果を平坦化できるでしょう。

79
Pete Minus

これを行うために集計は必要ありません。

これらはソート基準です:

  1. 距離ASC(company.location)
  2. レーティングDESC(company.rating_value)
  3. Soonest Future Availability ASC(company.employee.availability.start)

#3を無視すると、次のような比較的単純なcompanyクエリを実行できます。

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は、最も近い各会社の可用性(company> employee> availability)に到達して見つける必要があるため、トリッキーですリクエストの時間。その期間をサードソート基準として使用します。

孫レベルでfunction_scoreクエリを使用して、リクエスト時間とヒット_scoreの各空き時間の時間差を取得します。 (次に、_scoreを3番目のソート基準として使用します)。

孫に到達するには、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)"
                }
              }
            ]
          }

したがって、各孫の_scoreAvailability)は1 / number-of-hours-until-availableになります(つまり、maximumを使用できます)従業員ごとに利用可能になるまでの相互時間、および会社ごとに利用可能な最大相互(ly?)従業員)。

まとめると、companyのクエリを続行しますが、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" }
 }
}
3