加重平均集計

文書から抽出された数値の加重平均を計算する single-value メトリクス集計です。これらの値は、文書内の特定の数値フィールドから抽出できます。

通常の平均を計算する場合、各データポイントは等しい「重み」を持ち、最終値に等しく寄与します。一方、加重平均は各データポイントに異なる重みを付けます。各データポイントが最終値に寄与する量は文書から抽出されます。

数式として、加重平均は ∑(value * weight) / ∑(weight) です。

通常の平均は、すべての値が暗黙の重み 1 を持つ加重平均と考えることができます。


表 51. weighted_avg パラメータ

パラメータ名 説明 必須 デフォルト値
value 値を提供するフィールドまたはスクリプトの設定 必須
weight 重みを提供するフィールドまたはスクリプトの設定 必須
format 数値応答フォーマッタ オプション

value および weight オブジェクトには、フィールドごとの特定の設定があります:


表 52. value パラメータ

パラメータ名 説明 必須 デフォルト値
field 値を抽出するフィールド 必須
missing フィールドが完全に欠落している場合に使用する値 オプション


表 53. weight パラメータ

パラメータ名 説明 必須 デフォルト値
field 重みを抽出するフィールド 必須
missing フィールドが完全に欠落している場合に使用する重み オプション

文書に 0-100 の数値スコアを保持する "grade" フィールドと、任意の数値重みを保持する "weight" フィールドがある場合、次のように加重平均を計算できます:

Python

  1. resp = client.search(
  2. index="exams",
  3. size=0,
  4. aggs={
  5. "weighted_grade": {
  6. "weighted_avg": {
  7. "value": {
  8. "field": "grade"
  9. },
  10. "weight": {
  11. "field": "weight"
  12. }
  13. }
  14. }
  15. },
  16. )
  17. print(resp)

Ruby

  1. response = client.search(
  2. index: 'exams',
  3. body: {
  4. size: 0,
  5. aggregations: {
  6. weighted_grade: {
  7. weighted_avg: {
  8. value: {
  9. field: 'grade'
  10. },
  11. weight: {
  12. field: 'weight'
  13. }
  14. }
  15. }
  16. }
  17. }
  18. )
  19. puts response

Js

  1. const response = await client.search({
  2. index: "exams",
  3. size: 0,
  4. aggs: {
  5. weighted_grade: {
  6. weighted_avg: {
  7. value: {
  8. field: "grade",
  9. },
  10. weight: {
  11. field: "weight",
  12. },
  13. },
  14. },
  15. },
  16. });
  17. console.log(response);

コンソール

  1. POST /exams/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "weighted_grade": {
  6. "weighted_avg": {
  7. "value": {
  8. "field": "grade"
  9. },
  10. "weight": {
  11. "field": "weight"
  12. }
  13. }
  14. }
  15. }
  16. }

次のような応答が得られます:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "weighted_grade": {
  5. "value": 70.0
  6. }
  7. }
  8. }

フィールドごとに複数の値が許可されますが、重みは1つだけ許可されます。集計が複数の重みを持つ文書に遭遇した場合(例:重みフィールドが多値フィールドの場合)、検索は中止されます。この状況がある場合は、ランタイムフィールドを構築して、それらの値を単一の重みに結合する必要があります。

この単一の重みは、value フィールドから抽出された各値に独立して適用されます。

この例は、複数の値を持つ単一の文書が単一の重みで平均化される方法を示しています:

Python

  1. resp = client.index(
  2. index="exams",
  3. refresh=True,
  4. document={
  5. "grade": [
  6. 1,
  7. 2,
  8. 3
  9. ],
  10. "weight": 2
  11. },
  12. )
  13. print(resp)
  14. resp1 = client.search(
  15. index="exams",
  16. size=0,
  17. aggs={
  18. "weighted_grade": {
  19. "weighted_avg": {
  20. "value": {
  21. "field": "grade"
  22. },
  23. "weight": {
  24. "field": "weight"
  25. }
  26. }
  27. }
  28. },
  29. )
  30. print(resp1)

