重要な用語の集約

セット内の用語の興味深いまたは異常な発生を返す集約です。

使用例:

  • ユーザーがテキスト内で「鳥インフルエンザ」を検索したときに「H5N1」を提案する
  • 損失を報告しているクレジットカード所有者の取引履歴から「共通の妥協点」である商人を特定する
  • 自動ニュース分類器のために株式シンボル$ATIに関連するキーワードを提案する
  • 自分の公平な割合以上のむち打ち傷を診断している詐欺的な医者を見つける
  • 異常に多くのバーストを持つタイヤメーカーを見つける

これらのすべてのケースでは、選択される用語は単にセット内で最も人気のある用語ではありません。 それらは、前景セットと背景セットの間で測定された人気の大きな変化を経験した用語です。「H5N1」という用語が1000万のドキュメントインデックスの中で5つのドキュメントにしか存在せず、ユーザーの検索結果を構成する100のドキュメントのうち4つに見つかった場合、それは重要であり、おそらく彼らの検索に非常に関連しています。5/10,000,000対4/100は頻度の大きな変動です。

単一セット分析

最も単純なケースでは、関心のある前景セットはクエリによって一致した検索結果であり、統計的比較に使用される背景セットは結果が収集されたインデックスまたはインデックスです。

例:

Python

  1. resp = client.search(
  2. query={
  3. "terms": {
  4. "force": [
  5. "British Transport Police"
  6. ]
  7. }
  8. },
  9. aggregations={
  10. "significant_crime_types": {
  11. "significant_terms": {
  12. "field": "crime_type"
  13. }
  14. }
  15. },
  16. )
  17. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. query: {
  4. terms: {
  5. force: [
  6. 'British Transport Police'
  7. ]
  8. }
  9. },
  10. aggregations: {
  11. significant_crime_types: {
  12. significant_terms: {
  13. field: 'crime_type'
  14. }
  15. }
  16. }
  17. }
  18. )
  19. puts response

Js

  1. const response = await client.search({
  2. query: {
  3. terms: {
  4. force: ["British Transport Police"],
  5. },
  6. },
  7. aggregations: {
  8. significant_crime_types: {
  9. significant_terms: {
  10. field: "crime_type",
  11. },
  12. },
  13. },
  14. });
  15. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "query": {
  4. "terms": { "force": [ "British Transport Police" ] }
  5. },
  6. "aggregations": {
  7. "significant_crime_types": {
  8. "significant_terms": { "field": "crime_type" }
  9. }
  10. }
  11. }

レスポンス:

コンソール結果

  1. {
  2. ...
  3. "aggregations": {
  4. "significant_crime_types": {
  5. "doc_count": 47347,
  6. "bg_count": 5064554,
  7. "buckets": [
  8. {
  9. "key": "Bicycle theft",
  10. "doc_count": 3640,
  11. "score": 0.371235374214817,
  12. "bg_count": 66799
  13. }
  14. ...
  15. ]
  16. }
  17. }
  18. }

すべての警察機関からのすべての犯罪のインデックスをクエリすると、これらの結果は、英国交通警察が自転車盗難の不均衡に大きな数を扱っていることを示しています。 通常、自転車盗難は犯罪のわずか1%(66799/5064554)を占めますが、鉄道や駅での犯罪を扱う英国交通警察では、犯罪の7%(3640/47347)が自転車盗難です。 これは頻度の大きな七倍の増加であり、この異常は主要な犯罪タイプとして強調されました。

異常を見つけるためにクエリを使用することの問題は、比較に使用するための1つのサブセットしか提供しないことです。 他のすべての警察機関の異常を発見するには、異なる機関ごとにクエリを繰り返す必要があります。

これは、インデックス内の異常なパターンを探すための面倒な方法です。

マルチセット分析

複数のカテゴリにわたる分析を実行するより簡単な方法は、親レベルの集約を使用してデータを分析の準備のためにセグメント化することです。

セグメンテーションのための親集約を使用した例:

Python

  1. resp = client.search(
  2. aggregations={
  3. "forces": {
  4. "terms": {
  5. "field": "force"
  6. },
  7. "aggregations": {
  8. "significant_crime_types": {
  9. "significant_terms": {
  10. "field": "crime_type"
  11. }
  12. }
  13. }
  14. }
  15. },
  16. )
  17. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. aggregations: {
  4. forces: {
  5. terms: {
  6. field: 'force'
  7. },
  8. aggregations: {
  9. significant_crime_types: {
  10. significant_terms: {
  11. field: 'crime_type'
  12. }
  13. }
  14. }
  15. }
  16. }
  17. }
  18. )
  19. puts response

