集約

集約は、メトリック、統計、またはその他の分析としてデータを要約します。集約は、次のような質問に答えるのに役立ちます:

  • 私のウェブサイトの平均読み込み時間はどれくらいですか?
  • 取引量に基づいて、私の最も価値のある顧客は誰ですか?
  • 私のネットワークで大きなファイルと見なされるのは何ですか?
  • 各製品カテゴリには何製品がありますか?

Elasticsearchは、集約を3つのカテゴリに整理します:

  • メトリック集約は、フィールド値から合計や平均などのメトリックを計算します。
  • バケット集約は、フィールド値、範囲、またはその他の基準に基づいてドキュメントをバケット(ビンとも呼ばれる)にグループ化します。
  • パイプライン集約は、ドキュメントやフィールドの代わりに他の集約から入力を受け取ります。

集約を実行する

集約は、検索の一部として、検索APIaggsパラメータを指定することで実行できます。次の検索は、my-fieldに対して用語集約を実行します:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. aggs={
  4. "my-agg-name": {
  5. "terms": {
  6. "field": "my-field"
  7. }
  8. }
  9. },
  10. )
  11. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. aggregations: {
  5. "my-agg-name": {
  6. terms: {
  7. field: 'my-field'
  8. }
  9. }
  10. }
  11. }
  12. )
  13. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. aggs: {
  4. "my-agg-name": {
  5. terms: {
  6. field: "my-field",
  7. },
  8. },
  9. },
  10. });
  11. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "aggs": {
  4. "my-agg-name": {
  5. "terms": {
  6. "field": "my-field"
  7. }
  8. }
  9. }
  10. }

集約結果は、レスポンスのaggregationsオブジェクトに含まれています:

コンソール-結果

  1. {
  2. "took": 78,
  3. "timed_out": false,
  4. "_shards": {
  5. "total": 1,
  6. "successful": 1,
  7. "skipped": 0,
  8. "failed": 0
  9. },
  10. "hits": {
  11. "total": {
  12. "value": 5,
  13. "relation": "eq"
  14. },
  15. "max_score": 1.0,
  16. "hits": [...]
  17. },
  18. "aggregations": {
  19. "my-agg-name": {
  20. "doc_count_error_upper_bound": 0,
  21. "sum_other_doc_count": 0,
  22. "buckets": []
  23. }
  24. }
  25. }
my-agg-name集約の結果。

集約のスコープを変更する

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. query={
  6. "range": {
  7. "@timestamp": {
  8. "gte": "now-1d/d",
  9. "lt": "now/d"
  10. }
  11. }
  12. },
  13. aggs={
  14. "my-agg-name": {
  15. "terms": {
  16. "field": "my-field"
  17. }
  18. }
  19. },
  20. )
  21. print(resp)
  22. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. query: {
  5. range: {
  6. "@timestamp": {
  7. gte: 'now-1d/d',
  8. lt: 'now/d'
  9. }
  10. }
  11. },
  12. aggregations: {
  13. "my-agg-name": {
  14. terms: {
  15. field: 'my-field'
  16. }
  17. }
  18. }
  19. }
  20. )
  21. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. query: {
  4. range: {
  5. "@timestamp": {
  6. gte: "now-1d/d",
  7. lt: "now/d",
  8. },
  9. },
  10. },
  11. aggs: {
  12. "my-agg-name": {
  13. terms: {
  14. field: "my-field",
  15. },
  16. },
  17. },
  18. });
  19. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "query": {
  4. "range": {
  5. "@timestamp": {
  6. "gte": "now-1d/d",
  7. "lt": "now/d"
  8. }
  9. }
  10. },
  11. "aggs": {
  12. "my-agg-name": {
  13. "terms": {
  14. "field": "my-field"
  15. }
  16. }
  17. }
  18. }

集約結果のみを返す

デフォルトでは、集約を含む検索は、検索ヒットと集約結果の両方を返します。集約結果のみを返すには、size0に設定します:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. size=0,
  4. aggs={
  5. "my-agg-name": {
  6. "terms": {
  7. "field": "my-field"
  8. }
  9. }
  10. },
  11. )
  12. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. size: 0,
  5. aggregations: {
  6. "my-agg-name": {
  7. terms: {
  8. field: 'my-field'
  9. }
  10. }
  11. }
  12. }
  13. )
  14. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. size: 0,
  4. aggs: {
  5. "my-agg-name": {
  6. terms: {
  7. field: "my-field",
  8. },
  9. },
  10. },
  11. });
  12. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my-agg-name": {
  6. "terms": {
  7. "field": "my-field"
  8. }
  9. }
  10. }
  11. }

