重要なテキスト集約

セット内の自由テキスト用語の興味深いまたは異常な発生を返す集約です。これは 重要な用語 集約に似ていますが、以下の点で異なります:

  • text フィールドに特化して設計されています
  • フィールドデータやドキュメント値を必要としません
  • テキストコンテンツをその場で再分析し、統計を歪める傾向のあるノイズの多いテキストの重複セクションをフィルタリングできます。

大きな結果セットの再分析には多くの時間とメモリが必要です。重要なテキスト集約は、サンプラー または 多様化サンプラー 集約の子として使用することをお勧めします。これにより、分析が小さな選択肢の上位一致ドキュメント(例:200)に制限されます。これにより、通常、速度、メモリ使用量、結果の質が向上します。

使用例:

  • ユーザーが「鳥インフルエンザ」を検索したときに「H5N1」を提案してクエリを拡張するのを助ける
  • 自動ニュース分類器で使用するために株式シンボル $ATI に関連するキーワードを提案する

これらのケースでは、選択される単語は単に結果の中で最も人気のある用語ではありません。最も人気のある単語は非常に退屈な傾向があります(and, of, the, we, I, they …)。重要な単語は、前景背景のセット間で人気に顕著な変化があったものです。「H5N1」という用語が1000万ドキュメントのインデックスの中で5つのドキュメントにしか存在せず、ユーザーの検索結果を構成する100のドキュメントのうち4つに見つかった場合、それは重要であり、彼らの検索に非常に関連している可能性があります。5/10,000,000 対 4/100 は頻度の大きな変動です。

基本的な使用法

典型的な使用ケースでは、前景の関心のあるセットはクエリの上位一致検索結果の選択であり、統計的比較に使用される背景のセットは、結果が収集されたインデックスまたはインデックス群です。

例:

Python

  1. resp = client.search(
  2. index="news",
  3. query={
  4. "match": {
  5. "content": "Bird flu"
  6. }
  7. },
  8. aggregations={
  9. "my_sample": {
  10. "sampler": {
  11. "shard_size": 100
  12. },
  13. "aggregations": {
  14. "keywords": {
  15. "significant_text": {
  16. "field": "content"
  17. }
  18. }
  19. }
  20. }
  21. },
  22. )
  23. print(resp)

