コンポジット集約

コンポジット集約は高コストです。コンポジット集約を本番環境にデプロイする前に、アプリケーションの負荷テストを行ってください。

異なるソースからコンポジットバケットを作成するマルチバケット集約です。

他の multi-bucket 集約とは異なり、composite 集約を使用して、マルチレベル集約から すべての バケットを効率的にページネートできます。この集約は、特定の集約の すべての バケットをストリーミングする方法を提供し、これは スクロール がドキュメントに対して行うことに似ています。

コンポジットバケットは、各ドキュメントから抽出/作成された値の組み合わせから構築され、各組み合わせはコンポジットバケットと見なされます。

例えば、次のドキュメントを考えてみてください:

Js

  1. {
  2. "keyword": ["foo", "bar"],
  3. "number": [23, 65, 76]
  4. }

keywordnumber を集約結果のソースフィールドとして使用すると、次のコンポジットバケットが生成されます:

Js

  1. { "keyword": "foo", "number": 23 }
  2. { "keyword": "foo", "number": 65 }
  3. { "keyword": "foo", "number": 76 }
  4. { "keyword": "bar", "number": 23 }
  5. { "keyword": "bar", "number": 65 }
  6. { "keyword": "bar", "number": 76 }

値ソース

sources パラメータは、コンポジットバケットを構築する際に使用するソースフィールドを定義します。sources の定義順序は、キーが返される順序を制御します。

sources を定義する際には、一意の名前を使用する必要があります。

sources パラメータは、次のいずれかのタイプである必要があります:

用語

terms 値ソースは、単純な terms 集約に似ています。値は terms 集約と同様にフィールドから抽出されます。

例:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "product": {
  9. "terms": {
  10. "field": "product"
  11. }
  12. }
  13. }
  14. ]
  15. }
  16. }
  17. },
  18. )
  19. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. product: {
  10. terms: {
  11. field: 'product'
  12. }
  13. }
  14. }
  15. ]
  16. }
  17. }
  18. }
  19. }
  20. )
  21. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. product: {
  9. terms: {
  10. field: "product",
  11. },
  12. },
  13. },
  14. ],
  15. },
  16. },
  17. },
  18. });
  19. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "product": { "terms": { "field": "product" } } }
  9. ]
  10. }
  11. }
  12. }
  13. }

terms 集約と同様に、ランタイムフィールド を使用してコンポジットバケットの値を作成することが可能です:

Python

  1. resp = client.search(
  2. runtime_mappings={
  3. "day_of_week": {
  4. "type": "keyword",
  5. "script": "\n emit(doc['timestamp'].value.dayOfWeekEnum\n .getDisplayName(TextStyle.FULL, Locale.ENGLISH))\n "
  6. }
  7. },
  8. size=0,
  9. aggs={
  10. "my_buckets": {
  11. "composite": {
  12. "sources": [
  13. {
  14. "dow": {
  15. "terms": {
  16. "field": "day_of_week"
  17. }
  18. }
  19. }
  20. ]
  21. }
  22. }
  23. },
  24. )
  25. print(resp)

Js

  1. const response = await client.search({
  2. runtime_mappings: {
  3. day_of_week: {
  4. type: "keyword",
  5. script:
  6. "\n emit(doc['timestamp'].value.dayOfWeekEnum\n .getDisplayName(TextStyle.FULL, Locale.ENGLISH))\n ",
  7. },
  8. },
  9. size: 0,
  10. aggs: {
  11. my_buckets: {
  12. composite: {
  13. sources: [
  14. {
  15. dow: {
  16. terms: {
  17. field: "day_of_week",
  18. },
  19. },
  20. },
  21. ],
  22. },
  23. },
  24. },
  25. });
  26. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "runtime_mappings": {
  4. "day_of_week": {
  5. "type": "keyword",
  6. "script": """
  7. emit(doc['timestamp'].value.dayOfWeekEnum
  8. .getDisplayName(TextStyle.FULL, Locale.ENGLISH))
  9. """
  10. }
  11. },
  12. "size": 0,
  13. "aggs": {
  14. "my_buckets": {
  15. "composite": {
  16. "sources": [
  17. {
  18. "dow": {
  19. "terms": { "field": "day_of_week" }
  20. }
  21. }
  22. ]
  23. }
  24. }
  25. }
  26. }

似ているものの、terms 値ソースは terms 集約と同じパラメータセットをサポートしていません。他のサポートされている値ソースパラメータについては、次を参照してください:

ヒストグラム

histogram 値ソースは数値値に適用され、値に対して固定サイズの間隔を構築します。interval パラメータは、数値値がどのように変換されるべきかを定義します。例えば、interval が 5 に設定されている場合、任意の数値値はその最も近い間隔に変換され、101 の値は 100 と 105 の間の間隔のキーである 100 に変換されます。

例:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "histo": {
  9. "histogram": {
  10. "field": "price",
  11. "interval": 5
  12. }
  13. }
  14. }
  15. ]
  16. }
  17. }
  18. },
  19. )
  20. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. histo: {
  10. histogram: {
  11. field: 'price',
  12. interval: 5
  13. }
  14. }
  15. }
  16. ]
  17. }
  18. }
  19. }
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. histo: {
  9. histogram: {
  10. field: "price",
  11. interval: 5,
  12. },
  13. },
  14. },
  15. ],
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "histo": { "histogram": { "field": "price", "interval": 5 } } }
  9. ]
  10. }
  11. }
  12. }
  13. }

