ボックスプロット集約

集約されたドキュメントから抽出された数値のボックスプロットを計算する boxplot メトリクス集約です。これらの値は、ドキュメント内の特定の数値または ヒストグラムフィールド から生成されることがあります。

boxplot 集約は、ボックスプロット を作成するために必要な情報を返します:最小値、最大値、中央値、第一四分位数(25パーセンタイル)および第三四分位数(75パーセンタイル)値。

構文

boxplot 集約は、単独で次のようになります:

Js

  1. {
  2. "boxplot": {
  3. "field": "load_time"
  4. }
  5. }

ロード時間を表すボックスプロットを見てみましょう:

Python

  1. resp = client.search(
  2. index="latency",
  3. size=0,
  4. aggs={
  5. "load_time_boxplot": {
  6. "boxplot": {
  7. "field": "load_time"
  8. }
  9. }
  10. },
  11. )
  12. print(resp)

Ruby

  1. response = client.search(
  2. index: 'latency',
  3. body: {
  4. size: 0,
  5. aggregations: {
  6. load_time_boxplot: {
  7. boxplot: {
  8. field: 'load_time'
  9. }
  10. }
  11. }
  12. }
  13. )
  14. puts response

Js

  1. const response = await client.search({
  2. index: "latency",
  3. size: 0,
  4. aggs: {
  5. load_time_boxplot: {
  6. boxplot: {
  7. field: "load_time",
  8. },
  9. },
  10. },
  11. });
  12. console.log(response);

コンソール

  1. GET latency/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "load_time_boxplot": {
  6. "boxplot": {
  7. "field": "load_time"
  8. }
  9. }
  10. }
  11. }
フィールド load_time は数値フィールドでなければなりません

応答は次のようになります:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "load_time_boxplot": {
  5. "min": 0.0,
  6. "max": 990.0,
  7. "q1": 167.5,
  8. "q2": 445.0,
  9. "q3": 722.5,
  10. "lower": 0.0,
  11. "upper": 990.0
  12. }
  13. }
  14. }

この場合、下ひげと上ひげの値は最小値と最大値に等しくなります。一般的に、これらの値は 1.5 IQR 範囲であり、つまり `````q1 - (1.5 IQR)q3 + (1.5 * IQR)に最も近い値です。これは近似であるため、与えられた値は実際のデータから観測された値ではない可能性がありますが、合理的な誤差範囲内にあるべきです。ボックスプロット集約は外れ値ポイントを直接返しませんが、lower > minまたはupper < max````` を確認して、どちら側に外れ値が存在するかを確認し、直接クエリすることができます。

スクリプト

インデックスが正確に作成されていない値のボックスプロットを作成する必要がある場合は、ランタイムフィールド を作成し、そのボックスプロットを取得する必要があります。たとえば、ロード時間がミリ秒単位であるが、秒単位で計算された値が必要な場合は、ランタイムフィールドを使用して変換します:

Python

  1. resp = client.search(
  2. index="latency",
  3. size=0,
  4. runtime_mappings={
  5. "load_time.seconds": {
  6. "type": "long",
  7. "script": {
  8. "source": "emit(doc['load_time'].value / params.timeUnit)",
  9. "params": {
  10. "timeUnit": 1000
  11. }
  12. }
  13. }
  14. },
  15. aggs={
  16. "load_time_boxplot": {
  17. "boxplot": {
  18. "field": "load_time.seconds"
  19. }
  20. }
  21. },
  22. )
  23. print(resp)

Ruby

  1. response = client.search(
  2. index: 'latency',
  3. body: {
  4. size: 0,
  5. runtime_mappings: {
  6. 'load_time.seconds' => {
  7. type: 'long',
  8. script: {
  9. source: "emit(doc['load_time'].value / params.timeUnit)",
  10. params: {
  11. "timeUnit": 1000
  12. }
  13. }
  14. }
  15. },
  16. aggregations: {
  17. load_time_boxplot: {
  18. boxplot: {
  19. field: 'load_time.seconds'
  20. }
  21. }
  22. }
  23. }
  24. )
  25. puts response

Js

  1. const response = await client.search({
  2. index: "latency",
  3. size: 0,
  4. runtime_mappings: {
  5. "load_time.seconds": {
  6. type: "long",
  7. script: {
  8. source: "emit(doc['load_time'].value / params.timeUnit)",
  9. params: {
  10. timeUnit: 1000,
  11. },
  12. },
  13. },
  14. },
  15. aggs: {
  16. load_time_boxplot: {
  17. boxplot: {
  18. field: "load_time.seconds",
  19. },
  20. },
  21. },
  22. });
  23. console.log(response);

コンソール

  1. GET latency/_search
  2. {
  3. "size": 0,
  4. "runtime_mappings": {
  5. "load_time.seconds": {
  6. "type": "long",
  7. "script": {
  8. "source": "emit(doc['load_time'].value / params.timeUnit)",
  9. "params": {
  10. "timeUnit": 1000
  11. }
  12. }
  13. }
  14. },
  15. "aggs": {
  16. "load_time_boxplot": {
  17. "boxplot": { "field": "load_time.seconds" }
  18. }
  19. }
  20. }