Js

  1. const response = await client.search({
  2. aggregations: {
  3. forces: {
  4. terms: {
  5. field: "force",
  6. },
  7. aggregations: {
  8. significant_crime_types: {
  9. significant_terms: {
  10. field: "crime_type",
  11. },
  12. },
  13. },
  14. },
  15. },
  16. });
  17. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "aggregations": {
  4. "forces": {
  5. "terms": { "field": "force" },
  6. "aggregations": {
  7. "significant_crime_types": {
  8. "significant_terms": { "field": "crime_type" }
  9. }
  10. }
  11. }
  12. }
  13. }

レスポンス:

コンソール結果

  1. {
  2. ...
  3. "aggregations": {
  4. "forces": {
  5. "doc_count_error_upper_bound": 1375,
  6. "sum_other_doc_count": 7879845,
  7. "buckets": [
  8. {
  9. "key": "Metropolitan Police Service",
  10. "doc_count": 894038,
  11. "significant_crime_types": {
  12. "doc_count": 894038,
  13. "bg_count": 5064554,
  14. "buckets": [
  15. {
  16. "key": "Robbery",
  17. "doc_count": 27617,
  18. "score": 0.0599,
  19. "bg_count": 53182
  20. }
  21. ...
  22. ]
  23. }
  24. },
  25. {
  26. "key": "British Transport Police",
  27. "doc_count": 47347,
  28. "significant_crime_types": {
  29. "doc_count": 47347,
  30. "bg_count": 5064554,
  31. "buckets": [
  32. {
  33. "key": "Bicycle theft",
  34. "doc_count": 3640,
  35. "score": 0.371,
  36. "bg_count": 66799
  37. }
  38. ...
  39. ]
  40. }
  41. }
  42. ]
  43. }
  44. }
  45. }

これで、単一のリクエストを使用して各警察機関の異常検出が可能になりました。

地理的エリアでセグメント化して特定の犯罪タイプの異常なホットスポットを特定するために、他の形式のトップレベル集約を使用できます:

Python

  1. resp = client.search(
  2. aggs={
  3. "hotspots": {
  4. "geohash_grid": {
  5. "field": "location",
  6. "precision": 5
  7. },
  8. "aggs": {
  9. "significant_crime_types": {
  10. "significant_terms": {
  11. "field": "crime_type"
  12. }
  13. }
  14. }
  15. }
  16. },
  17. )
  18. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. aggregations: {
  4. hotspots: {
  5. geohash_grid: {
  6. field: 'location',
  7. precision: 5
  8. },
  9. aggregations: {
  10. significant_crime_types: {
  11. significant_terms: {
  12. field: 'crime_type'
  13. }
  14. }
  15. }
  16. }
  17. }
  18. }
  19. )
  20. puts response

Js

  1. const response = await client.search({
  2. aggs: {
  3. hotspots: {
  4. geohash_grid: {
  5. field: "location",
  6. precision: 5,
  7. },
  8. aggs: {
  9. significant_crime_types: {
  10. significant_terms: {
  11. field: "crime_type",
  12. },
  13. },
  14. },
  15. },
  16. },
  17. });
  18. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "aggs": {
  4. "hotspots": {
  5. "geohash_grid": {
  6. "field": "location",
  7. "precision": 5
  8. },
  9. "aggs": {
  10. "significant_crime_types": {
  11. "significant_terms": { "field": "crime_type" }
  12. }
  13. }
  14. }
  15. }
  16. }

この例では、geohash_grid集約を使用して地理的エリアを表す結果バケットを作成し、各バケット内でこれらの厳密に焦点を絞ったエリアにおける犯罪タイプの異常レベルを特定できます。 例えば、

  • 空港では武器の押収が異常に多い
  • 大学では自転車盗難が増加している

より大きなカバレッジエリアを持つ高いgeohash_gridズームレベルでは、全体の警察機関が特定の犯罪タイプの異常な量に取り組んでいる場所が見えてきます。

明らかに、時間ベースのトップレベルセグメンテーションは、単純なterms集約が通常、すべての時間スロットにわたって持続する非常に人気のある「定数」を示す各時点での現在のトレンドを特定するのに役立ちます。