histogram 集約と同様に、ランタイムフィールド を使用してコンポジットバケットの値を作成することが可能です:

Python

  1. resp = client.search(
  2. runtime_mappings={
  3. "price.discounted": {
  4. "type": "double",
  5. "script": "\n double price = doc['price'].value;\n if (doc['product'].value == 'mad max') {\n price *= 0.8;\n }\n emit(price);\n "
  6. }
  7. },
  8. size=0,
  9. aggs={
  10. "my_buckets": {
  11. "composite": {
  12. "sources": [
  13. {
  14. "price": {
  15. "histogram": {
  16. "interval": 5,
  17. "field": "price.discounted"
  18. }
  19. }
  20. }
  21. ]
  22. }
  23. }
  24. },
  25. )
  26. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. runtime_mappings: {
  4. 'price.discounted' => {
  5. type: 'double',
  6. script: "\n double price = doc['price'].value;\n if (doc['product'].value == 'mad max') {\n price *= 0.8;\n }\n emit(price);\n "
  7. }
  8. },
  9. size: 0,
  10. aggregations: {
  11. my_buckets: {
  12. composite: {
  13. sources: [
  14. {
  15. price: {
  16. histogram: {
  17. interval: 5,
  18. field: 'price.discounted'
  19. }
  20. }
  21. }
  22. ]
  23. }
  24. }
  25. }
  26. }
  27. )
  28. puts response

Js

  1. const response = await client.search({
  2. runtime_mappings: {
  3. "price.discounted": {
  4. type: "double",
  5. script:
  6. "\n double price = doc['price'].value;\n if (doc['product'].value == 'mad max') {\n price *= 0.8;\n }\n emit(price);\n ",
  7. },
  8. },
  9. size: 0,
  10. aggs: {
  11. my_buckets: {
  12. composite: {
  13. sources: [
  14. {
  15. price: {
  16. histogram: {
  17. interval: 5,
  18. field: "price.discounted",
  19. },
  20. },
  21. },
  22. ],
  23. },
  24. },
  25. },
  26. });
  27. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "runtime_mappings": {
  4. "price.discounted": {
  5. "type": "double",
  6. "script": """
  7. double price = doc['price'].value;
  8. if (doc['product'].value == 'mad max') {
  9. price *= 0.8;
  10. }
  11. emit(price);
  12. """
  13. }
  14. },
  15. "size": 0,
  16. "aggs": {
  17. "my_buckets": {
  18. "composite": {
  19. "sources": [
  20. {
  21. "price": {
  22. "histogram": {
  23. "interval": 5,
  24. "field": "price.discounted"
  25. }
  26. }
  27. }
  28. ]
  29. }
  30. }
  31. }
  32. }

日付ヒストグラム

date_histogramhistogram 値ソースに似ていますが、間隔は日付/時間の式によって指定されます:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "date": {
  9. "date_histogram": {
  10. "field": "timestamp",
  11. "calendar_interval": "1d"
  12. }
  13. }
  14. }
  15. ]
  16. }
  17. }
  18. },
  19. )
  20. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. date: {
  10. date_histogram: {
  11. field: 'timestamp',
  12. calendar_interval: '1d'
  13. }
  14. }
  15. }
  16. ]
  17. }
  18. }
  19. }
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. date: {
  9. date_histogram: {
  10. field: "timestamp",
  11. calendar_interval: "1d",
  12. },
  13. },
  14. },
  15. ],
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } }
  9. ]
  10. }
  11. }
  12. }
  13. }

上記の例は、1日ごとに間隔を作成し、すべての timestamp 値をその最も近い間隔の開始に変換します。間隔に利用可能な式:yearquartermonthweekdayhourminutesecond

時間値は、時間単位 解析によってサポートされる略語を介して指定することもできます。分数の時間値はサポートされていないことに注意してくださいが、別の時間単位にシフトすることで対処できます(例:1.5h90m として指定できます)。

フォーマット

内部的に、日付はエポックからのミリ秒で表される64ビットの数として表現されます。これらのタイムスタンプはバケットキーとして返されます。フォーマットパラメータで指定されたフォーマットを使用して、フォーマットされた日付文字列を返すことも可能です:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "date": {
  9. "date_histogram": {
  10. "field": "timestamp",
  11. "calendar_interval": "1d",
  12. "format": "yyyy-MM-dd"
  13. }
  14. }
  15. }
  16. ]
  17. }
  18. }
  19. },
  20. )
  21. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. date: {
  10. date_histogram: {
  11. field: 'timestamp',
  12. calendar_interval: '1d',
  13. format: 'yyyy-MM-dd'
  14. }
  15. }
  16. }
  17. ]
  18. }
  19. }
  20. }
  21. }
  22. )
  23. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. date: {
  9. date_histogram: {
  10. field: "timestamp",
  11. calendar_interval: "1d",
  12. format: "yyyy-MM-dd",
  13. },
  14. },
  15. },
  16. ],
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. {
  9. "date": {
  10. "date_histogram": {
  11. "field": "timestamp",
  12. "calendar_interval": "1d",
  13. "format": "yyyy-MM-dd"
  14. }
  15. }
  16. }
  17. ]
  18. }
  19. }
  20. }
  21. }
表現力豊かな日付形式パターンをサポートします。

タイムゾーン