ボックスプロットの値は(通常)近似値です

boxplot メトリクスで使用されるアルゴリズムは TDigest と呼ばれています(T-Digestsを使用した正確な分位数の計算でテッド・ダニングによって導入されました)。

ボックスプロットは他のパーセンタイル集約と同様に 非決定的 です。これは、同じデータを使用してわずかに異なる結果を得る可能性があることを意味します。

圧縮

近似アルゴリズムは、メモリの利用と推定精度のバランスを取る必要があります。このバランスは compression パラメータを使用して制御できます:

Python

  1. resp = client.search(
  2. index="latency",
  3. size=0,
  4. aggs={
  5. "load_time_boxplot": {
  6. "boxplot": {
  7. "field": "load_time",
  8. "compression": 200
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Ruby

  1. response = client.search(
  2. index: 'latency',
  3. body: {
  4. size: 0,
  5. aggregations: {
  6. load_time_boxplot: {
  7. boxplot: {
  8. field: 'load_time',
  9. compression: 200
  10. }
  11. }
  12. }
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.search({
  2. index: "latency",
  3. size: 0,
  4. aggs: {
  5. load_time_boxplot: {
  6. boxplot: {
  7. field: "load_time",
  8. compression: 200,
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

コンソール

  1. GET latency/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "load_time_boxplot": {
  6. "boxplot": {
  7. "field": "load_time",
  8. "compression": 200
  9. }
  10. }
  11. }
  12. }
圧縮はメモリ使用量と近似誤差を制御します

TDigest アルゴリズムは、パーセンタイルを近似するために「ノード」を使用します。ノードが多いほど、精度が高く(データのボリュームに比例して大きなメモリフットプリント)、compression パラメータは最大ノード数を 20 * compression に制限します。

したがって、圧縮値を増加させることで、より多くのメモリをコストにしてパーセンタイルの精度を向上させることができます。大きな圧縮値は、基礎となるツリーのデータ構造が大きくなるため、アルゴリズムを遅くします。デフォルトの圧縮値は 100 です。

「ノード」は約 32 バイトのメモリを使用するため、最悪のシナリオ(ソートされて順序通りに到着する大量のデータ)では、デフォルト設定で約 64KB の TDigest が生成されます。実際にはデータはよりランダムであり、TDigest はより少ないメモリを使用します。

実行ヒント

TDigest のデフォルト実装はパフォーマンスの最適化がされており、数百万または数十億のサンプル値にスケーリングしながら、許容可能な精度レベルを維持します(場合によっては数百万のサンプルで相対誤差が 1% に近い)。精度のために最適化された実装を使用するオプションがあり、パラメータ execution_hint を値 high_accuracy に設定します:

Python

  1. resp = client.search(
  2. index="latency",
  3. size=0,
  4. aggs={
  5. "load_time_boxplot": {
  6. "boxplot": {
  7. "field": "load_time",
  8. "execution_hint": "high_accuracy"
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Ruby

  1. response = client.search(
  2. index: 'latency',
  3. body: {
  4. size: 0,
  5. aggregations: {
  6. load_time_boxplot: {
  7. boxplot: {
  8. field: 'load_time',
  9. execution_hint: 'high_accuracy'
  10. }
  11. }
  12. }
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.search({
  2. index: "latency",
  3. size: 0,
  4. aggs: {
  5. load_time_boxplot: {
  6. boxplot: {
  7. field: "load_time",
  8. execution_hint: "high_accuracy",
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

コンソール

  1. GET latency/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "load_time_boxplot": {
  6. "boxplot": {
  7. "field": "load_time",
  8. "execution_hint": "high_accuracy"
  9. }
  10. }
  11. }
  12. }
精度のために TDigest を最適化し、パフォーマンスを犠牲にします

このオプションは、精度を向上させる可能性があります(場合によっては数百万のサンプルで相対誤差が 0.01% に近い)が、その場合、パーセンタイルクエリの完了に 2 倍から 10 倍の時間がかかります。

欠損値

missing パラメータは、値が欠けているドキュメントがどのように扱われるべきかを定義します。デフォルトでは無視されますが、値があるかのように扱うことも可能です。

Python

  1. resp = client.search(
  2. index="latency",
  3. size=0,
  4. aggs={
  5. "grade_boxplot": {
  6. "boxplot": {
  7. "field": "grade",
  8. "missing": 10
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Ruby

  1. response = client.search(
  2. index: 'latency',
  3. body: {
  4. size: 0,
  5. aggregations: {
  6. grade_boxplot: {
  7. boxplot: {
  8. field: 'grade',
  9. missing: 10
  10. }
  11. }
  12. }
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.search({
  2. index: "latency",
  3. size: 0,
  4. aggs: {
  5. grade_boxplot: {
  6. boxplot: {
  7. field: "grade",
  8. missing: 10,
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

コンソール

  1. GET latency/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "grade_boxplot": {
  6. "boxplot": {
  7. "field": "grade",
  8. "missing": 10
  9. }
  10. }
  11. }
  12. }
grade フィールドに値がないドキュメントは、値が 10 のドキュメントと同じバケットに入ります。