Ruby

  1. response = client.index(
  2. index: 'exams',
  3. refresh: true,
  4. body: {
  5. grade: [
  6. 1,
  7. 2,
  8. 3
  9. ],
  10. weight: 2
  11. }
  12. )
  13. puts response
  14. response = client.search(
  15. index: 'exams',
  16. body: {
  17. size: 0,
  18. aggregations: {
  19. weighted_grade: {
  20. weighted_avg: {
  21. value: {
  22. field: 'grade'
  23. },
  24. weight: {
  25. field: 'weight'
  26. }
  27. }
  28. }
  29. }
  30. }
  31. )
  32. puts response

Js

  1. const response = await client.index({
  2. index: "exams",
  3. refresh: "true",
  4. document: {
  5. grade: [1, 2, 3],
  6. weight: 2,
  7. },
  8. });
  9. console.log(response);
  10. const response1 = await client.search({
  11. index: "exams",
  12. size: 0,
  13. aggs: {
  14. weighted_grade: {
  15. weighted_avg: {
  16. value: {
  17. field: "grade",
  18. },
  19. weight: {
  20. field: "weight",
  21. },
  22. },
  23. },
  24. },
  25. });
  26. console.log(response1);

コンソール

  1. POST /exams/_doc?refresh
  2. {
  3. "grade": [1, 2, 3],
  4. "weight": 2
  5. }
  6. POST /exams/_search
  7. {
  8. "size": 0,
  9. "aggs": {
  10. "weighted_grade": {
  11. "weighted_avg": {
  12. "value": {
  13. "field": "grade"
  14. },
  15. "weight": {
  16. "field": "weight"
  17. }
  18. }
  19. }
  20. }
  21. }

3つの値(12、および 3)は、すべて 2 の重みを持つ独立した値として含まれます:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "weighted_grade": {
  5. "value": 2.0
  6. }
  7. }
  8. }

集計は 2.0 を結果として返し、手動で計算した場合に期待されるものと一致します: ((1*2) + (2*2) + (3*2)) / (2+2+2) == 2

ランタイムフィールド

インデックスされた値と完全に一致しない値を合計または重み付けする必要がある場合は、ランタイムフィールドで集計を実行します。

Python

  1. resp = client.index(
  2. index="exams",
  3. refresh=True,
  4. document={
  5. "grade": 100,
  6. "weight": [
  7. 2,
  8. 3
  9. ]
  10. },
  11. )
  12. print(resp)
  13. resp1 = client.index(
  14. index="exams",
  15. refresh=True,
  16. document={
  17. "grade": 80,
  18. "weight": 3
  19. },
  20. )
  21. print(resp1)
  22. resp2 = client.search(
  23. index="exams",
  24. filter_path="aggregations",
  25. size=0,
  26. runtime_mappings={
  27. "weight.combined": {
  28. "type": "double",
  29. "script": "\n double s = 0;\n for (double w : doc['weight']) {\n s += w;\n }\n emit(s);\n "
  30. }
  31. },
  32. aggs={
  33. "weighted_grade": {
  34. "weighted_avg": {
  35. "value": {
  36. "script": "doc.grade.value + 1"
  37. },
  38. "weight": {
  39. "field": "weight.combined"
  40. }
  41. }
  42. }
  43. },
  44. )
  45. print(resp2)

Ruby

  1. response = client.index(
  2. index: 'exams',
  3. refresh: true,
  4. body: {
  5. grade: 100,
  6. weight: [
  7. 2,
  8. 3
  9. ]
  10. }
  11. )
  12. puts response
  13. response = client.index(
  14. index: 'exams',
  15. refresh: true,
  16. body: {
  17. grade: 80,
  18. weight: 3
  19. }
  20. )
  21. puts response
  22. response = client.search(
  23. index: 'exams',
  24. filter_path: 'aggregations',
  25. body: {
  26. size: 0,
  27. runtime_mappings: {
  28. 'weight.combined' => {
  29. type: 'double',
  30. script: "\n double s = 0;\n for (double w : doc['weight']) {\n s += w;\n }\n emit(s);\n "
  31. }
  32. },
  33. aggregations: {
  34. weighted_grade: {
  35. weighted_avg: {
  36. value: {
  37. script: 'doc.grade.value + 1'
  38. },
  39. weight: {
  40. field: 'weight.combined'
  41. }
  42. }
  43. }
  44. }
  45. }
  46. )
  47. puts response