複数の集約を実行する

同じリクエストで複数の集約を指定できます:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. aggs={
  4. "my-first-agg-name": {
  5. "terms": {
  6. "field": "my-field"
  7. }
  8. },
  9. "my-second-agg-name": {
  10. "avg": {
  11. "field": "my-other-field"
  12. }
  13. }
  14. },
  15. )
  16. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. aggregations: {
  5. "my-first-agg-name": {
  6. terms: {
  7. field: 'my-field'
  8. }
  9. },
  10. "my-second-agg-name": {
  11. avg: {
  12. field: 'my-other-field'
  13. }
  14. }
  15. }
  16. }
  17. )
  18. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. aggs: {
  4. "my-first-agg-name": {
  5. terms: {
  6. field: "my-field",
  7. },
  8. },
  9. "my-second-agg-name": {
  10. avg: {
  11. field: "my-other-field",
  12. },
  13. },
  14. },
  15. });
  16. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "aggs": {
  4. "my-first-agg-name": {
  5. "terms": {
  6. "field": "my-field"
  7. }
  8. },
  9. "my-second-agg-name": {
  10. "avg": {
  11. "field": "my-other-field"
  12. }
  13. }
  14. }
  15. }

サブ集約を実行する

バケット集約は、バケットまたはメトリックのサブ集約をサポートします。たとえば、avgサブ集約を持つ用語集約は、各ドキュメントのバケットの平均値を計算します。サブ集約のネストに制限はありません。

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. aggs={
  4. "my-agg-name": {
  5. "terms": {
  6. "field": "my-field"
  7. },
  8. "aggs": {
  9. "my-sub-agg-name": {
  10. "avg": {
  11. "field": "my-other-field"
  12. }
  13. }
  14. }
  15. }
  16. },
  17. )
  18. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. aggregations: {
  5. "my-agg-name": {
  6. terms: {
  7. field: 'my-field'
  8. },
  9. aggregations: {
  10. "my-sub-agg-name": {
  11. avg: {
  12. field: 'my-other-field'
  13. }
  14. }
  15. }
  16. }
  17. }
  18. }
  19. )
  20. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. aggs: {
  4. "my-agg-name": {
  5. terms: {
  6. field: "my-field",
  7. },
  8. aggs: {
  9. "my-sub-agg-name": {
  10. avg: {
  11. field: "my-other-field",
  12. },
  13. },
  14. },
  15. },
  16. },
  17. });
  18. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "aggs": {
  4. "my-agg-name": {
  5. "terms": {
  6. "field": "my-field"
  7. },
  8. "aggs": {
  9. "my-sub-agg-name": {
  10. "avg": {
  11. "field": "my-other-field"
  12. }
  13. }
  14. }
  15. }
  16. }
  17. }

レスポンスは、サブ集約結果を親集約の下にネストします:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "my-agg-name": {
  5. "doc_count_error_upper_bound": 0,
  6. "sum_other_doc_count": 0,
  7. "buckets": [
  8. {
  9. "key": "foo",
  10. "doc_count": 5,
  11. "my-sub-agg-name": {
  12. "value": 75.0
  13. }
  14. }
  15. ]
  16. }
  17. }
  18. }
親集約、my-agg-nameの結果。
my-agg-nameのサブ集約、my-sub-agg-nameの結果。