日付時刻はElasticsearchにUTCで保存されます。デフォルトでは、すべてのバケット化と丸めもUTCで行われます。time_zoneパラメータを使用して、バケット化に異なるタイムゾーンを使用することを示すことができます。

タイムゾーンは、ISO 8601 UTCオフセット(例:+01:00または-08:00)として指定するか、America/Los_AngelesのようなTZデータベースで使用される識別子として指定できます。

オフセット

offset パラメータを使用して、各バケットの開始値を指定された正の(+)または負のオフセット(-)の期間で変更します。たとえば、1h は1時間、1d は1日です。詳細な時間の持続オプションについては、時間単位 を参照してください。

たとえば、day の間隔を使用すると、各バケットは真夜中から真夜中まで実行されます。offset パラメータを +6h に設定すると、各バケットは午前6時から午前6時まで実行されるようになります:

Python

  1. resp = client.index(
  2. index="my-index-000001",
  3. id="1",
  4. refresh=True,
  5. document={
  6. "date": "2015-10-01T05:30:00Z"
  7. },
  8. )
  9. print(resp)
  10. resp1 = client.index(
  11. index="my-index-000001",
  12. id="2",
  13. refresh=True,
  14. document={
  15. "date": "2015-10-01T06:30:00Z"
  16. },
  17. )
  18. print(resp1)
  19. resp2 = client.search(
  20. index="my-index-000001",
  21. size="0",
  22. aggs={
  23. "my_buckets": {
  24. "composite": {
  25. "sources": [
  26. {
  27. "date": {
  28. "date_histogram": {
  29. "field": "date",
  30. "calendar_interval": "day",
  31. "offset": "+6h",
  32. "format": "iso8601"
  33. }
  34. }
  35. }
  36. ]
  37. }
  38. }
  39. },
  40. )
  41. print(resp2)

Ruby

  1. response = client.index(
  2. index: 'my-index-000001',
  3. id: 1,
  4. refresh: true,
  5. body: {
  6. date: '2015-10-01T05:30:00Z'
  7. }
  8. )
  9. puts response
  10. response = client.index(
  11. index: 'my-index-000001',
  12. id: 2,
  13. refresh: true,
  14. body: {
  15. date: '2015-10-01T06:30:00Z'
  16. }
  17. )
  18. puts response
  19. response = client.search(
  20. index: 'my-index-000001',
  21. size: 0,
  22. body: {
  23. aggregations: {
  24. my_buckets: {
  25. composite: {
  26. sources: [
  27. {
  28. date: {
  29. date_histogram: {
  30. field: 'date',
  31. calendar_interval: 'day',
  32. offset: '+6h',
  33. format: 'iso8601'
  34. }
  35. }
  36. }
  37. ]
  38. }
  39. }
  40. }
  41. }
  42. )
  43. puts response

Js

  1. const response = await client.index({
  2. index: "my-index-000001",
  3. id: 1,
  4. refresh: "true",
  5. document: {
  6. date: "2015-10-01T05:30:00Z",
  7. },
  8. });
  9. console.log(response);
  10. const response1 = await client.index({
  11. index: "my-index-000001",
  12. id: 2,
  13. refresh: "true",
  14. document: {
  15. date: "2015-10-01T06:30:00Z",
  16. },
  17. });
  18. console.log(response1);
  19. const response2 = await client.search({
  20. index: "my-index-000001",
  21. size: 0,
  22. aggs: {
  23. my_buckets: {
  24. composite: {
  25. sources: [
  26. {
  27. date: {
  28. date_histogram: {
  29. field: "date",
  30. calendar_interval: "day",
  31. offset: "+6h",
  32. format: "iso8601",
  33. },
  34. },
  35. },
  36. ],
  37. },
  38. },
  39. },
  40. });
  41. console.log(response2);

コンソール

  1. PUT my-index-000001/_doc/1?refresh
  2. {
  3. "date": "2015-10-01T05:30:00Z"
  4. }
  5. PUT my-index-000001/_doc/2?refresh
  6. {
  7. "date": "2015-10-01T06:30:00Z"
  8. }
  9. GET my-index-000001/_search?size=0
  10. {
  11. "aggs": {
  12. "my_buckets": {
  13. "composite" : {
  14. "sources" : [
  15. {
  16. "date": {
  17. "date_histogram" : {
  18. "field": "date",
  19. "calendar_interval": "day",
  20. "offset": "+6h",
  21. "format": "iso8601"
  22. }
  23. }
  24. }
  25. ]
  26. }
  27. }
  28. }
  29. }

真夜中から始まる単一のバケットの代わりに、上記のリクエストは午前6時から始まるバケットにドキュメントをグループ化します:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "my_buckets": {
  5. "after_key": { "date": "2015-10-01T06:00:00.000Z" },
  6. "buckets": [
  7. {
  8. "key": { "date": "2015-09-30T06:00:00.000Z" },
  9. "doc_count": 1
  10. },
  11. {
  12. "key": { "date": "2015-10-01T06:00:00.000Z" },
  13. "doc_count": 1
  14. }
  15. ]
  16. }
  17. }
  18. }

各バケットの開始 offset は、time_zone 調整が行われた後に計算されます。

GeoTile グリッド

