合計集計

集計された文書から抽出された数値を合計する single-value メトリクス集計です。これらの値は、特定の数値または ヒストグラム フィールドから抽出できます。

データが販売記録を表す文書で構成されていると仮定すると、すべての帽子の販売価格を合計することができます:

Python

  1. resp = client.search(
  2. index="sales",
  3. size="0",
  4. query={
  5. "constant_score": {
  6. "filter": {
  7. "match": {
  8. "type": "hat"
  9. }
  10. }
  11. }
  12. },
  13. aggs={
  14. "hat_prices": {
  15. "sum": {
  16. "field": "price"
  17. }
  18. }
  19. },
  20. )
  21. print(resp)

Ruby

  1. response = client.search(
  2. index: 'sales',
  3. size: 0,
  4. body: {
  5. query: {
  6. constant_score: {
  7. filter: {
  8. match: {
  9. type: 'hat'
  10. }
  11. }
  12. }
  13. },
  14. aggregations: {
  15. hat_prices: {
  16. sum: {
  17. field: 'price'
  18. }
  19. }
  20. }
  21. }
  22. )
  23. puts response

Js

  1. const response = await client.search({
  2. index: "sales",
  3. size: 0,
  4. query: {
  5. constant_score: {
  6. filter: {
  7. match: {
  8. type: "hat",
  9. },
  10. },
  11. },
  12. },
  13. aggs: {
  14. hat_prices: {
  15. sum: {
  16. field: "price",
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

コンソール

  1. POST /sales/_search?size=0
  2. {
  3. "query": {
  4. "constant_score": {
  5. "filter": {
  6. "match": { "type": "hat" }
  7. }
  8. }
  9. },
  10. "aggs": {
  11. "hat_prices": { "sum": { "field": "price" } }
  12. }
  13. }

結果は次のとおりです:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "hat_prices": {
  5. "value": 450.0
  6. }
  7. }
  8. }

集計の名前(上記の hat_prices)は、返されたレスポンスから集計結果を取得するためのキーとしても機能します。

スクリプト

単一のフィールドよりも複雑な何かの sum を取得する必要がある場合は、ランタイムフィールド で集計を実行します。

Python

  1. resp = client.search(
  2. index="sales",
  3. size="0",
  4. runtime_mappings={
  5. "price.weighted": {
  6. "type": "double",
  7. "script": "\n double price = doc['price'].value;\n if (doc['promoted'].value) {\n price *= 0.8;\n }\n emit(price);\n "
  8. }
  9. },
  10. query={
  11. "constant_score": {
  12. "filter": {
  13. "match": {
  14. "type": "hat"
  15. }
  16. }
  17. }
  18. },
  19. aggs={
  20. "hat_prices": {
  21. "sum": {
  22. "field": "price.weighted"
  23. }
  24. }
  25. },
  26. )
  27. print(resp)

Ruby

  1. response = client.search(
  2. index: 'sales',
  3. size: 0,
  4. body: {
  5. runtime_mappings: {
  6. 'price.weighted' => {
  7. type: 'double',
  8. script: "\n double price = doc['price'].value;\n if (doc['promoted'].value) {\n price *= 0.8;\n }\n emit(price);\n "
  9. }
  10. },
  11. query: {
  12. constant_score: {
  13. filter: {
  14. match: {
  15. type: 'hat'
  16. }
  17. }
  18. }
  19. },
  20. aggregations: {
  21. hat_prices: {
  22. sum: {
  23. field: 'price.weighted'
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.search({
  2. index: "sales",
  3. size: 0,
  4. runtime_mappings: {
  5. "price.weighted": {
  6. type: "double",
  7. script:
  8. "\n double price = doc['price'].value;\n if (doc['promoted'].value) {\n price *= 0.8;\n }\n emit(price);\n ",
  9. },
  10. },
  11. query: {
  12. constant_score: {
  13. filter: {
  14. match: {
  15. type: "hat",
  16. },
  17. },
  18. },
  19. },
  20. aggs: {
  21. hat_prices: {
  22. sum: {
  23. field: "price.weighted",
  24. },
  25. },
  26. },
  27. });
  28. console.log(response);

コンソール

  1. POST /sales/_search?size=0
  2. {
  3. "runtime_mappings": {
  4. "price.weighted": {
  5. "type": "double",
  6. "script": """
  7. double price = doc['price'].value;
  8. if (doc['promoted'].value) {
  9. price *= 0.8;
  10. }
  11. emit(price);
  12. """
  13. }
  14. },
  15. "query": {
  16. "constant_score": {
  17. "filter": {
  18. "match": { "type": "hat" }
  19. }
  20. }
  21. },
  22. "aggs": {
  23. "hat_prices": {
  24. "sum": {
  25. "field": "price.weighted"
  26. }
  27. }
  28. }
  29. }

欠損値

欠損値を持つ文書がどのように扱われるかを定義するのが missing パラメータです。デフォルトでは、値が欠損している文書は無視されますが、値があるかのように扱うことも可能です。たとえば、これは価格のないすべての帽子の販売を 100 として扱います。

Python

  1. resp = client.search(
  2. index="sales",
  3. size="0",
  4. query={
  5. "constant_score": {
  6. "filter": {
  7. "match": {
  8. "type": "hat"
  9. }
  10. }
  11. }
  12. },
  13. aggs={
  14. "hat_prices": {
  15. "sum": {
  16. "field": "price",
  17. "missing": 100
  18. }
  19. }
  20. },
  21. )
  22. print(resp)

Ruby

  1. response = client.search(
  2. index: 'sales',
  3. size: 0,
  4. body: {
  5. query: {
  6. constant_score: {
  7. filter: {
  8. match: {
  9. type: 'hat'
  10. }
  11. }
  12. }
  13. },
  14. aggregations: {
  15. hat_prices: {
  16. sum: {
  17. field: 'price',
  18. missing: 100
  19. }
  20. }
  21. }
  22. }
  23. )
  24. puts response

Js

  1. const response = await client.search({
  2. index: "sales",
  3. size: 0,
  4. query: {
  5. constant_score: {
  6. filter: {
  7. match: {
  8. type: "hat",
  9. },
  10. },
  11. },
  12. },
  13. aggs: {
  14. hat_prices: {
  15. sum: {
  16. field: "price",
  17. missing: 100,
  18. },
  19. },
  20. },
  21. });
  22. console.log(response);

コンソール

  1. POST /sales/_search?size=0
  2. {
  3. "query": {
  4. "constant_score": {
  5. "filter": {
  6. "match": { "type": "hat" }
  7. }
  8. }
  9. },
  10. "aggs": {
  11. "hat_prices": {
  12. "sum": {
  13. "field": "price",
  14. "missing": 100
  15. }
  16. }
  17. }
  18. }

ヒストグラムフィールド

ヒストグラムフィールド に対して合計が計算されると、集計の結果は values 配列内のすべての要素の合計に、counts 配列内の同じ位置の数を掛けたものになります。

たとえば、異なるネットワークのレイテンシメトリクスを持つ事前集計されたヒストグラムを保存する次のインデックスについて:

Python

  1. resp = client.indices.create(
  2. index="metrics_index",
  3. mappings={
  4. "properties": {
  5. "latency_histo": {
  6. "type": "histogram"
  7. }
  8. }
  9. },
  10. )
  11. print(resp)
  12. resp1 = client.index(
  13. index="metrics_index",
  14. id="1",
  15. refresh=True,
  16. document={
  17. "network.name": "net-1",
  18. "latency_histo": {
  19. "values": [
  20. 0.1,
  21. 0.2,
  22. 0.3,
  23. 0.4,
  24. 0.5
  25. ],
  26. "counts": [
  27. 3,
  28. 7,
  29. 23,
  30. 12,
  31. 6
  32. ]
  33. }
  34. },
  35. )
  36. print(resp1)
  37. resp2 = client.index(
  38. index="metrics_index",
  39. id="2",
  40. refresh=True,
  41. document={
  42. "network.name": "net-2",
  43. "latency_histo": {
  44. "values": [
  45. 0.1,
  46. 0.2,
  47. 0.3,
  48. 0.4,
  49. 0.5
  50. ],
  51. "counts": [
  52. 8,
  53. 17,
  54. 8,
  55. 7,
  56. 6
  57. ]
  58. }
  59. },
  60. )
  61. print(resp2)
  62. resp3 = client.search(
  63. index="metrics_index",
  64. size="0",
  65. filter_path="aggregations",
  66. aggs={
  67. "total_latency": {
  68. "sum": {
  69. "field": "latency_histo"
  70. }
  71. }
  72. },
  73. )
  74. print(resp3)

Ruby

  1. response = client.indices.create(
  2. index: 'metrics_index',
  3. body: {
  4. mappings: {
  5. properties: {
  6. latency_histo: {
  7. type: 'histogram'
  8. }
  9. }
  10. }
  11. }
  12. )
  13. puts response
  14. response = client.index(
  15. index: 'metrics_index',
  16. id: 1,
  17. refresh: true,
  18. body: {
  19. 'network.name' => 'net-1',
  20. latency_histo: {
  21. values: [
  22. 0.1,
  23. 0.2,
  24. 0.3,
  25. 0.4,
  26. 0.5
  27. ],
  28. counts: [
  29. 3,
  30. 7,
  31. 23,
  32. 12,
  33. 6
  34. ]
  35. }
  36. }
  37. )
  38. puts response
  39. response = client.index(
  40. index: 'metrics_index',
  41. id: 2,
  42. refresh: true,
  43. body: {
  44. 'network.name' => 'net-2',
  45. latency_histo: {
  46. values: [
  47. 0.1,
  48. 0.2,
  49. 0.3,
  50. 0.4,
  51. 0.5
  52. ],
  53. counts: [
  54. 8,
  55. 17,
  56. 8,
  57. 7,
  58. 6
  59. ]
  60. }
  61. }
  62. )
  63. puts response
  64. response = client.search(
  65. index: 'metrics_index',
  66. size: 0,
  67. filter_path: 'aggregations',
  68. body: {
  69. aggregations: {
  70. total_latency: {
  71. sum: {
  72. field: 'latency_histo'
  73. }
  74. }
  75. }
  76. }
  77. )
  78. puts response

Js

  1. const response = await client.indices.create({
  2. index: "metrics_index",
  3. mappings: {
  4. properties: {
  5. latency_histo: {
  6. type: "histogram",
  7. },
  8. },
  9. },
  10. });
  11. console.log(response);
  12. const response1 = await client.index({
  13. index: "metrics_index",
  14. id: 1,
  15. refresh: "true",
  16. document: {
  17. "network.name": "net-1",
  18. latency_histo: {
  19. values: [0.1, 0.2, 0.3, 0.4, 0.5],
  20. counts: [3, 7, 23, 12, 6],
  21. },
  22. },
  23. });
  24. console.log(response1);
  25. const response2 = await client.index({
  26. index: "metrics_index",
  27. id: 2,
  28. refresh: "true",
  29. document: {
  30. "network.name": "net-2",
  31. latency_histo: {
  32. values: [0.1, 0.2, 0.3, 0.4, 0.5],
  33. counts: [8, 17, 8, 7, 6],
  34. },
  35. },
  36. });
  37. console.log(response2);
  38. const response3 = await client.search({
  39. index: "metrics_index",
  40. size: 0,
  41. filter_path: "aggregations",
  42. aggs: {
  43. total_latency: {
  44. sum: {
  45. field: "latency_histo",
  46. },
  47. },
  48. },
  49. });
  50. console.log(response3);

コンソール

  1. PUT metrics_index
  2. {
  3. "mappings": {
  4. "properties": {
  5. "latency_histo": { "type": "histogram" }
  6. }
  7. }
  8. }
  9. PUT metrics_index/_doc/1?refresh
  10. {
  11. "network.name" : "net-1",
  12. "latency_histo" : {
  13. "values" : [0.1, 0.2, 0.3, 0.4, 0.5],
  14. "counts" : [3, 7, 23, 12, 6]
  15. }
  16. }
  17. PUT metrics_index/_doc/2?refresh
  18. {
  19. "network.name" : "net-2",
  20. "latency_histo" : {
  21. "values" : [0.1, 0.2, 0.3, 0.4, 0.5],
  22. "counts" : [8, 17, 8, 7, 6]
  23. }
  24. }
  25. POST /metrics_index/_search?size=0&filter_path=aggregations
  26. {
  27. "aggs" : {
  28. "total_latency" : { "sum" : { "field" : "latency_histo" } }
  29. }
  30. }

各ヒストグラムフィールドに対して、sum 集計は values 配列内の各数値を、その関連する counts 配列内のカウントで掛けて加算します。

最終的に、すべてのヒストグラムのすべての値を加算し、次の結果を返します:

コンソール-結果

  1. {
  2. "aggregations": {
  3. "total_latency": {
  4. "value": 28.8
  5. }
  6. }
  7. }