スコアはどのように計算されますか?

スコアに返される数字は、主に異なる提案を合理的にランク付けするために意図されており、エンドユーザーが簡単に理解できるものではありません。 スコアは、前景および背景セットのドキュメント頻度から導出されます。 簡単に言えば、用語は、サブセット内での出現頻度と背景での出現頻度に顕著な違いがある場合に重要と見なされます。 用語のランク付け方法は構成可能であり、「パラメータ」セクションを参照してください。

自由テキストフィールドでの使用

significant_terms集約は、トークン化された自由テキストフィールドで効果的に使用して、次のことを提案できます:

  • エンドユーザーの検索を洗練するためのキーワード
  • パーコレータークエリで使用するキーワード

自由テキストフィールドをsignificant_terms分析の対象として選択することは高価になる可能性があります! すべてのユニークな単語をRAMにロードしようとします。 小さなインデックスでのみ使用することをお勧めします。

「これが好きだが、これは好きではない」パターンを使用する

構造化フィールド(例: category:adultMovie)を最初に検索し、自由テキスト「movie_description」フィールドでsignificant_termsを使用することで、誤分類されたコンテンツを見つけることができます。 提案された単語を取り(想像にお任せします)、「category:adultMovie」としてマークされていないが、これらのキーワードを含むすべての映画を検索します。 これで、再分類するか、少なくとも「familyFriendly」カテゴリから削除すべき誤分類された映画のランク付けリストが得られます。

各用語からの重要性スコアは、マッチをソートするための便利なboost設定を提供することもできます。 キーワードを使用してminimum_should_match設定のtermsクエリを制御することで、結果セットの精度/再現率のバランスを制御できます。つまり、高い設定は関連する結果の数が少なく、キーワードが詰まった結果を生成し、「1」の設定は、任意のキーワードを含むすべてのドキュメントを持つより徹底的な結果セットを生成します。

文脈内でのsignificant_termsの表示自由テキストのsignificant_termsは、文脈で見ると理解しやすくなります。 自由テキストフィールドからのsignificant_terms提案の結果を取り、それを同じフィールドのtermsクエリでhighlight句を使用して、ユーザーにドキュメントの例スニペットを提示します。 用語がステム化されず、強調表示され、正しいケースで、正しい順序で、いくつかの文脈とともに提示されると、その重要性/意味がより明らかになります。

カスタム背景セット

通常、ドキュメントの前景セットは、インデックス内のすべてのドキュメントの背景セットに対して「差分」を取ります。 ただし、比較の基礎としてより狭い背景セットを使用することが有用な場合があります。 たとえば、世界中のコンテンツを含むインデックス内の「マドリード」に関連するドキュメントに対するクエリは、「スペイン」が重要な用語であることを明らかにするかもしれません。 これは真実かもしれませんが、より焦点を絞った用語が必要な場合は、spainという用語にbackground_filterを使用して、文書のより狭いセットをコンテキストとして確立できます。 これを背景として使用すると、「スペイン」は今や一般的な用語と見なされ、したがって「首都」のようなマドリードにより強く関連する単語ほど重要ではなくなります。 背景フィルターを使用すると、すべての用語の投稿をフィルタリングして頻度を決定する必要があるため、処理が遅くなることに注意してください。

制限

重要な用語はインデックスされた値でなければならない

用語の集約とは異なり、現在のところ、カウント目的でスクリプト生成された用語を使用することはできません。 significant_terms集約が前景および背景頻度の両方を考慮する必要があるため、比較のために背景頻度を取得するためにインデックス全体でスクリプトを使用することは非常に高価になります。 また、DocValuesは、同様の理由で用語データのソースとしてサポートされていません。

浮動小数点フィールドの分析は不可

浮動小数点フィールドは、現在、significant_terms分析の対象としてサポートされていません。 整数または長いフィールドは、追跡するのが興味深い銀行口座番号やカテゴリ番号のような概念を表すために使用できますが、浮動小数点フィールドは通常、何かの量を表すために使用されます。 したがって、個々の浮動小数点用語は、この形式の頻度分析には役立ちません。