geotile_grid 値ソースは geo_point フィールドで機能し、ポイントをグリッド内のセルを表すバケットにグループ化します。結果のグリッドはスパースであり、マッチするデータを持つセルのみを含みます。各セルは、多くのオンラインマップサイトで使用される マップタイル に対応しています。各セルは「{zoom}/{x}/{y}」形式でラベル付けされ、zoom はユーザー指定の精度に等しいです。

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "tile": {
  9. "geotile_grid": {
  10. "field": "location",
  11. "precision": 8
  12. }
  13. }
  14. }
  15. ]
  16. }
  17. }
  18. },
  19. )
  20. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. tile: {
  10. geotile_grid: {
  11. field: 'location',
  12. precision: 8
  13. }
  14. }
  15. }
  16. ]
  17. }
  18. }
  19. }
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. tile: {
  9. geotile_grid: {
  10. field: "location",
  11. precision: 8,
  12. },
  13. },
  14. },
  15. ],
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "tile": { "geotile_grid": { "field": "location", "precision": 8 } } }
  9. ]
  10. }
  11. }
  12. }
  13. }

精度

最も高精度のジオタイルは長さ29で、10cm x 10cm未満の土地をカバーするセルを生成します。この精度は、各タイルを生成してメモリにロードする必要がないため、コンポジット集約に特に適しています。

精度(ズーム)が地上のサイズにどのように相関するかについては、ズームレベルのドキュメント を参照してください。この集約の精度は0から29の範囲で設定できます。

バウンディングボックスフィルタリング

ジオタイルソースは、特定のジオバウンディングボックスに制約をかけることができ、使用されるタイルの範囲を減少させます。これらの境界は、特定の地理的エリアの一部に高精度のタイルが必要な場合に便利です。

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "tile": {
  9. "geotile_grid": {
  10. "field": "location",
  11. "precision": 22,
  12. "bounds": {
  13. "top_left": "POINT (4.9 52.4)",
  14. "bottom_right": "POINT (5.0 52.3)"
  15. }
  16. }
  17. }
  18. }
  19. ]
  20. }
  21. }
  22. },
  23. )
  24. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. tile: {
  10. geotile_grid: {
  11. field: 'location',
  12. precision: 22,
  13. bounds: {
  14. top_left: 'POINT (4.9 52.4)',
  15. bottom_right: 'POINT (5.0 52.3)'
  16. }
  17. }
  18. }
  19. }
  20. ]
  21. }
  22. }
  23. }
  24. }
  25. )
  26. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. tile: {
  9. geotile_grid: {
  10. field: "location",
  11. precision: 22,
  12. bounds: {
  13. top_left: "POINT (4.9 52.4)",
  14. bottom_right: "POINT (5.0 52.3)",
  15. },
  16. },
  17. },
  18. },
  19. ],
  20. },
  21. },
  22. },
  23. });
  24. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. {
  9. "tile": {
  10. "geotile_grid": {
  11. "field": "location",
  12. "precision": 22,
  13. "bounds": {
  14. "top_left": "POINT (4.9 52.4)",
  15. "bottom_right": "POINT (5.0 52.3)"
  16. }
  17. }
  18. }
  19. }
  20. ]
  21. }
  22. }
  23. }
  24. }

異なる値ソースの混合

sources パラメータは、値ソースの配列を受け入れます。異なる値ソースを混合してコンポジットバケットを作成することが可能です。例えば:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "date": {
  9. "date_histogram": {
  10. "field": "timestamp",
  11. "calendar_interval": "1d"
  12. }
  13. }
  14. },
  15. {
  16. "product": {
  17. "terms": {
  18. "field": "product"
  19. }
  20. }
  21. }
  22. ]
  23. }
  24. }
  25. },
  26. )
  27. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. date: {
  10. date_histogram: {
  11. field: 'timestamp',
  12. calendar_interval: '1d'
  13. }
  14. }
  15. },
  16. {
  17. product: {
  18. terms: {
  19. field: 'product'
  20. }
  21. }
  22. }
  23. ]
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. date: {
  9. date_histogram: {
  10. field: "timestamp",
  11. calendar_interval: "1d",
  12. },
  13. },
  14. },
  15. {
  16. product: {
  17. terms: {
  18. field: "product",
  19. },
  20. },
  21. },
  22. ],
  23. },
  24. },
  25. },
  26. });
  27. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } },
  9. { "product": { "terms": { "field": "product" } } }
  10. ]
  11. }
  12. }
  13. }
  14. }

これにより、2つの値ソース、date_histogramterms によって作成された値からコンポジットバケットが作成されます。各バケットは、集約で定義された各値ソースの1つの値で構成されます。任意のタイプの組み合わせが許可され、配列内の順序はコンポジットバケットに保持されます。

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "shop": {
  9. "terms": {
  10. "field": "shop"
  11. }
  12. }
  13. },
  14. {
  15. "product": {
  16. "terms": {
  17. "field": "product"
  18. }
  19. }
  20. },
  21. {
  22. "date": {
  23. "date_histogram": {
  24. "field": "timestamp",
  25. "calendar_interval": "1d"
  26. }
  27. }
  28. }
  29. ]
  30. }
  31. }
  32. },
  33. )
  34. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. shop: {
  10. terms: {
  11. field: 'shop'
  12. }
  13. }
  14. },
  15. {
  16. product: {
  17. terms: {
  18. field: 'product'
  19. }
  20. }
  21. },
  22. {
  23. date: {
  24. date_histogram: {
  25. field: 'timestamp',
  26. calendar_interval: '1d'
  27. }
  28. }
  29. }
  30. ]
  31. }
  32. }
  33. }
  34. }
  35. )
  36. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. shop: {
  9. terms: {
  10. field: "shop",
  11. },
  12. },
  13. },
  14. {
  15. product: {
  16. terms: {
  17. field: "product",
  18. },
  19. },
  20. },
  21. {
  22. date: {
  23. date_histogram: {
  24. field: "timestamp",
  25. calendar_interval: "1d",
  26. },
  27. },
  28. },
  29. ],
  30. },
  31. },
  32. },
  33. });
  34. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "shop": { "terms": { "field": "shop" } } },
  9. { "product": { "terms": { "field": "product" } } },
  10. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } }
  11. ]
  12. }
  13. }
  14. }
  15. }

