多様なサンプラー集約

sampler 集約と同様に、これはフィルタリング集約であり、サブ集約の処理を上位スコアのドキュメントのサンプルに制限するために使用されます。diversified_sampler 集約は、共通の値(例えば「著者」)を共有する一致の数を制限する機能を追加します。

優れた市場調査者は、データのサンプルを扱う際には、そのサンプルが特定の声によって偏ることなく、健全な意見の多様性を表すことが重要であると教えてくれます。集約とサンプリングでも同様で、これらの多様化設定を使用することで、コンテンツのバイアスを取り除く方法を提供できます(過剰に人口が集中した地理、タイムラインの大きなスパイク、または過剰に活動するフォーラムのスパム投稿者など)。

使用例:

  • 分析の焦点を高い関連性の一致に絞り、低品質の一致の非常に長い尾を避ける
  • 異なるソースからのコンテンツの公正な表現を確保することで、分析からのバイアスを取り除く
  • サンプルのみを使用して有用な結果を生成できる集約の実行コストを削減する(例: significant_terms

field 設定は、重複排除に使用される値を提供するために使用され、max_docs_per_value 設定は、共通の値を共有する任意のシャードで収集されるドキュメントの最大数を制御します。max_docs_per_value のデフォルト設定は 1 です。

field が単一のドキュメントに対して複数の値を生成する場合、集約はエラーをスローします(効率の懸念から、複数値フィールドを使用した重複排除はサポートされていません)。

例:

StackOverflow フォーラムの投稿で #elasticsearch に強く関連付けられているタグを確認したいが、#Kibana を #Cabana と誤って綴る傾向のある一部の prolific ユーザーの影響を無視したい場合。

Python

  1. resp = client.search(
  2. index="stackoverflow",
  3. size="0",
  4. query={
  5. "query_string": {
  6. "query": "tags:elasticsearch"
  7. }
  8. },
  9. aggs={
  10. "my_unbiased_sample": {
  11. "diversified_sampler": {
  12. "shard_size": 200,
  13. "field": "author"
  14. },
  15. "aggs": {
  16. "keywords": {
  17. "significant_terms": {
  18. "field": "tags",
  19. "exclude": [
  20. "elasticsearch"
  21. ]
  22. }
  23. }
  24. }
  25. }
  26. },
  27. )
  28. print(resp)

Ruby

  1. response = client.search(
  2. index: 'stackoverflow',
  3. size: 0,
  4. body: {
  5. query: {
  6. query_string: {
  7. query: 'tags:elasticsearch'
  8. }
  9. },
  10. aggregations: {
  11. my_unbiased_sample: {
  12. diversified_sampler: {
  13. shard_size: 200,
  14. field: 'author'
  15. },
  16. aggregations: {
  17. keywords: {
  18. significant_terms: {
  19. field: 'tags',
  20. exclude: [
  21. 'elasticsearch'
  22. ]
  23. }
  24. }
  25. }
  26. }
  27. }
  28. }
  29. )
  30. puts response

Js

  1. const response = await client.search({
  2. index: "stackoverflow",
  3. size: 0,
  4. query: {
  5. query_string: {
  6. query: "tags:elasticsearch",
  7. },
  8. },
  9. aggs: {
  10. my_unbiased_sample: {
  11. diversified_sampler: {
  12. shard_size: 200,
  13. field: "author",
  14. },
  15. aggs: {
  16. keywords: {
  17. significant_terms: {
  18. field: "tags",
  19. exclude: ["elasticsearch"],
  20. },
  21. },
  22. },
  23. },
  24. },
  25. });
  26. console.log(response);

コンソール

  1. POST /stackoverflow/_search?size=0
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "tags:elasticsearch"
  6. }
  7. },
  8. "aggs": {
  9. "my_unbiased_sample": {
  10. "diversified_sampler": {
  11. "shard_size": 200,
  12. "field": "author"
  13. },
  14. "aggs": {
  15. "keywords": {
  16. "significant_terms": {
  17. "field": "tags",
  18. "exclude": [ "elasticsearch" ]
  19. }
  20. }
  21. }
  22. }
  23. }
  24. }

応答:

コンソール結果

  1. {
  2. ...
  3. "aggregations": {
  4. "my_unbiased_sample": {
  5. "doc_count": 151,
  6. "keywords": {
  7. "doc_count": 151,
  8. "bg_count": 650,
  9. "buckets": [
  10. {
  11. "key": "kibana",
  12. "doc_count": 150,
  13. "score": 2.213,
  14. "bg_count": 200
  15. }
  16. ]
  17. }
  18. }
  19. }
  20. }
合計で151のドキュメントがサンプリングされました。
重要な_用語集約の結果は、サンプル内の任意の著者からの最大1つの投稿を要求したため、特定の著者の癖によって偏っていません。

スクリプト例

このシナリオでは、フィールド値の組み合わせで多様化を図りたいと考えています。タグフィールド内の複数の値のハッシュを生成するために ランタイムフィールド を使用して、同じ繰り返しのタグの組み合わせからなるサンプルを持たないようにします。

Python

  1. resp = client.search(
  2. index="stackoverflow",
  3. size="0",
  4. query={
  5. "query_string": {
  6. "query": "tags:kibana"
  7. }
  8. },
  9. runtime_mappings={
  10. "tags.hash": {
  11. "type": "long",
  12. "script": "emit(doc['tags'].hashCode())"
  13. }
  14. },
  15. aggs={
  16. "my_unbiased_sample": {
  17. "diversified_sampler": {
  18. "shard_size": 200,
  19. "max_docs_per_value": 3,
  20. "field": "tags.hash"
  21. },
  22. "aggs": {
  23. "keywords": {
  24. "significant_terms": {
  25. "field": "tags",
  26. "exclude": [
  27. "kibana"
  28. ]
  29. }
  30. }
  31. }
  32. }
  33. },
  34. )
  35. print(resp)