親集約としての使用

  1. もう1つの考慮事項は、significant_terms集約がシャードレベルで多くの候補結果を生成し、すべてのシャードからの統計がマージされた後にのみ、削減ノードで後でプルーニングされることです。 その結果、後で多くの候補用語を破棄するsignificant_terms集約の下に大きな子集約を埋め込むことは、RAMの観点から非効率的で高価になる可能性があります。 このような場合は、2回の検索を実行することをお勧めします。最初はsignificant_termsの合理化されたリストを提供し、次にこの短縮リストの用語を追加して、必要な子集約を取得するために戻ります。
  2. ### 近似カウント
  3. 結果に提供される用語を含むドキュメントのカウントは、各シャードから返されたサンプルを合計することに基づいており、次のようにすることができます:
  4. - 特定のシャードがそのトップサンプルで特定の用語の数値を提供しなかった場合は低くなる
  5. - 背景頻度を考慮すると高くなる可能性があり、削除されたドキュメントで見つかった出現をカウントする可能性があります
  6. ほとんどの設計上の決定と同様に、これは、いくつかの(通常は小さな)不正確さのコストで高速なパフォーマンスを提供することを選択したトレードオフの基礎です。 ただし、次のセクションで説明する`````size`````および`````shard size`````設定は、精度レベルを制御するためのツールを提供します。
  7. ## パラメータ
  8. ### JLHスコア
  9. JLHスコアは、パラメータを追加することで重要性スコアとして使用できます
  10. #### Js
  11. ``````js
  12. "jlh": {
  13. }
  14. `

スコアは、前景および背景セットのドキュメント頻度から導出されます。 絶対的な人気の変化(foregroundPercent - backgroundPercent)は一般的な用語を好む一方、相対的な人気の変化(foregroundPercent/ backgroundPercent)は希少な用語を好みます。 希少対一般は本質的に精度対再現率のバランスであり、したがって、絶対的および相対的な変化は、精度と再現率の間のスイートスポットを提供するために掛け合わされます。

相互情報

相互情報は、
「情報検索」Manning et al.の第13.5.1章で説明されているように、パラメータを追加することで重要性スコアとして使用できます

Js

  1. "mutual_information": {
  2. "include_negatives": true
  3. }

相互情報は、サブセットの記述的な用語とサブセット外のドキュメントの用語を区別しません。 したがって、重要な用語には、サブセット内での出現頻度が高い用語と、サブセット外での出現頻度が低い用語が含まれる可能性があります。 サブセット内での出現頻度がサブセット外での出現頻度よりも低い用語をフィルタリングするには、include_negativesfalseに設定できます。

デフォルトでは、バケット内のドキュメントは背景にも含まれていると仮定されます。 代わりに、比較したい異なるドキュメントのセットを表すカスタム背景フィルターを定義した場合は、設定してください。

Js

  1. "background_is_superset": false

カイ二乗

カイ二乗は、「情報検索」Manning et al.の第13.5.2章で説明されているように、パラメータを追加することで重要性スコアとして使用できます

Js

  1. "chi_square": {
  2. }

カイ二乗は相互情報のように振る舞い、include_negativesおよびbackground_is_supersetと同じパラメータで構成できます。

Google正規化距離

Google正規化距離は、
「Google類似距離」CilibrasiとVitanyi、2007
で説明されているように、パラメータを追加することで重要性スコアとして使用できます

Js

  1. "gnd": {
  2. }
  1. ### p値スコア
  2. p値は、帰無仮説が正しいと仮定した場合に、実際に観察された結果と同じくらい極端なテスト結果を得る確率です。 p値は、前景セットと背景セットが独立していると仮定して計算されます[ベルヌーイ試行](https://en.wikipedia.org/wiki/Bernoulli_trial)で、確率が同じであるという帰無仮説があります。
  3. #### 使用例
  4. この例では、「失敗に終わった」と「失敗に終わらなかった」という前景セットに対して、用語`````user_agent.version`````p値スコアを計算します。
  5. `````"background_is_superset": false`````は、背景セットが前景セットのカウントを含まないことを示します。
  6. `````"normalize_above": 1000`````は、さまざまなスケールで一貫した重要性結果を返すことを容易にします。 `````1000`````は、`````1000`````より大きい用語カウントが`````1000/term_count`````の因子でスケールダウンされることを示します。
  7. #### Python
  8. ``````python
  9. resp = client.search(
  10. query={
  11. "bool": {
  12. "filter": [
  13. {
  14. "term": {
  15. "event.outcome": "failure"
  16. }
  17. },
  18. {
  19. "range": {
  20. "@timestamp": {
  21. "gte": "2021-02-01",
  22. "lt": "2021-02-04"
  23. }
  24. }
  25. },
  26. {
  27. "term": {
  28. "service.name": {
  29. "value": "frontend-node"
  30. }
  31. }
  32. }
  33. ]
  34. }
  35. },
  36. aggs={
  37. "failure_p_value": {
  38. "significant_terms": {
  39. "field": "user_agent.version",
  40. "background_filter": {
  41. "bool": {
  42. "must_not": [
  43. {
  44. "term": {
  45. "event.outcome": "failure"
  46. }
  47. }
  48. ],
  49. "filter": [
  50. {
  51. "range": {
  52. "@timestamp": {
  53. "gte": "2021-02-01",
  54. "lt": "2021-02-04"
  55. }
  56. }
  57. },
  58. {
  59. "term": {
  60. "service.name": {
  61. "value": "frontend-node"
  62. }
  63. }
  64. }
  65. ]
  66. }
  67. },
  68. "p_value": {
  69. "background_is_superset": False,
  70. "normalize_above": 1000
  71. }
  72. }
  73. }
  74. },
  75. )
  76. print(resp)
  77. `