順序

デフォルトでは、コンポジットバケットはその自然な順序でソートされます。値はその値の昇順でソートされます。複数の値ソースが要求される場合、順序は値ソースごとに行われ、コンポジットバケットの最初の値は他のコンポジットバケットの最初の値と比較され、等しい場合はコンポジットバケット内の次の値がタイブレークに使用されます。これは、コンポジットバケット [foo, 100][foobar, 0] よりも小さいと見なされることを意味します。foofoobar よりも小さいと見なされます。各値ソースのソートの方向を定義することが可能で、orderasc(デフォルト値)または desc(降順)に設定することで、値ソース定義内で直接設定できます。例えば:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "date": {
  9. "date_histogram": {
  10. "field": "timestamp",
  11. "calendar_interval": "1d",
  12. "order": "desc"
  13. }
  14. }
  15. },
  16. {
  17. "product": {
  18. "terms": {
  19. "field": "product",
  20. "order": "asc"
  21. }
  22. }
  23. }
  24. ]
  25. }
  26. }
  27. },
  28. )
  29. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. date: {
  10. date_histogram: {
  11. field: 'timestamp',
  12. calendar_interval: '1d',
  13. order: 'desc'
  14. }
  15. }
  16. },
  17. {
  18. product: {
  19. terms: {
  20. field: 'product',
  21. order: 'asc'
  22. }
  23. }
  24. }
  25. ]
  26. }
  27. }
  28. }
  29. }
  30. )
  31. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. date: {
  9. date_histogram: {
  10. field: "timestamp",
  11. calendar_interval: "1d",
  12. order: "desc",
  13. },
  14. },
  15. },
  16. {
  17. product: {
  18. terms: {
  19. field: "product",
  20. order: "asc",
  21. },
  22. },
  23. },
  24. ],
  25. },
  26. },
  27. },
  28. });
  29. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
  9. { "product": { "terms": { "field": "product", "order": "asc" } } }
  10. ]
  11. }
  12. }
  13. }
  14. }

… は、date_histogram ソースからの値を比較する際にコンポジットバケットを降順にソートし、terms ソースからの値を比較する際に昇順にソートします。

欠落バケット

デフォルトでは、特定のソースに値がないドキュメントは無視されます。missing_buckettrue に設定することで、応答に含めることが可能です(デフォルトは false):

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "product_name": {
  9. "terms": {
  10. "field": "product",
  11. "missing_bucket": True,
  12. "missing_order": "last"
  13. }
  14. }
  15. }
  16. ]
  17. }
  18. }
  19. },
  20. )
  21. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. product_name: {
  10. terms: {
  11. field: 'product',
  12. missing_bucket: true,
  13. missing_order: 'last'
  14. }
  15. }
  16. }
  17. ]
  18. }
  19. }
  20. }
  21. }
  22. )
  23. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. product_name: {
  9. terms: {
  10. field: "product",
  11. missing_bucket: true,
  12. missing_order: "last",
  13. },
  14. },
  15. },
  16. ],
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [{
  8. "product_name": {
  9. "terms": {
  10. "field": "product",
  11. "missing_bucket": true,
  12. "missing_order": "last"
  13. }
  14. }
  15. }]
  16. }
  17. }
  18. }
  19. }

上記の例では、product_name ソースは product 値を持たないドキュメントのために明示的な null バケットを出力します。このバケットは最後に配置されます。

missing_order パラメータを使用して null バケットの位置を制御できます。missing_orderfirst または last の場合、null バケットはそれぞれ最初または最後の位置に配置されます。missing_order が省略されるか default の場合、ソースの order がバケットの位置を決定します。orderasc(昇順)の場合、バケットは最初の位置にあります。orderdesc(降順)の場合、バケットは最後の位置にあります。

サイズ

size パラメータを設定して、いくつのコンポジットバケットを返すべきかを定義できます。各コンポジットバケットは単一のバケットと見なされるため、サイズを10に設定すると、値ソースから作成された最初の10個のコンポジットバケットが返されます。応答には、各コンポジットバケットの値が、各値ソースから抽出された値を含む配列で含まれます。デフォルトは 10 です。

ページネーション