Js

  1. const response = await client.index({
  2. index: "exams",
  3. refresh: "true",
  4. document: {
  5. grade: 100,
  6. weight: [2, 3],
  7. },
  8. });
  9. console.log(response);
  10. const response1 = await client.index({
  11. index: "exams",
  12. refresh: "true",
  13. document: {
  14. grade: 80,
  15. weight: 3,
  16. },
  17. });
  18. console.log(response1);
  19. const response2 = await client.search({
  20. index: "exams",
  21. filter_path: "aggregations",
  22. size: 0,
  23. runtime_mappings: {
  24. "weight.combined": {
  25. type: "double",
  26. script:
  27. "\n double s = 0;\n for (double w : doc['weight']) {\n s += w;\n }\n emit(s);\n ",
  28. },
  29. },
  30. aggs: {
  31. weighted_grade: {
  32. weighted_avg: {
  33. value: {
  34. script: "doc.grade.value + 1",
  35. },
  36. weight: {
  37. field: "weight.combined",
  38. },
  39. },
  40. },
  41. },
  42. });
  43. console.log(response2);

コンソール

  1. POST /exams/_doc?refresh
  2. {
  3. "grade": 100,
  4. "weight": [2, 3]
  5. }
  6. POST /exams/_doc?refresh
  7. {
  8. "grade": 80,
  9. "weight": 3
  10. }
  11. POST /exams/_search?filter_path=aggregations
  12. {
  13. "size": 0,
  14. "runtime_mappings": {
  15. "weight.combined": {
  16. "type": "double",
  17. "script": """
  18. double s = 0;
  19. for (double w : doc['weight']) {
  20. s += w;
  21. }
  22. emit(s);
  23. """
  24. }
  25. },
  26. "aggs": {
  27. "weighted_grade": {
  28. "weighted_avg": {
  29. "value": {
  30. "script": "doc.grade.value + 1"
  31. },
  32. "weight": {
  33. "field": "weight.combined"
  34. }
  35. }
  36. }
  37. }
  38. }

次のようになります:

コンソール-結果

  1. {
  2. "aggregations": {
  3. "weighted_grade": {
  4. "value": 93.5
  5. }
  6. }
  7. }

欠落した値

デフォルトでは、集計は null または value または weight フィールドの値が欠落している文書を除外します。これらの文書に対してデフォルト値を指定するには、missing パラメータを使用します。

Python

  1. resp = client.search(
  2. index="exams",
  3. size=0,
  4. aggs={
  5. "weighted_grade": {
  6. "weighted_avg": {
  7. "value": {
  8. "field": "grade",
  9. "missing": 2
  10. },
  11. "weight": {
  12. "field": "weight",
  13. "missing": 3
  14. }
  15. }
  16. }
  17. },
  18. )
  19. print(resp)

Js

  1. const response = await client.search({
  2. index: "exams",
  3. size: 0,
  4. aggs: {
  5. weighted_grade: {
  6. weighted_avg: {
  7. value: {
  8. field: "grade",
  9. missing: 2,
  10. },
  11. weight: {
  12. field: "weight",
  13. missing: 3,
  14. },
  15. },
  16. },
  17. },
  18. });
  19. console.log(response);

コンソール

  1. POST /exams/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "weighted_grade": {
  6. "weighted_avg": {
  7. "value": {
  8. "field": "grade",
  9. "missing": 2
  10. },
  11. "weight": {
  12. "field": "weight",
  13. "missing": 3
  14. }
  15. }
  16. }
  17. }
  18. }