Ruby

  1. response = client.search(
  2. body: {
  3. query: {
  4. bool: {
  5. filter: [
  6. {
  7. term: {
  8. 'event.outcome' => 'failure'
  9. }
  10. },
  11. {
  12. range: {
  13. "@timestamp": {
  14. gte: '2021-02-01',
  15. lt: '2021-02-04'
  16. }
  17. }
  18. },
  19. {
  20. term: {
  21. 'service.name' => {
  22. value: 'frontend-node'
  23. }
  24. }
  25. }
  26. ]
  27. }
  28. },
  29. aggregations: {
  30. failure_p_value: {
  31. significant_terms: {
  32. field: 'user_agent.version',
  33. background_filter: {
  34. bool: {
  35. must_not: [
  36. {
  37. term: {
  38. 'event.outcome' => 'failure'
  39. }
  40. }
  41. ],
  42. filter: [
  43. {
  44. range: {
  45. "@timestamp": {
  46. gte: '2021-02-01',
  47. lt: '2021-02-04'
  48. }
  49. }
  50. },
  51. {
  52. term: {
  53. 'service.name' => {
  54. value: 'frontend-node'
  55. }
  56. }
  57. }
  58. ]
  59. }
  60. },
  61. p_value: {
  62. background_is_superset: false,
  63. normalize_above: 1000
  64. }
  65. }
  66. }
  67. }
  68. }
  69. )
  70. puts response

Js

  1. const response = await client.search({
  2. query: {
  3. bool: {
  4. filter: [
  5. {
  6. term: {
  7. "event.outcome": "failure",
  8. },
  9. },
  10. {
  11. range: {
  12. "@timestamp": {
  13. gte: "2021-02-01",
  14. lt: "2021-02-04",
  15. },
  16. },
  17. },
  18. {
  19. term: {
  20. "service.name": {
  21. value: "frontend-node",
  22. },
  23. },
  24. },
  25. ],
  26. },
  27. },
  28. aggs: {
  29. failure_p_value: {
  30. significant_terms: {
  31. field: "user_agent.version",
  32. background_filter: {
  33. bool: {
  34. must_not: [
  35. {
  36. term: {
  37. "event.outcome": "failure",
  38. },
  39. },
  40. ],
  41. filter: [
  42. {
  43. range: {
  44. "@timestamp": {
  45. gte: "2021-02-01",
  46. lt: "2021-02-04",
  47. },
  48. },
  49. },
  50. {
  51. term: {
  52. "service.name": {
  53. value: "frontend-node",
  54. },
  55. },
  56. },
  57. ],
  58. },
  59. },
  60. p_value: {
  61. background_is_superset: false,
  62. normalize_above: 1000,
  63. },
  64. },
  65. },
  66. },
  67. });
  68. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "query": {
  4. "bool": {
  5. "filter": [
  6. {
  7. "term": {
  8. "event.outcome": "failure"
  9. }
  10. },
  11. {
  12. "range": {
  13. "@timestamp": {
  14. "gte": "2021-02-01",
  15. "lt": "2021-02-04"
  16. }
  17. }
  18. },
  19. {
  20. "term": {
  21. "service.name": {
  22. "value": "frontend-node"
  23. }
  24. }
  25. }
  26. ]
  27. }
  28. },
  29. "aggs": {
  30. "failure_p_value": {
  31. "significant_terms": {
  32. "field": "user_agent.version",
  33. "background_filter": {
  34. "bool": {
  35. "must_not": [
  36. {
  37. "term": {
  38. "event.outcome": "failure"
  39. }
  40. }
  41. ],
  42. "filter": [
  43. {
  44. "range": {
  45. "@timestamp": {
  46. "gte": "2021-02-01",
  47. "lt": "2021-02-04"
  48. }
  49. }
  50. },
  51. {
  52. "term": {
  53. "service.name": {
  54. "value": "frontend-node"
  55. }
  56. }
  57. }
  58. ]
  59. }
  60. },
  61. "p_value": {"background_is_superset": false, "normalize_above": 1000}
  62. }
  63. }
  64. }
  65. }