コンポジットバケットの数が高すぎる(または不明)場合、単一の応答で返すことができるように、複数のリクエストに分割することが可能です。コンポジットバケットは本質的にフラットであるため、要求された size は、応答で返されるコンポジットバケットの正確な数です(返すべきコンポジットバケットが少なくとも size であると仮定します)。すべてのコンポジットバケットを取得する必要がある場合は、小さなサイズ(100 または 1000 など)を使用し、その後 after パラメータを使用して次の結果を取得することが望ましいです。例えば:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "size": 2,
  7. "sources": [
  8. {
  9. "date": {
  10. "date_histogram": {
  11. "field": "timestamp",
  12. "calendar_interval": "1d"
  13. }
  14. }
  15. },
  16. {
  17. "product": {
  18. "terms": {
  19. "field": "product"
  20. }
  21. }
  22. }
  23. ]
  24. }
  25. }
  26. },
  27. )
  28. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. size: 2,
  8. sources: [
  9. {
  10. date: {
  11. date_histogram: {
  12. field: 'timestamp',
  13. calendar_interval: '1d'
  14. }
  15. }
  16. },
  17. {
  18. product: {
  19. terms: {
  20. field: 'product'
  21. }
  22. }
  23. }
  24. ]
  25. }
  26. }
  27. }
  28. }
  29. )
  30. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. size: 2,
  7. sources: [
  8. {
  9. date: {
  10. date_histogram: {
  11. field: "timestamp",
  12. calendar_interval: "1d",
  13. },
  14. },
  15. },
  16. {
  17. product: {
  18. terms: {
  19. field: "product",
  20. },
  21. },
  22. },
  23. ],
  24. },
  25. },
  26. },
  27. });
  28. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "size": 2,
  8. "sources": [
  9. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d" } } },
  10. { "product": { "terms": { "field": "product" } } }
  11. ]
  12. }
  13. }
  14. }
  15. }

… 返される:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "my_buckets": {
  5. "after_key": {
  6. "date": 1494288000000,
  7. "product": "mad max"
  8. },
  9. "buckets": [
  10. {
  11. "key": {
  12. "date": 1494201600000,
  13. "product": "rocky"
  14. },
  15. "doc_count": 1
  16. },
  17. {
  18. "key": {
  19. "date": 1494288000000,
  20. "product": "mad max"
  21. },
  22. "doc_count": 2
  23. }
  24. ]
  25. }
  26. }
  27. }

次のバケットセットを取得するには、after パラメータを応答で返された after_key 値に設定して、同じ集約を再送信します。例えば、このリクエストは前の応答で提供された after_key 値を使用します:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "size": 2,
  7. "sources": [
  8. {
  9. "date": {
  10. "date_histogram": {
  11. "field": "timestamp",
  12. "calendar_interval": "1d",
  13. "order": "desc"
  14. }
  15. }
  16. },
  17. {
  18. "product": {
  19. "terms": {
  20. "field": "product",
  21. "order": "asc"
  22. }
  23. }
  24. }
  25. ],
  26. "after": {
  27. "date": 1494288000000,
  28. "product": "mad max"
  29. }
  30. }
  31. }
  32. },
  33. )
  34. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. size: 2,
  8. sources: [
  9. {
  10. date: {
  11. date_histogram: {
  12. field: 'timestamp',
  13. calendar_interval: '1d',
  14. order: 'desc'
  15. }
  16. }
  17. },
  18. {
  19. product: {
  20. terms: {
  21. field: 'product',
  22. order: 'asc'
  23. }
  24. }
  25. }
  26. ],
  27. after: {
  28. date: 1_494_288_000_000,
  29. product: 'mad max'
  30. }
  31. }
  32. }
  33. }
  34. }
  35. )
  36. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. size: 2,
  7. sources: [
  8. {
  9. date: {
  10. date_histogram: {
  11. field: "timestamp",
  12. calendar_interval: "1d",
  13. order: "desc",
  14. },
  15. },
  16. },
  17. {
  18. product: {
  19. terms: {
  20. field: "product",
  21. order: "asc",
  22. },
  23. },
  24. },
  25. ],
  26. after: {
  27. date: 1494288000000,
  28. product: "mad max",
  29. },
  30. },
  31. },
  32. },
  33. });
  34. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "size": 2,
  8. "sources": [
  9. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
  10. { "product": { "terms": { "field": "product", "order": "asc" } } }
  11. ],
  12. "after": { "date": 1494288000000, "product": "mad max" }
  13. }
  14. }
  15. }
  16. }
提供された値の にソートされるバケットに集約を制限する必要があります。

after_key通常 応答で返された最後のバケットのキーですが、それは保証されていません。常にバケットから導出するのではなく、返された after_key を使用してください。

早期終了

最適なパフォーマンスのために、インデックスソート をインデックスに設定し、コンポジット集約のソース順序の一部または完全に一致させる必要があります。例えば、次のインデックスソート:

Python

  1. resp = client.indices.create(
  2. index="my-index-000001",
  3. settings={
  4. "index": {
  5. "sort.field": [
  6. "username",
  7. "timestamp"
  8. ],
  9. "sort.order": [
  10. "asc",
  11. "desc"
  12. ]
  13. }
  14. },
  15. mappings={
  16. "properties": {
  17. "username": {
  18. "type": "keyword",
  19. "doc_values": True
  20. },
  21. "timestamp": {
  22. "type": "date"
  23. }
  24. }
  25. },
  26. )
  27. print(resp)

Ruby

  1. response = client.indices.create(
  2. index: 'my-index-000001',
  3. body: {
  4. settings: {
  5. index: {
  6. 'sort.field' => [
  7. 'username',
  8. 'timestamp'
  9. ],
  10. 'sort.order' => [
  11. 'asc',
  12. 'desc'
  13. ]
  14. }
  15. },
  16. mappings: {
  17. properties: {
  18. username: {
  19. type: 'keyword',
  20. doc_values: true
  21. },
  22. timestamp: {
  23. type: 'date'
  24. }
  25. }
  26. }
  27. }
  28. )
  29. puts response