カスタムメタデータを追加する

  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="my-index-000001",
  5. aggs={
  6. "my-agg-name": {
  7. "terms": {
  8. "field": "my-field"
  9. },
  10. "meta": {
  11. "my-metadata-field": "foo"
  12. }
  13. }
  14. },
  15. )
  16. print(resp)
  17. `

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. body: {
  4. aggregations: {
  5. "my-agg-name": {
  6. terms: {
  7. field: 'my-field'
  8. },
  9. meta: {
  10. "my-metadata-field": 'foo'
  11. }
  12. }
  13. }
  14. }
  15. )
  16. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. aggs: {
  4. "my-agg-name": {
  5. terms: {
  6. field: "my-field",
  7. },
  8. meta: {
  9. "my-metadata-field": "foo",
  10. },
  11. },
  12. },
  13. });
  14. console.log(response);

コンソール

  1. GET /my-index-000001/_search
  2. {
  3. "aggs": {
  4. "my-agg-name": {
  5. "terms": {
  6. "field": "my-field"
  7. },
  8. "meta": {
  9. "my-metadata-field": "foo"
  10. }
  11. }
  12. }
  13. }

レスポンスは、metaオブジェクトをそのまま返します:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "my-agg-name": {
  5. "meta": {
  6. "my-metadata-field": "foo"
  7. },
  8. "doc_count_error_upper_bound": 0,
  9. "sum_other_doc_count": 0,
  10. "buckets": []
  11. }
  12. }
  13. }

集約タイプを返す

デフォルトでは、集約結果には集約の名前が含まれますが、そのタイプは含まれません。集約タイプを返すには、typed_keysクエリパラメータを使用します。

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. typed_keys=True,
  4. aggs={
  5. "my-agg-name": {
  6. "histogram": {
  7. "field": "my-field",
  8. "interval": 1000
  9. }
  10. }
  11. },
  12. )
  13. print(resp)

Ruby

  1. response = client.search(
  2. index: 'my-index-000001',
  3. typed_keys: true,
  4. body: {
  5. aggregations: {
  6. "my-agg-name": {
  7. histogram: {
  8. field: 'my-field',
  9. interval: 1000
  10. }
  11. }
  12. }
  13. }
  14. )
  15. puts response

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. typed_keys: "true",
  4. aggs: {
  5. "my-agg-name": {
  6. histogram: {
  7. field: "my-field",
  8. interval: 1000,
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

コンソール

  1. GET /my-index-000001/_search?typed_keys
  2. {
  3. "aggs": {
  4. "my-agg-name": {
  5. "histogram": {
  6. "field": "my-field",
  7. "interval": 1000
  8. }
  9. }
  10. }
  11. }

レスポンスは、集約の名前の前に集約タイプを返します。

いくつかの集約は、リクエストのタイプとは異なる集約タイプを返します。たとえば、用語、重要な用語、およびパーセンタイル集約は、集約フィールドのデータタイプに応じて異なる集約タイプを返します。

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "histogram#my-agg-name": {
  5. "buckets": []
  6. }
  7. }
  8. }
集約タイプ、histogram、その後に#セパレーターと集約の名前、my-agg-nameが続きます。

集約でスクリプトを使用する

フィールドが必要な集約と正確に一致しない場合は、ランタイムフィールドで集約する必要があります:

Python

  1. resp = client.search(
  2. index="my-index-000001",
  3. size="0",
  4. runtime_mappings={
  5. "message.length": {
  6. "type": "long",
  7. "script": "emit(doc['message.keyword'].value.length())"
  8. }
  9. },
  10. aggs={
  11. "message_length": {
  12. "histogram": {
  13. "interval": 10,
  14. "field": "message.length"
  15. }
  16. }
  17. },
  18. )
  19. print(resp)

Js

  1. const response = await client.search({
  2. index: "my-index-000001",
  3. size: 0,
  4. runtime_mappings: {
  5. "message.length": {
  6. type: "long",
  7. script: "emit(doc['message.keyword'].value.length())",
  8. },
  9. },
  10. aggs: {
  11. message_length: {
  12. histogram: {
  13. interval: 10,
  14. field: "message.length",
  15. },
  16. },
  17. },
  18. });
  19. console.log(response);

コンソール

  1. GET /my-index-000001/_search?size=0
  2. {
  3. "runtime_mappings": {
  4. "message.length": {
  5. "type": "long",
  6. "script": "emit(doc['message.keyword'].value.length())"
  7. }
  8. },
  9. "aggs": {
  10. "message_length": {
  11. "histogram": {
  12. "interval": 10,
  13. "field": "message.length"
  14. }
  15. }
  16. }
  17. }

スクリプトはフィールド値を動的に計算するため、集約に少しオーバーヘッドが追加されます。計算にかかる時間に加えて、termsfiltersのような一部の集約は、ランタイムフィールドで最適化の一部を使用できません。ランタイムフィールドを使用する際のパフォーマンスコストは、集約によって異なります。

集約キャッシュ

より迅速なレスポンスのために、Elasticsearchは、頻繁に実行される集約の結果をシャードリクエストキャッシュにキャッシュします。キャッシュされた結果を取得するには、各検索に同じpreference文字列を使用します。検索ヒットが必要ない場合は、size0に設定してキャッシュを埋めるのを避けます。

Elasticsearchは、同じ優先文字列を持つ検索を同じシャードにルーティングします。検索間でシャードのデータが変更されない場合、シャードはキャッシュされた集約結果を返します。

長い値の制限

集約を実行する際、Elasticsearchはdouble値を使用して数値データを保持および表現します。その結果、longの数値が253を超える集約は近似値になります。