パーセンテージ

用語を含む前景サンプル内のドキュメントの数を、用語を含む背景内のドキュメントの数で割った単純な計算です。 デフォルトでは、これにより0より大きく1より小さいスコアが生成されます。

このヒューリスティックの利点は、スコアリングロジックが「一人当たり」統計に精通している人に簡単に説明できることです。 ただし、高いカーディナリティのフィールドでは、このヒューリスティックが、1回だけ発生するタイプミスなどの最も希少な用語を選択する傾向があります。

経験豊富なボクサーが、勝った試合の割合に基づいて賞を授与される場合、チャンピオンシップに勝つのは難しいでしょう。 これらのルールでは、1回の試合しかない新人が勝つことは不可能です。 見解を強化するには通常、複数の観察が必要であるため、これらのケースではmin_doc_countshard_min_doc_countの両方を10などの高い値に設定して、そうでなければ優先される低頻度の用語をフィルタリングすることをお勧めします。

Js

  1. "percentage": {
  2. }

どれが最適ですか?

おおよそ、mutual_informationは、背景でも頻繁に発生する場合でも、高頻度の用語を好みます。 たとえば、自然言語テキストの分析では、ストップワードの選択につながる可能性があります。 mutual_informationは、誤字のような非常に希少な用語を選択する可能性は低いです。 gndは、高い共起を持つ用語を好み、ストップワードの選択を避けます。 同義語検出により適しているかもしれません。 ただし、gndは、たとえば、誤字の結果として非常に希少な用語を選択する傾向があります。 chi_squarejlhは、やや中間的です。

異なるヒューリスティックのどれが最良の選択であるかを判断するのは難しいです。なぜなら、それは重要な用語が何に使用されるかに依存するからです(たとえば、Yang and Pedersen、「テキスト分類における特徴選択に関する比較研究」、1997を参照して、テキスト分類のための特徴選択に重要な用語を使用する研究)。

上記のいずれの測定も使用ケースに適さない場合は、カスタム重要性測定を実装する別のオプションがあります。

スクリプト化

カスタマイズされたスコアは、スクリプトを介して実装できます:

Js

  1. "script_heuristic": {
  2. "script": {
  3. "lang": "painless",
  4. "source": "params._subset_freq/(params._superset_freq - params._subset_freq + 1)"
  5. }
  6. }

スクリプトは、インライン(上記の例のように)、インデックス化、またはディスクに保存できます。 オプションの詳細については、スクリプトドキュメントを参照してください。

スクリプト内で利用可能なパラメータは

_subset_freq サブセット内で用語が出現するドキュメントの数。
_superset_freq スーパーセット内で用語が出現するドキュメントの数。
_subset_size サブセット内のドキュメントの数。
_superset_size スーパーセット内のドキュメントの数。

サイズとシャードサイズ

sizeパラメータは、全体の用語リストから返される用語バケットの数を定義するために設定できます。 デフォルトでは、検索プロセスを調整するノードは、各シャードに自分のトップ用語バケットを提供するように要求し、すべてのシャードが応答すると、最終的なリストに結果を減らし、クライアントに返されます。 ユニークな用語の数がsizeを超える場合、返されるリストはわずかにオフになり、正確でない可能性があります(用語カウントがわずかにオフになっている可能性があり、トップサイズバケットに含まれるべき用語が返されない可能性があります)。