Js

  1. const response = await client.indices.create({
  2. index: "my-index-000001",
  3. settings: {
  4. index: {
  5. "sort.field": ["username", "timestamp"],
  6. "sort.order": ["asc", "desc"],
  7. },
  8. },
  9. mappings: {
  10. properties: {
  11. username: {
  12. type: "keyword",
  13. doc_values: true,
  14. },
  15. timestamp: {
  16. type: "date",
  17. },
  18. },
  19. },
  20. });
  21. console.log(response);

コンソール

  1. PUT my-index-000001
  2. {
  3. "settings": {
  4. "index": {
  5. "sort.field": [ "username", "timestamp" ],
  6. "sort.order": [ "asc", "desc" ]
  7. }
  8. },
  9. "mappings": {
  10. "properties": {
  11. "username": {
  12. "type": "keyword",
  13. "doc_values": true
  14. },
  15. "timestamp": {
  16. "type": "date"
  17. }
  18. }
  19. }
  20. }
このインデックスは username で最初にソートされ、その後 timestamp でソートされます。
username フィールドの昇順および timestamp フィールドの降順で。
1. これらのコンポジット集約を最適化するために使用できます:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "user_name": {
  9. "terms": {
  10. "field": "user_name"
  11. }
  12. }
  13. }
  14. ]
  15. }
  16. }
  17. },
  18. )
  19. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. user_name: {
  10. terms: {
  11. field: 'user_name'
  12. }
  13. }
  14. }
  15. ]
  16. }
  17. }
  18. }
  19. }
  20. )
  21. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. user_name: {
  9. terms: {
  10. field: "user_name",
  11. },
  12. },
  13. },
  14. ],
  15. },
  16. },
  17. },
  18. });
  19. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "user_name": { "terms": { "field": "user_name" } } }
  9. ]
  10. }
  11. }
  12. }
  13. }
user_name はインデックスソートのプレフィックスであり、順序が一致します(asc)。

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "user_name": {
  9. "terms": {
  10. "field": "user_name"
  11. }
  12. }
  13. },
  14. {
  15. "date": {
  16. "date_histogram": {
  17. "field": "timestamp",
  18. "calendar_interval": "1d",
  19. "order": "desc"
  20. }
  21. }
  22. }
  23. ]
  24. }
  25. }
  26. },
  27. )
  28. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. user_name: {
  10. terms: {
  11. field: 'user_name'
  12. }
  13. }
  14. },
  15. {
  16. date: {
  17. date_histogram: {
  18. field: 'timestamp',
  19. calendar_interval: '1d',
  20. order: 'desc'
  21. }
  22. }
  23. }
  24. ]
  25. }
  26. }
  27. }
  28. }
  29. )
  30. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. user_name: {
  9. terms: {
  10. field: "user_name",
  11. },
  12. },
  13. },
  14. {
  15. date: {
  16. date_histogram: {
  17. field: "timestamp",
  18. calendar_interval: "1d",
  19. order: "desc",
  20. },
  21. },
  22. },
  23. ],
  24. },
  25. },
  26. },
  27. });
  28. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "user_name": { "terms": { "field": "user_name" } } },
  9. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } }
  10. ]
  11. }
  12. }
  13. }
  14. }
user_name はインデックスソートのプレフィックスであり、順序が一致します(asc)。
timestamp もプレフィックスと一致し、順序が一致します(desc)。

早期終了を最適化するために、リクエスト内で track_total_hitsfalse に設定することが推奨されます。リクエストに一致する総ヒット数は最初のリクエストで取得でき、この数をすべてのページで計算するのはコストがかかります。

Python

  1. resp = client.search(
  2. size=0,
  3. track_total_hits=False,
  4. aggs={
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. {
  9. "user_name": {
  10. "terms": {
  11. "field": "user_name"
  12. }
  13. }
  14. },
  15. {
  16. "date": {
  17. "date_histogram": {
  18. "field": "timestamp",
  19. "calendar_interval": "1d",
  20. "order": "desc"
  21. }
  22. }
  23. }
  24. ]
  25. }
  26. }
  27. },
  28. )
  29. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. track_total_hits: false,
  5. aggregations: {
  6. my_buckets: {
  7. composite: {
  8. sources: [
  9. {
  10. user_name: {
  11. terms: {
  12. field: 'user_name'
  13. }
  14. }
  15. },
  16. {
  17. date: {
  18. date_histogram: {
  19. field: 'timestamp',
  20. calendar_interval: '1d',
  21. order: 'desc'
  22. }
  23. }
  24. }
  25. ]
  26. }
  27. }
  28. }
  29. }
  30. )
  31. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. track_total_hits: false,
  4. aggs: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. user_name: {
  10. terms: {
  11. field: "user_name",
  12. },
  13. },
  14. },
  15. {
  16. date: {
  17. date_histogram: {
  18. field: "timestamp",
  19. calendar_interval: "1d",
  20. order: "desc",
  21. },
  22. },
  23. },
  24. ],
  25. },
  26. },
  27. },
  28. });
  29. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "track_total_hits": false,
  5. "aggs": {
  6. "my_buckets": {
  7. "composite": {
  8. "sources": [
  9. { "user_name": { "terms": { "field": "user_name" } } },
  10. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } }
  11. ]
  12. }
  13. }
  14. }
  15. }