Ruby

  1. response = client.search(
  2. index: 'stackoverflow',
  3. size: 0,
  4. body: {
  5. query: {
  6. query_string: {
  7. query: 'tags:kibana'
  8. }
  9. },
  10. runtime_mappings: {
  11. 'tags.hash' => {
  12. type: 'long',
  13. script: "emit(doc['tags'].hashCode())"
  14. }
  15. },
  16. aggregations: {
  17. my_unbiased_sample: {
  18. diversified_sampler: {
  19. shard_size: 200,
  20. max_docs_per_value: 3,
  21. field: 'tags.hash'
  22. },
  23. aggregations: {
  24. keywords: {
  25. significant_terms: {
  26. field: 'tags',
  27. exclude: [
  28. 'kibana'
  29. ]
  30. }
  31. }
  32. }
  33. }
  34. }
  35. }
  36. )
  37. puts response

Js

  1. const response = await client.search({
  2. index: "stackoverflow",
  3. size: 0,
  4. query: {
  5. query_string: {
  6. query: "tags:kibana",
  7. },
  8. },
  9. runtime_mappings: {
  10. "tags.hash": {
  11. type: "long",
  12. script: "emit(doc['tags'].hashCode())",
  13. },
  14. },
  15. aggs: {
  16. my_unbiased_sample: {
  17. diversified_sampler: {
  18. shard_size: 200,
  19. max_docs_per_value: 3,
  20. field: "tags.hash",
  21. },
  22. aggs: {
  23. keywords: {
  24. significant_terms: {
  25. field: "tags",
  26. exclude: ["kibana"],
  27. },
  28. },
  29. },
  30. },
  31. },
  32. });
  33. console.log(response);

コンソール

  1. POST /stackoverflow/_search?size=0
  2. {
  3. "query": {
  4. "query_string": {
  5. "query": "tags:kibana"
  6. }
  7. },
  8. "runtime_mappings": {
  9. "tags.hash": {
  10. "type": "long",
  11. "script": "emit(doc['tags'].hashCode())"
  12. }
  13. },
  14. "aggs": {
  15. "my_unbiased_sample": {
  16. "diversified_sampler": {
  17. "shard_size": 200,
  18. "max_docs_per_value": 3,
  19. "field": "tags.hash"
  20. },
  21. "aggs": {
  22. "keywords": {
  23. "significant_terms": {
  24. "field": "tags",
  25. "exclude": [ "kibana" ]
  26. }
  27. }
  28. }
  29. }
  30. }
  31. }

応答:

コンソール結果

  1. {
  2. ...
  3. "aggregations": {
  4. "my_unbiased_sample": {
  5. "doc_count": 6,
  6. "keywords": {
  7. "doc_count": 6,
  8. "bg_count": 650,
  9. "buckets": [
  10. {
  11. "key": "logstash",
  12. "doc_count": 3,
  13. "score": 2.213,
  14. "bg_count": 50
  15. },
  16. {
  17. "key": "elasticsearch",
  18. "doc_count": 3,
  19. "score": 1.34,
  20. "bg_count": 200
  21. }
  22. ]
  23. }
  24. }
  25. }
  26. }

shard_size

shard_size パラメータは、各シャードで処理されるサンプルに収集される上位スコアのドキュメントの数を制限します。デフォルト値は 100 です。

max_docs_per_value

max_docs_per_value はオプションのパラメータであり、重複排除の値の選択ごとに許可されるドキュメントの数を制限します。デフォルト設定は「1」です。

execution_hint

オプションの execution_hint 設定は、重複排除に使用される値の管理に影響を与える可能性があります。各オプションは、重複排除を実行中にメモリ内に最大 shard_size の値を保持しますが、保持される値のタイプは次のように制御できます:

  • フィールド値を直接保持する(map
  • Lucene インデックスによって決定されたフィールドのオーディナルを保持する(global_ordinals
  • フィールド値のハッシュを保持する - ハッシュ衝突の可能性あり(bytes_hash

デフォルト設定は、Lucene インデックスからこの情報が利用可能な場合は global_ordinals を使用し、そうでない場合は map に戻ります。bytes_hash 設定は、いくつかのケースでより高速である可能性がありますが、ハッシュ衝突の可能性により重複排除ロジックにおいて偽陽性の可能性を導入します。Elasticsearch は、適用できない場合は実行ヒントの選択を無視し、これらのヒントに対して後方互換性の保証はありませんのでご注意ください。

制限事項

幅優先集約の下にネストできません

品質ベースのフィルターである多様化サンプラー集約は、各ドキュメントに対して生成される関連スコアにアクセスする必要があります。したがって、terms 集約の下にネストすることはできません。collect_mode がデフォルトの depth_first モードから breadth_first に切り替わると、スコアが破棄されるためです。この状況ではエラーがスローされます。

制限された重複排除ロジック

重複排除ロジックはシャードレベルでのみ適用されるため、シャード間では適用されません。

地理/日付フィールド用の特別な構文はありません

現在、多様化値を定義するための構文は、field または script の選択によって定義されています - 「7d」(7日)などの地理または日付単位を表現するための追加の構文的な糖衣はありません。このサポートは後のリリースで追加される可能性があり、ユーザーは現在、スクリプトを使用してこの種の値を作成する必要があります。