より良い精度を確保するために、最終sizeの倍数が、各シャードから要求する用語の数(2 * (size * 1.5 + 10))として使用されます。 この設定を手動で制御するには、shard_sizeパラメータを使用して、各シャードによって生成される候補用語のボリュームを制御できます。

低頻度の用語は、すべての結果が結合されると最も興味深いものになる可能性があるため、significant_terms集約は、shard_sizeパラメータがsize設定よりもかなり高い値に設定されているときに、より高品質の結果を生成できます。 これにより、有望な候補用語のより大きなボリュームが、最終選択の前に削減ノードによって統合的にレビューされることが保証されます。 明らかに、大きな候補用語リストは追加のネットワークトラフィックとRAM使用を引き起こすため、これはバランスを取る必要がある品質/コストのトレードオフです。 shard_sizeが-1(デフォルト)に設定されている場合、shard_sizeはシャードの数とsizeパラメータに基づいて自動的に推定されます。

shard_sizesizeより小さくすることはできません(あまり意味がありません)。 それがそうである場合、Elasticsearchはそれを上書きし、sizeと等しくリセットします。

最小ドキュメントカウント

設定されたヒット数を超える用語のみを返すことが可能です。min_doc_countオプションを使用します:

Python

  1. resp = client.search(
  2. aggs={
  3. "tags": {
  4. "significant_terms": {
  5. "field": "tag",
  6. "min_doc_count": 10
  7. }
  8. }
  9. },
  10. )
  11. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. aggregations: {
  4. tags: {
  5. significant_terms: {
  6. field: 'tag',
  7. min_doc_count: 10
  8. }
  9. }
  10. }
  11. }
  12. )
  13. puts response

Js

  1. const response = await client.search({
  2. aggs: {
  3. tags: {
  4. significant_terms: {
  5. field: "tag",
  6. min_doc_count: 10,
  7. },
  8. },
  9. },
  10. });
  11. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "aggs": {
  4. "tags": {
  5. "significant_terms": {
  6. "field": "tag",
  7. "min_doc_count": 10
  8. }
  9. }
  10. }
  11. }

上記の集約は、10回以上見つかったタグのみを返します。 デフォルト値は3です。

スコアが高い用語はシャードレベルで収集され、2回目のステップで他のシャードから収集された用語とマージされます。 ただし、シャードはグローバルな用語頻度に関する情報を持っていません。 用語が候補リストに追加されるかどうかの決定は、ローカルシャード頻度を使用してシャード上で計算されたスコアのみに依存し、単語のグローバル頻度には依存しません。 min_doc_count基準は、すべてのシャードのローカル用語統計をマージした後にのみ適用されます。 ある意味で、候補として用語を追加する決定は、用語が実際に必要なmin_doc_countに達するかどうかについてあまり確信がない状態で行われます。 これにより、低頻度だが高スコアの用語が候補リストを占める場合、最終結果に多くの(グローバルに)高頻度の用語が欠落する可能性があります。 これを避けるために、shard_sizeパラメータを増やして、シャード上の候補用語をより多く許可できます。 ただし、これによりメモリ消費とネットワークトラフィックが増加します。

shard_min_doc_count

shard_min_doc_countパラメータは、用語が候補リストに追加されるべきかどうかに関するシャードの確信を調整します。 用語は、セット内のローカルシャード頻度がmin_doc_countより高い場合にのみ考慮されます。 辞書に多くの低頻度の用語が含まれており、それに興味がない場合(たとえば、誤字など)、shard_min_doc_countパラメータを設定して、ローカルカウントをマージした後でも、min_doc_countに達しない可能性が高い候補用語をシャードレベルでフィルタリングできます。 shard_min_doc_countはデフォルトで0に設定されており、明示的に設定しない限り効果はありません。

min_doc_count1に設定することは一般的に推奨されません。なぜなら、誤字や他の奇妙な好奇心を返す傾向があるからです。 用語の複数のインスタンスを見つけることは、まだ希少であるが、用語が一度限りの事故の結果ではないことを強化するのに役立ちます。 最小証拠の重みを提供するためにデフォルト値は3が使用されます。 shard_min_doc_countを高く設定しすぎると、重要な候補用語がシャードレベルでフィルタリングされる可能性があります。 この値はmin_doc_count/#shardsよりもかなり低く設定する必要があります。

カスタム背景コンテキスト