ソースの順序は重要であり、以下の例では user_nametimestamp を入れ替えると、ソート最適化が無効になります。この構成はインデックスソート仕様に一致しません。ソースの順序が使用ケースにとって重要でない場合は、次の簡単なガイドラインに従うことができます:

  • 最も高いカーディナリティを持つフィールドを最初に配置します。
  • フィールドの順序がインデックスソートの順序と一致することを確認します。
  • マルチバリューフィールドは最後に配置します。これらは早期終了に使用できません。

index sort はインデックス作成を遅くする可能性があるため、特定の使用ケースとデータセットでインデックスソートをテストして、要件に一致することを確認することが非常に重要です。一致しない場合、composite 集約は、クエリがすべてのドキュメント(match_all クエリ)に一致する場合、ソートされていないインデックスで早期終了を試みることもあります。

サブ集約

multi-bucket 集約と同様に、composite 集約はサブ集約を保持できます。これらのサブ集約は、この親集約によって作成された各コンポジットバケットに対して他のバケットや統計を計算するために使用できます。例えば、次の例は、各コンポジットバケットごとのフィールドの平均値を計算します:

Python

  1. resp = client.search(
  2. size=0,
  3. aggs={
  4. "my_buckets": {
  5. "composite": {
  6. "sources": [
  7. {
  8. "date": {
  9. "date_histogram": {
  10. "field": "timestamp",
  11. "calendar_interval": "1d",
  12. "order": "desc"
  13. }
  14. }
  15. },
  16. {
  17. "product": {
  18. "terms": {
  19. "field": "product"
  20. }
  21. }
  22. }
  23. ]
  24. },
  25. "aggregations": {
  26. "the_avg": {
  27. "avg": {
  28. "field": "price"
  29. }
  30. }
  31. }
  32. }
  33. },
  34. )
  35. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. size: 0,
  4. aggregations: {
  5. my_buckets: {
  6. composite: {
  7. sources: [
  8. {
  9. date: {
  10. date_histogram: {
  11. field: 'timestamp',
  12. calendar_interval: '1d',
  13. order: 'desc'
  14. }
  15. }
  16. },
  17. {
  18. product: {
  19. terms: {
  20. field: 'product'
  21. }
  22. }
  23. }
  24. ]
  25. },
  26. aggregations: {
  27. the_avg: {
  28. avg: {
  29. field: 'price'
  30. }
  31. }
  32. }
  33. }
  34. }
  35. }
  36. )
  37. puts response

Js

  1. const response = await client.search({
  2. size: 0,
  3. aggs: {
  4. my_buckets: {
  5. composite: {
  6. sources: [
  7. {
  8. date: {
  9. date_histogram: {
  10. field: "timestamp",
  11. calendar_interval: "1d",
  12. order: "desc",
  13. },
  14. },
  15. },
  16. {
  17. product: {
  18. terms: {
  19. field: "product",
  20. },
  21. },
  22. },
  23. ],
  24. },
  25. aggregations: {
  26. the_avg: {
  27. avg: {
  28. field: "price",
  29. },
  30. },
  31. },
  32. },
  33. },
  34. });
  35. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_buckets": {
  6. "composite": {
  7. "sources": [
  8. { "date": { "date_histogram": { "field": "timestamp", "calendar_interval": "1d", "order": "desc" } } },
  9. { "product": { "terms": { "field": "product" } } }
  10. ]
  11. },
  12. "aggregations": {
  13. "the_avg": {
  14. "avg": { "field": "price" }
  15. }
  16. }
  17. }
  18. }
  19. }

… 返される:

コンソール-結果

  1. {
  2. ...
  3. "aggregations": {
  4. "my_buckets": {
  5. "after_key": {
  6. "date": 1494201600000,
  7. "product": "rocky"
  8. },
  9. "buckets": [
  10. {
  11. "key": {
  12. "date": 1494460800000,
  13. "product": "apocalypse now"
  14. },
  15. "doc_count": 1,
  16. "the_avg": {
  17. "value": 10.0
  18. }
  19. },
  20. {
  21. "key": {
  22. "date": 1494374400000,
  23. "product": "mad max"
  24. },
  25. "doc_count": 1,
  26. "the_avg": {
  27. "value": 27.0
  28. }
  29. },
  30. {
  31. "key": {
  32. "date": 1494288000000,
  33. "product": "mad max"
  34. },
  35. "doc_count": 2,
  36. "the_avg": {
  37. "value": 22.5
  38. }
  39. },
  40. {
  41. "key": {
  42. "date": 1494201600000,
  43. "product": "rocky"
  44. },
  45. "doc_count": 1,
  46. "the_avg": {
  47. "value": 10.0
  48. }
  49. }
  50. ]
  51. }
  52. }
  53. }

パイプライン集約

コンポジット集約は現在、パイプライン集約と互換性がなく、ほとんどの場合意味がありません。例えば、コンポジット集約のページング特性により、単一の論理パーティション(例えば1日)が複数のページに分散する可能性があります。パイプライン集約は最終的なバケットリストに対する純粋なポストプロセッシングであるため、コンポジットページでの導関数のようなものを実行すると、ページ上の「部分的」結果のみを考慮するため、不正確な結果をもたらす可能性があります。

bucket_selector のように、単一のバケットに自己完結するパイプライン集約は将来的にサポートされる可能性があります。