Ruby

  1. response = client.search(
  2. index: 'news',
  3. body: {
  4. query: {
  5. match: {
  6. content: 'Bird flu'
  7. }
  8. },
  9. aggregations: {
  10. my_sample: {
  11. sampler: {
  12. shard_size: 100
  13. },
  14. aggregations: {
  15. keywords: {
  16. significant_text: {
  17. field: 'content'
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }
  24. )
  25. puts response

Js

  1. const response = await client.search({
  2. index: "news",
  3. query: {
  4. match: {
  5. content: "Bird flu",
  6. },
  7. },
  8. aggregations: {
  9. my_sample: {
  10. sampler: {
  11. shard_size: 100,
  12. },
  13. aggregations: {
  14. keywords: {
  15. significant_text: {
  16. field: "content",
  17. },
  18. },
  19. },
  20. },
  21. },
  22. });
  23. console.log(response);

コンソール

  1. GET news/_search
  2. {
  3. "query": {
  4. "match": { "content": "Bird flu" }
  5. },
  6. "aggregations": {
  7. "my_sample": {
  8. "sampler": {
  9. "shard_size": 100
  10. },
  11. "aggregations": {
  12. "keywords": {
  13. "significant_text": { "field": "content" }
  14. }
  15. }
  16. }
  17. }
  18. }

応答:

コンソール結果

  1. {
  2. "took": 9,
  3. "timed_out": false,
  4. "_shards": ...,
  5. "hits": ...,
  6. "aggregations" : {
  7. "my_sample": {
  8. "doc_count": 100,
  9. "keywords" : {
  10. "doc_count": 100,
  11. "buckets" : [
  12. {
  13. "key": "h5n1",
  14. "doc_count": 4,
  15. "score": 4.71235374214817,
  16. "bg_count": 5
  17. }
  18. ...
  19. ]
  20. }
  21. }
  22. }
  23. }

結果は「h5n1」が鳥インフルエンザに強く関連するいくつかの用語の1つであることを示しています。私たちのインデックス全体では5回しか発生せず(bg_countを参照)、それでも「鳥インフルエンザ」結果の100ドキュメントサンプルのうち4つに幸運にも現れました。これは重要な単語を示唆しており、ユーザーが検索に追加する可能性があります。

filter_duplicate_textを使用したノイズデータの処理

自由テキストフィールドには、元のコンテンツとテキストの機械的コピー(カット&ペーストの伝記、メール返信チェーン、リツイート、ボイラープレートのヘッダー/フッター、ページナビゲーションメニュー、サイドバーのニュースリンク、著作権通知、標準的な免責事項、住所)が混在していることがよくあります。

実際のデータでは、これらの重複したテキストセクションは、フィルタリングされない限り、significant_textの結果に多く見られます。ほぼ重複したテキストをフィルタリングすることはインデックス時に難しい作業ですが、filter_duplicate_text設定を使用してクエリ時にデータをその場でクレンジングできます。

まず、さまざまなニュースをカバーする100万件のニュース記事のSignalメディアデータセットを使用したフィルタリングされていない実世界の例を見てみましょう。「elasticsearch」に言及する記事の検索結果の生の重要なテキスト結果は次のとおりです:

Js

  1. {
  2. ...
  3. "aggregations": {
  4. "sample": {
  5. "doc_count": 35,
  6. "keywords": {
  7. "doc_count": 35,
  8. "buckets": [
  9. {
  10. "key": "elasticsearch",
  11. "doc_count": 35,
  12. "score": 28570.428571428572,
  13. "bg_count": 35
  14. },
  15. ...
  16. {
  17. "key": "currensee",
  18. "doc_count": 8,
  19. "score": 6530.383673469388,
  20. "bg_count": 8
  21. },
  22. ...
  23. {
  24. "key": "pozmantier",
  25. "doc_count": 4,
  26. "score": 3265.191836734694,
  27. "bg_count": 4
  28. },
  29. ...
  30. }

クレンジングされていないドキュメントは、表面的には統計的に「elasticsearch」の出現と相関しているように見える奇妙な用語をいくつか示しています(例:「pozmantier」)。これらのドキュメントの例を掘り下げて、なぜpozmantierがこのクエリと関連しているのかを見てみましょう:

Python

  1. resp = client.search(
  2. index="news",
  3. query={
  4. "simple_query_string": {
  5. "query": "+elasticsearch +pozmantier"
  6. }
  7. },
  8. source=[
  9. "title",
  10. "source"
  11. ],
  12. highlight={
  13. "fields": {
  14. "content": {}
  15. }
  16. },
  17. )
  18. print(resp)

Ruby

  1. response = client.search(
  2. index: 'news',
  3. body: {
  4. query: {
  5. simple_query_string: {
  6. query: '+elasticsearch +pozmantier'
  7. }
  8. },
  9. _source: [
  10. 'title',
  11. 'source'
  12. ],
  13. highlight: {
  14. fields: {
  15. content: {}
  16. }
  17. }
  18. }
  19. )
  20. puts response

Js

  1. const response = await client.search({
  2. index: "news",
  3. query: {
  4. simple_query_string: {
  5. query: "+elasticsearch +pozmantier",
  6. },
  7. },
  8. _source: ["title", "source"],
  9. highlight: {
  10. fields: {
  11. content: {},
  12. },
  13. },
  14. });
  15. console.log(response);

コンソール

  1. GET news/_search
  2. {
  3. "query": {
  4. "simple_query_string": {
  5. "query": "+elasticsearch +pozmantier"
  6. }
  7. },
  8. "_source": [
  9. "title",
  10. "source"
  11. ],
  12. "highlight": {
  13. "fields": {
  14. "content": {}
  15. }
  16. }
  17. }

結果は、いくつかの技術プロジェクトの審査委員会に関する非常に似たニュース記事のシリーズを示しています:

Js

  1. {
  2. ...
  3. "hits": {
  4. "hits": [
  5. {
  6. ...
  7. "_source": {
  8. "source": "Presentation Master",
  9. "title": "T.E.N. Announces Nominees for the 2015 ISE® North America Awards"
  10. },
  11. "highlight": {
  12. "content": [
  13. "City of San Diego Mike <em>Pozmantier</em>, Program Manager, Cyber Security Division, Department of",
  14. " Janus, Janus <em>ElasticSearch</em> Security Visualization Engine "
  15. ]
  16. }
  17. },
  18. {
  19. ...
  20. "_source": {
  21. "source": "RCL Advisors",
  22. "title": "T.E.N. Announces Nominees for the 2015 ISE(R) North America Awards"
  23. },
  24. "highlight": {
  25. "content": [
  26. "Mike <em>Pozmantier</em>, Program Manager, Cyber Security Division, Department of Homeland Security S&T",
  27. "Janus, Janus <em>ElasticSearch</em> Security Visualization Engine"
  28. ]
  29. }
  30. },
  31. ...

マイク・ポズマンティアは、多くの審査員の一人であり、elasticsearchは審査される多くのプロジェクトの一つで使用されました。

通常のように、この長いプレスリリースはさまざまなニュースサイトによってカット&ペーストされ、その結果、含まれる珍しい名前、数字、または誤字は、私たちの一致するクエリと統計的に相関することになります。

幸いなことに、類似のドキュメントは類似のランクを持つ傾向があるため、上位一致ドキュメントのストリームを調査する一環として、重要なテキスト集約は、すでに見たトークンのシーケンスを削除するフィルターを適用できます。では、filter_duplicate_text設定をオンにして、この同じクエリを試してみましょう:

Python

  1. resp = client.search(
  2. index="news",
  3. query={
  4. "match": {
  5. "content": "elasticsearch"
  6. }
  7. },
  8. aggs={
  9. "sample": {
  10. "sampler": {
  11. "shard_size": 100
  12. },
  13. "aggs": {
  14. "keywords": {
  15. "significant_text": {
  16. "field": "content",
  17. "filter_duplicate_text": True
  18. }
  19. }
  20. }
  21. }
  22. },
  23. )
  24. print(resp)

Ruby

  1. response = client.search(
  2. index: 'news',
  3. body: {
  4. query: {
  5. match: {
  6. content: 'elasticsearch'
  7. }
  8. },
  9. aggregations: {
  10. sample: {
  11. sampler: {
  12. shard_size: 100
  13. },
  14. aggregations: {
  15. keywords: {
  16. significant_text: {
  17. field: 'content',
  18. filter_duplicate_text: true
  19. }
  20. }
  21. }
  22. }
  23. }
  24. }
  25. )
  26. puts response

Js

  1. const response = await client.search({
  2. index: "news",
  3. query: {
  4. match: {
  5. content: "elasticsearch",
  6. },
  7. },
  8. aggs: {
  9. sample: {
  10. sampler: {
  11. shard_size: 100,
  12. },
  13. aggs: {
  14. keywords: {
  15. significant_text: {
  16. field: "content",
  17. filter_duplicate_text: true,
  18. },
  19. },
  20. },
  21. },
  22. },
  23. });
  24. console.log(response);

コンソール

  1. GET news/_search
  2. {
  3. "query": {
  4. "match": {
  5. "content": "elasticsearch"
  6. }
  7. },
  8. "aggs": {
  9. "sample": {
  10. "sampler": {
  11. "shard_size": 100
  12. },
  13. "aggs": {
  14. "keywords": {
  15. "significant_text": {
  16. "field": "content",
  17. "filter_duplicate_text": true
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }

重複を排除したテキストの分析から得られた結果は、elastic stackに精通している人にとっては明らかに高品質です:

Js

  1. {
  2. ...
  3. "aggregations": {
  4. "sample": {
  5. "doc_count": 35,
  6. "keywords": {
  7. "doc_count": 35,
  8. "buckets": [
  9. {
  10. "key": "elasticsearch",
  11. "doc_count": 22,
  12. "score": 11288.001166180758,
  13. "bg_count": 35
  14. },
  15. {
  16. "key": "logstash",
  17. "doc_count": 3,
  18. "score": 1836.648979591837,
  19. "bg_count": 4
  20. },
  21. {
  22. "key": "kibana",
  23. "doc_count": 3,
  24. "score": 1469.3020408163263,
  25. "bg_count": 5
  26. }
  27. ]
  28. }
  29. }
  30. }
  31. }

ポズマンティア氏やelasticsearchとの他の一時的な関連は、コピー&ペースト操作や他の機械的な繰り返しの結果として集約結果に現れなくなりました。

重複またはほぼ重複するコンテンツが単一値のインデックスフィールド(おそらく記事のtitleテキストのハッシュまたはoriginal_press_release_urlフィールド)を介して識別可能であれば、親の多様化サンプラー集約を使用して、単一のキーに基づいてサンプルセットからこれらのドキュメントを排除する方が効率的です。重要なテキスト集約に前もって重複コンテンツを供給するほど、パフォーマンスが向上します。

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

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

「これと同じだが、これは違う」パターンを使用する

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

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

制限事項

子集約のサポートなし

重要なテキスト集約は、意図的に子集約の追加をサポートしていません。理由は以下の通りです:

  • 高いメモリコストが伴います
  • 一般的に有用な機能ではなく、必要な場合の回避策があります

候補用語のボリュームは一般的に非常に高く、最終結果が返される前にこれらは厳しく剪定されます。子集約をサポートすると、追加の混乱が生じ、非効率的になります。クライアントは、significant_textリクエストから得られた厳しく剪定された結果セットを常に取得し、その後、terms集約を使用してinclude句と子集約を持つフォローアップクエリを行い、選択したキーワードのさらなる分析をより効率的に行うことができます。

ネストされたオブジェクトのサポートなし

重要なテキスト集約は、現在、ネストされたオブジェクトのテキストフィールドと一緒に使用することもできません。なぜなら、これはドキュメントのJSONソースで機能するからです。これにより、一致するLucene docIDから保存されたJSONのネストされたドキュメントを一致させる際に、この機能が非効率的になります。

近似カウント

結果に提供される用語を含むドキュメントのカウントは、各シャードから返されたサンプルを合計することに基づいており、次のような場合があります:

  • 特定のシャードがその上位サンプルで特定の用語の数値を提供しなかった場合、低くなる可能性があります
  • 背景頻度を考慮すると、高くなる可能性があります。削除されたドキュメントで見つかった出現をカウントする可能性があります

ほとんどの設計決定と同様に、これは、いくつかの(通常は小さな)不正確さのコストで高速なパフォーマンスを提供することを選択したトレードオフの基礎です。ただし、次のセクションで説明するsizeおよびshard size設定は、精度レベルを制御するためのツールを提供します。

パラメータ

重要度ヒューリスティックス

この集約は、重要な用語集約と同じスコアリングヒューリスティックス(JLH、相互情報、gnd、カイ二乗など)をサポートしています。

サイズとシャードサイズ

  1. より良い精度を確保するために、最終`````size`````の倍数が各シャードから要求する用語の数として使用されます(`````2 * (size * 1.5 + 10)`````)。この設定を手動で制御するには、`````shard_size`````パラメータを使用して、各シャードによって生成される候補用語のボリュームを制御できます。
  2. 低頻度の用語は、すべての結果が結合されると最も興味深いものになる可能性があるため、`````shard_size`````パラメータが`````size`````設定よりもかなり高い値に設定されている場合、重要な用語集約はより高品質の結果を生成できます。これにより、有望な候補用語のより大きなボリュームが、最終選択の前に減少ノードによって統合的にレビューされます。明らかに、大きな候補用語リストは追加のネットワークトラフィックとRAM使用量を引き起こすため、これは品質/コストのトレードオフであり、バランスを取る必要があります。`````shard_size`````が-1(デフォルト)に設定されている場合、`````shard_size`````はシャードの数と`````size`````パラメータに基づいて自動的に推定されます。
  3. `````shard_size``````````size`````より小さくすることはできません(あまり意味がありません)。そうなった場合、elasticsearchはそれを上書きし、`````size`````と等しくリセットします。
  4. ### 最小ドキュメント数
  5. 設定されたヒット数を超える用語のみを返すことが可能です。`````min_doc_count`````オプションを使用します。デフォルト値は3です。
  6. スコアが高い用語はシャードレベルで収集され、他のシャードから収集された用語と2段階目でマージされます。ただし、シャードはグローバルな用語頻度に関する情報を持っていません。用語が候補リストに追加されるかどうかの決定は、ローカルシャード頻度を使用してシャード上で計算されたスコアのみに依存し、単語のグローバル頻度には依存しません。`````min_doc_count`````基準は、すべてのシャードのローカル用語統計をマージした後にのみ適用されます。ある意味で、候補として用語を追加する決定は、その用語が実際に必要な`````min_doc_count`````に達するかどうかについてあまり*確信*が持てない状態で行われます。これにより、低頻度だが高スコアの用語が候補リストを占める場合、最終結果に多くの(グローバルに)高頻度の用語が欠落する可能性があります。これを避けるために、`````shard_size`````パラメータを増やして、シャード上でより多くの候補用語を許可できます。ただし、これによりメモリ消費とネットワークトラフィックが増加します。
  7. #### shard_min_doc_count
  8. パラメータ`````shard_min_doc_count`````は、用語が候補リストに追加されるべきかどうかに関するシャードの*確信*を調整します。`````min_doc_count`````に関して。用語は、セット内のローカルシャード頻度が`````shard_min_doc_count`````より高い場合にのみ考慮されます。辞書に多くの低頻度の用語が含まれており、それに興味がない場合(たとえば、誤字など)、`````shard_min_doc_count`````パラメータを設定して、ローカルカウントをマージした後に必要な`````min_doc_count`````に達しないと合理的に確信できない候補用語をシャードレベルでフィルタリングできます。`````shard_min_doc_count`````はデフォルトで`````0`````に設定されており、明示的に設定しない限り効果はありません。
  9. `````min_doc_count``````````1`````に設定することは一般的に推奨されません。なぜなら、誤字や他の奇妙な好奇心を返す傾向があるからです。用語のインスタンスが1つ以上見つかることは、まだ珍しいが、その用語が一度限りの事故の結果ではないことを強化するのに役立ちます。デフォルト値は3で、最小の証拠の重みを提供します。`````shard_min_doc_count`````を高く設定しすぎると、重要な候補用語がシャードレベルでフィルタリングされることになります。この値は`````min_doc_count/#shards`````よりもかなり低く設定する必要があります。
  10. ### カスタム背景コンテキスト
  11. 背景用語頻度の統計情報のデフォルトソースは全体のインデックスであり、この範囲は`````background_filter`````を使用して狭めることができ、より狭いコンテキスト内の重要な用語に焦点を当てることができます:
  12. #### Python
  13. ``````python
  14. resp = client.search(
  15. index="news",
  16. query={
  17. "match": {
  18. "content": "madrid"
  19. }
  20. },
  21. aggs={
  22. "tags": {
  23. "significant_text": {
  24. "field": "content",
  25. "background_filter": {
  26. "term": {
  27. "content": "spain"
  28. }
  29. }
  30. }
  31. }
  32. },
  33. )
  34. print(resp)
  35. `

Ruby

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

Js

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

コンソール

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

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

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

ソースとインデックスマッピングの処理

通常、インデックスされたフィールド名と取得される元のJSONフィールドは同じ名前を共有します。ただし、copy_toのような機能を使用したより複雑なフィールドマッピングでは、ソースJSONフィールドと集約されるインデックスフィールドが異なる場合があります。この場合、source_fieldsパラメータを使用して、テキストが分析されるJSON _sourceフィールドをリストすることができます:

Python

  1. resp = client.search(
  2. index="news",
  3. query={
  4. "match": {
  5. "custom_all": "elasticsearch"
  6. }
  7. },
  8. aggs={
  9. "tags": {
  10. "significant_text": {
  11. "field": "custom_all",
  12. "source_fields": [
  13. "content",
  14. "title"
  15. ]
  16. }
  17. }
  18. },
  19. )
  20. print(resp)

Ruby

  1. response = client.search(
  2. index: 'news',
  3. body: {
  4. query: {
  5. match: {
  6. custom_all: 'elasticsearch'
  7. }
  8. },
  9. aggregations: {
  10. tags: {
  11. significant_text: {
  12. field: 'custom_all',
  13. source_fields: [
  14. 'content',
  15. 'title'
  16. ]
  17. }
  18. }
  19. }
  20. }
  21. )
  22. puts response

Js

  1. const response = await client.search({
  2. index: "news",
  3. query: {
  4. match: {
  5. custom_all: "elasticsearch",
  6. },
  7. },
  8. aggs: {
  9. tags: {
  10. significant_text: {
  11. field: "custom_all",
  12. source_fields: ["content", "title"],
  13. },
  14. },
  15. },
  16. });
  17. console.log(response);

コンソール

  1. GET news/_search
  2. {
  3. "query": {
  4. "match": {
  5. "custom_all": "elasticsearch"
  6. }
  7. },
  8. "aggs": {
  9. "tags": {
  10. "significant_text": {
  11. "field": "custom_all",
  12. "source_fields": [ "content", "title" ]
  13. }
  14. }
  15. }
  16. }

値のフィルタリング

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