背景用語頻度の統計情報のデフォルトソースはインデックス全体であり、この範囲はbackground_filterを使用して、より狭いコンテキスト内の重要な用語に焦点を合わせることで狭めることができます:

Python

  1. resp = client.search(
  2. query={
  3. "match": {
  4. "city": "madrid"
  5. }
  6. },
  7. aggs={
  8. "tags": {
  9. "significant_terms": {
  10. "field": "tag",
  11. "background_filter": {
  12. "term": {
  13. "text": "spain"
  14. }
  15. }
  16. }
  17. }
  18. },
  19. )
  20. print(resp)

Ruby

  1. response = client.search(
  2. body: {
  3. query: {
  4. match: {
  5. city: 'madrid'
  6. }
  7. },
  8. aggregations: {
  9. tags: {
  10. significant_terms: {
  11. field: 'tag',
  12. background_filter: {
  13. term: {
  14. text: 'spain'
  15. }
  16. }
  17. }
  18. }
  19. }
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.search({
  2. query: {
  3. match: {
  4. city: "madrid",
  5. },
  6. },
  7. aggs: {
  8. tags: {
  9. significant_terms: {
  10. field: "tag",
  11. background_filter: {
  12. term: {
  13. text: "spain",
  14. },
  15. },
  16. },
  17. },
  18. },
  19. });
  20. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "query": {
  4. "match": {
  5. "city": "madrid"
  6. }
  7. },
  8. "aggs": {
  9. "tags": {
  10. "significant_terms": {
  11. "field": "tag",
  12. "background_filter": {
  13. "term": { "text": "spain" }
  14. }
  15. }
  16. }
  17. }
  18. }

上記のフィルターは、世界中のインデックスのコンテキストでは異常であるが、「スペイン」という単語を含む文書のサブセットでは一般的な「スペイン」という用語を明らかにするのではなく、マドリード市に特有の用語に焦点を合わせるのに役立ちます。

背景フィルターの使用は、各用語の投稿をフィルタリングして頻度を決定する必要があるため、クエリを遅くします。

値のフィルタリング

バケットが作成される値をフィルタリングすることは可能ですが(ただし、めったに必要ではありません)、これは正規表現文字列または正確な用語の配列に基づいてincludeおよびexcludeパラメータを使用して行うことができます。 この機能は、terms aggregationドキュメントで説明されている機能を反映しています。

収集モード

メモリの問題を避けるために、significant_terms集約は常にbreadth_firstモードで子集約を計算します。 異なる収集モードの説明は、terms aggregationドキュメントで見つけることができます。

実行ヒント

用語集約を実行するためのさまざまなメカニズムがあります:

  • バケットごとにデータを集約するためにフィールド値を直接使用する(map
  • フィールドのグローバルオーディナルを使用し、グローバルオーディナルごとに1つのバケットを割り当てる(global_ordinals

Elasticsearchは、合理的なデフォルトを持つように努めているため、これは一般的に構成する必要はありません。

  1. `````map`````は、クエリに一致するドキュメントが非常に少ない場合にのみ考慮されるべきです。 そうでなければ、オーディナルベースの実行モードは大幅に高速です。 デフォルトでは、`````map`````はスクリプトで集約を実行する場合にのみ使用されます。スクリプトにはオーディナルがないためです。
  2. #### Python
  3. ``````python
  4. resp = client.search(
  5. aggs={
  6. "tags": {
  7. "significant_terms": {
  8. "field": "tags",
  9. "execution_hint": "map"
  10. }
  11. }
  12. },
  13. )
  14. print(resp)
  15. `

Ruby

  1. response = client.search(
  2. body: {
  3. aggregations: {
  4. tags: {
  5. significant_terms: {
  6. field: 'tags',
  7. execution_hint: 'map'
  8. }
  9. }
  10. }
  11. }
  12. )
  13. puts response

Js

  1. const response = await client.search({
  2. aggs: {
  3. tags: {
  4. significant_terms: {
  5. field: "tags",
  6. execution_hint: "map",
  7. },
  8. },
  9. },
  10. });
  11. console.log(response);

コンソール

  1. GET /_search
  2. {
  3. "aggs": {
  4. "tags": {
  5. "significant_terms": {
  6. "field": "tags",
  7. "execution_hint": "map"
  8. }
  9. }
  10. }
  11. }
可能な値はmapglobal_ordinalsです。

Elasticsearchは、適用できない場合、この実行ヒントを無視しますのでご注意ください。