テキスト集約の分類

半構造化テキストをバケットにグループ化するマルチバケット集約です。各 text フィールドはカスタムアナライザーを使用して再分析されます。結果として得られたトークンは、類似の形式のテキスト値のバケットを作成するために分類されます。この集約は、システムログのような機械生成テキストに最適です。テキストを分類するために使用されるのは、最初の100個の分析されたトークンのみです。

JVMにかなりのメモリが割り当てられている場合でも、この集約から回路ブレーカー例外が発生する場合は、分類に適さない形式のテキストを分類しようとしている可能性があります。categorization_filtersを追加するか、サンプラー多様化サンプラー、またはランダムサンプラーの下で実行して、作成されたカテゴリを探索することを検討してください。

分類に使用されるアルゴリズムは、バージョン8.3.0で完全に変更されました。その結果、この集約は、ノードの一部がバージョン8.3.0以上で、他のノードが8.3.0未満の混合バージョンクラスターでは機能しません。この変更に関連するエラーが発生した場合は、クラスター内のすべてのノードを同じバージョンにアップグレードしてください。

パラメータ

  • categorization_analyzer
  • (オプション、オブジェクトまたは文字列) 分類アナライザーは、テキストが分類される前にどのように分析され、トークン化されるかを指定します。構文は、Analyzeエンドポイントanalyzerを定義するために使用されるものと非常に似ています。このプロパティは、categorization_filtersと同時に使用することはできません。
    categorization_analyzer フィールドは、文字列またはオブジェクトとして指定できます。文字列の場合は、組み込みアナライザーまたは他のプラグインによって追加されたものを参照する必要があります。オブジェクトの場合は、次のプロパティを持ちます:
    1. - `````char_filter
    • (文字列またはオブジェクトの配列) 1つ以上の文字フィルター。組み込みの文字フィルターに加えて、他のプラグインがさらに多くの文字フィルターを提供できます。このプロパティはオプションです。指定されていない場合、分類の前に文字フィルターは適用されません。アナライザーの他の側面をカスタマイズしている場合、categorization_filtersの同等物を達成する必要がある場合は、ここにパターン置換文字フィルターとして追加してください。
    • tokenizer
    • (文字列またはオブジェクト) 文字フィルターが適用された後に使用するトークナイザーの名前または定義。このプロパティは、categorization_analyzerがオブジェクトとして指定されている場合は必須です。機械学習は、英語のログファイル形式で良好な分類結果を生成することが決定された方法でトークン化するml_standardというトークナイザーを提供します。そのトークナイザーを使用したいが、文字またはトークンフィルターを変更したい場合は、"tokenizer": "ml_standard"categorization_analyzerに指定してください。さらに、ml_classicトークナイザーも利用可能で、製品の古いバージョン(6.2以前)のカスタマイズ不可能なトークナイザーと同じ方法でトークン化します。ml_classicは、バージョン6.2から7.13までのデフォルトの分類トークナイザーであったため、これらのバージョンで作成されたジョブのデフォルトと同じ分類が必要な場合は、"tokenizer": "ml_classic"categorization_analyzerに指定してください。
      Elasticsearch 8.10.0以降、新しいバージョン番号が機械学習プラグインの構成と状態の変更を追跡するために使用されます。この新しいバージョン番号は、製品バージョンから切り離されており、独立して増加します。
    • filter
    • (文字列またはオブジェクトの配列) 1つ以上のトークンフィルター。組み込みのトークンフィルターに加えて、他のプラグインがさらに多くのトークンフィルターを提供できます。このプロパティはオプションです。指定されていない場合、分類の前にトークンフィルターは適用されません。
  • categorization_filters
  • (オプション、文字列の配列) このプロパティは正規表現の配列を期待します。これらの式は、分類フィールド値から一致するシーケンスをフィルタリングするために使用されます。この機能を使用して、カテゴリが定義される際に考慮されるシーケンスを除外することで、分類を微調整できます。たとえば、ログファイルに表示されるSQLステートメントを除外できます。このプロパティは、categorization_analyzerと同時に使用することはできません。トークン化の前に適用される単純な正規表現フィルターを定義したい場合は、このプロパティを設定するのが最も簡単な方法です。トークナイザーやトークン化後のフィルタリングをカスタマイズしたい場合は、categorization_analyzerプロパティを代わりに使用し、フィルターをpattern_replace文字フィルターとして含めてください。
  • field
  • (必須、文字列) 分類する半構造化テキストフィールド。
  • max_matched_tokens
  • (オプション、整数) このパラメータは現在何もしませんが、元の8.3.0以前の実装との互換性のために許可されています。
  • max_unique_tokens
  • (オプション、整数) このパラメータは現在何もしませんが、元の8.3.0以前の実装との互換性のために許可されています。
  • min_doc_count
  • (オプション、整数) 結果に返されるバケットの最小ドキュメント数。
  • shard_min_doc_count
  • (オプション、整数) マージ前にシャードから返されるバケットの最小ドキュメント数。
  • shard_size
  • (オプション、整数) すべての結果をマージする前に、各シャードから返される分類バケットの数。
  • similarity_threshold
  • (オプション、整数、デフォルト: 70) テキストがカテゴリバケットに追加されるために一致する必要があるトークン重みの最小パーセンテージ。1から100の間でなければなりません。値が大きいほど、カテゴリは狭くなります。大きな値はメモリ使用量を増加させ、より狭いカテゴリを作成します。
  • size
  • (オプション、整数、デフォルト: 10) 返されるバケットの数。

レスポンスボディ

  • key
  • (文字列) カテゴリに含まれる入力フィールドのすべての値に共通するトークン(categorization_analyzerによって抽出されたもの)で構成されます。
  • doc_count
  • (整数) カテゴリに一致するドキュメントの数。
  • max_matching_length
  • (整数) トークンが少ない短いメッセージからのカテゴリも、はるかに長いメッセージから派生した多くのトークンを含むカテゴリに一致する場合があります。max_matching_lengthは、カテゴリに属すると見なされるべきメッセージの最大長の指標です。カテゴリに一致するメッセージを検索する際、max_matching_lengthより長いメッセージは除外されるべきです。このフィールドを使用して、短いメッセージのカテゴリのメンバーを検索する際に、はるかに長いメッセージと一致しないようにします。
  • regex
  • (文字列) カテゴリに含まれる入力フィールドのすべての値に一致する正規表現です。regexkeyに含まれるすべての用語を組み込んでいない可能性がありますが、カテゴリに含まれる値間で順序が異なる場合があります。ただし、単純なケースでは、regexは、間に任意のセクションを許可する正規表現に連結された順序付きの用語になります。元の文書を検索するための主要なメカニズムとしてregexを使用することは推奨されません。正規表現を使用した検索は非常に遅いです。代わりに、keyフィールドの用語を使用して一致するドキュメントを検索するべきです。用語検索は逆インデックスを使用できるため、はるかに高速です。ただし、インデックスされていない小さなメッセージセットがカテゴリに一致するかどうかをテストするためにregexフィールドを使用することが有用な場合や、keyの用語がすべての一致したドキュメントで正しい順序で発生することを確認するために使用することが有用な場合があります。

基本的な使用法

大きな 結果セットを再分析するには、多くの時間とメモリが必要です。この集約は、非同期検索と併用して使用する必要があります。さらに、集約をサンプラーまたは多様化サンプラー集約の子として使用することを検討してください。これにより、通常、速度とメモリ使用量が改善されます。

例:

Python

  1. resp = client.search(
  2. index="log-messages",
  3. filter_path="aggregations",
  4. aggs={
  5. "categories": {
  6. "categorize_text": {
  7. "field": "message"
  8. }
  9. }
  10. },
  11. )
  12. print(resp)

Js

  1. const response = await client.search({
  2. index: "log-messages",
  3. filter_path: "aggregations",
  4. aggs: {
  5. categories: {
  6. categorize_text: {
  7. field: "message",
  8. },
  9. },
  10. },
  11. });
  12. console.log(response);

コンソール

  1. POST log-messages/_search?filter_path=aggregations
  2. {
  3. "aggs": {
  4. "categories": {
  5. "categorize_text": {
  6. "field": "message"
  7. }
  8. }
  9. }
  10. }

レスポンス:

コンソール-結果

  1. {
  2. "aggregations" : {
  3. "categories" : {
  4. "buckets" : [
  5. {
  6. "doc_count" : 3,
  7. "key" : "Node shutting down",
  8. "regex" : ".*?Node.+?shutting.+?down.*?",
  9. "max_matching_length" : 49
  10. },
  11. {
  12. "doc_count" : 1,
  13. "key" : "Node starting up",
  14. "regex" : ".*?Node.+?starting.+?up.*?",
  15. "max_matching_length" : 47
  16. },
  17. {
  18. "doc_count" : 1,
  19. "key" : "User foo_325 logging on",
  20. "regex" : ".*?User.+?foo_325.+?logging.+?on.*?",
  21. "max_matching_length" : 52
  22. },
  23. {
  24. "doc_count" : 1,
  25. "key" : "User foo_864 logged off",
  26. "regex" : ".*?User.+?foo_864.+?logged.+?off.*?",
  27. "max_matching_length" : 52
  28. }
  29. ]
  30. }
  31. }
  32. }
  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="log-messages",
  5. filter_path="aggregations",
  6. aggs={
  7. "categories": {
  8. "categorize_text": {
  9. "field": "message",
  10. "categorization_filters": [
  11. "\\w+\\_\\d{3}"
  12. ]
  13. }
  14. }
  15. },
  16. )
  17. print(resp)
  18. `

Js

  1. const response = await client.search({
  2. index: "log-messages",
  3. filter_path: "aggregations",
  4. aggs: {
  5. categories: {
  6. categorize_text: {
  7. field: "message",
  8. categorization_filters: ["\\w+\\_\\d{3}"],
  9. },
  10. },
  11. },
  12. });
  13. console.log(response);

コンソール

  1. POST log-messages/_search?filter_path=aggregations
  2. {
  3. "aggs": {
  4. "categories": {
  5. "categorize_text": {
  6. "field": "message",
  7. "categorization_filters": ["\\w+\\_\\d{3}"]
  8. }
  9. }
  10. }
  11. }
分析されたトークンに適用するフィルター。bar_123のようなトークンをフィルタリングします。
  1. [](#547973e7d5ba9f5b775211fbb3574cf8)
  2. #### コンソール-結果
  3. ``````console-result
  4. {
  5. "aggregations" : {
  6. "categories" : {
  7. "buckets" : [
  8. {
  9. "doc_count" : 3,
  10. "key" : "Node shutting down",
  11. "regex" : ".*?Node.+?shutting.+?down.*?",
  12. "max_matching_length" : 49
  13. },
  14. {
  15. "doc_count" : 1,
  16. "key" : "Node starting up",
  17. "regex" : ".*?Node.+?starting.+?up.*?",
  18. "max_matching_length" : 47
  19. },
  20. {
  21. "doc_count" : 1,
  22. "key" : "User logged off",
  23. "regex" : ".*?User.+?logged.+?off.*?",
  24. "max_matching_length" : 52
  25. },
  26. {
  27. "doc_count" : 1,
  28. "key" : "User logging on",
  29. "regex" : ".*?User.+?logging.+?on.*?",
  30. "max_matching_length" : 52
  31. }
  32. ]
  33. }
  34. }
  35. }
  36. `
  1. #### Python
  2. ``````python
  3. resp = client.search(
  4. index="log-messages",
  5. filter_path="aggregations",
  6. aggs={
  7. "categories": {
  8. "categorize_text": {
  9. "field": "message",
  10. "categorization_filters": [
  11. "\\w+\\_\\d{3}"
  12. ],
  13. "similarity_threshold": 11
  14. }
  15. }
  16. },
  17. )
  18. print(resp)
  19. `

Js

  1. const response = await client.search({
  2. index: "log-messages",
  3. filter_path: "aggregations",
  4. aggs: {
  5. categories: {
  6. categorize_text: {
  7. field: "message",
  8. categorization_filters: ["\\w+\\_\\d{3}"],
  9. similarity_threshold: 11,
  10. },
  11. },
  12. },
  13. });
  14. console.log(response);

コンソール

  1. POST log-messages/_search?filter_path=aggregations
  2. {
  3. "aggs": {
  4. "categories": {
  5. "categorize_text": {
  6. "field": "message",
  7. "categorization_filters": ["\\w+\\_\\d{3}"],
  8. "similarity_threshold": 11
  9. }
  10. }
  11. }
  12. }
分析されたトークンに適用するフィルター。bar_123のようなトークンをフィルタリングします。
既存のカテゴリにメッセージを追加する前に、トークン重みの11%が一致する必要があります。新しいカテゴリを作成するのではなく。

結果として得られるカテゴリは非常に広範で、ロググループを統合しています。(11%のsimilarity_thresholdは一般的に低すぎます。50%以上の設定が通常は良好です。)

コンソール-結果

  1. {
  2. "aggregations" : {
  3. "categories" : {
  4. "buckets" : [
  5. {
  6. "doc_count" : 4,
  7. "key" : "Node",
  8. "regex" : ".*?Node.*?",
  9. "max_matching_length" : 49
  10. },
  11. {
  12. "doc_count" : 2,
  13. "key" : "User",
  14. "regex" : ".*?User.*?",
  15. "max_matching_length" : 52
  16. }
  17. ]
  18. }
  19. }
  20. }

この集約は、サブ集約を持つことができ、サブ集約としても機能します。これにより、以下のように、トップの日次カテゴリとトップのサンプルドキュメントを収集できます。

Python

  1. resp = client.search(
  2. index="log-messages",
  3. filter_path="aggregations",
  4. aggs={
  5. "daily": {
  6. "date_histogram": {
  7. "field": "time",
  8. "fixed_interval": "1d"
  9. },
  10. "aggs": {
  11. "categories": {
  12. "categorize_text": {
  13. "field": "message",
  14. "categorization_filters": [
  15. "\\w+\\_\\d{3}"
  16. ]
  17. },
  18. "aggs": {
  19. "hit": {
  20. "top_hits": {
  21. "size": 1,
  22. "sort": [
  23. "time"
  24. ],
  25. "_source": "message"
  26. }
  27. }
  28. }
  29. }
  30. }
  31. }
  32. },
  33. )
  34. print(resp)

Js

  1. const response = await client.search({
  2. index: "log-messages",
  3. filter_path: "aggregations",
  4. aggs: {
  5. daily: {
  6. date_histogram: {
  7. field: "time",
  8. fixed_interval: "1d",
  9. },
  10. aggs: {
  11. categories: {
  12. categorize_text: {
  13. field: "message",
  14. categorization_filters: ["\\w+\\_\\d{3}"],
  15. },
  16. aggs: {
  17. hit: {
  18. top_hits: {
  19. size: 1,
  20. sort: ["time"],
  21. _source: "message",
  22. },
  23. },
  24. },
  25. },
  26. },
  27. },
  28. },
  29. });
  30. console.log(response);

コンソール

  1. POST log-messages/_search?filter_path=aggregations
  2. {
  3. "aggs": {
  4. "daily": {
  5. "date_histogram": {
  6. "field": "time",
  7. "fixed_interval": "1d"
  8. },
  9. "aggs": {
  10. "categories": {
  11. "categorize_text": {
  12. "field": "message",
  13. "categorization_filters": ["\\w+\\_\\d{3}"]
  14. },
  15. "aggs": {
  16. "hit": {
  17. "top_hits": {
  18. "size": 1,
  19. "sort": ["time"],
  20. "_source": "message"
  21. }
  22. }
  23. }
  24. }
  25. }
  26. }
  27. }
  28. }

コンソール-結果

  1. {
  2. "aggregations" : {
  3. "daily" : {
  4. "buckets" : [
  5. {
  6. "key_as_string" : "2016-02-07T00:00:00.000Z",
  7. "key" : 1454803200000,
  8. "doc_count" : 3,
  9. "categories" : {
  10. "buckets" : [
  11. {
  12. "doc_count" : 2,
  13. "key" : "Node shutting down",
  14. "regex" : ".*?Node.+?shutting.+?down.*?",
  15. "max_matching_length" : 49,
  16. "hit" : {
  17. "hits" : {
  18. "total" : {
  19. "value" : 2,
  20. "relation" : "eq"
  21. },
  22. "max_score" : null,
  23. "hits" : [
  24. {
  25. "_index" : "log-messages",
  26. "_id" : "1",
  27. "_score" : null,
  28. "_source" : {
  29. "message" : "2016-02-07T00:00:00+0000 Node 3 shutting down"
  30. },
  31. "sort" : [
  32. 1454803260000
  33. ]
  34. }
  35. ]
  36. }
  37. }
  38. },
  39. {
  40. "doc_count" : 1,
  41. "key" : "Node starting up",
  42. "regex" : ".*?Node.+?starting.+?up.*?",
  43. "max_matching_length" : 47,
  44. "hit" : {
  45. "hits" : {
  46. "total" : {
  47. "value" : 1,
  48. "relation" : "eq"
  49. },
  50. "max_score" : null,
  51. "hits" : [
  52. {
  53. "_index" : "log-messages",
  54. "_id" : "2",
  55. "_score" : null,
  56. "_source" : {
  57. "message" : "2016-02-07T00:00:00+0000 Node 5 starting up"
  58. },
  59. "sort" : [
  60. 1454803320000
  61. ]
  62. }
  63. ]
  64. }
  65. }
  66. }
  67. ]
  68. }
  69. },
  70. {
  71. "key_as_string" : "2016-02-08T00:00:00.000Z",
  72. "key" : 1454889600000,
  73. "doc_count" : 3,
  74. "categories" : {
  75. "buckets" : [
  76. {
  77. "doc_count" : 1,
  78. "key" : "Node shutting down",
  79. "regex" : ".*?Node.+?shutting.+?down.*?",
  80. "max_matching_length" : 49,
  81. "hit" : {
  82. "hits" : {
  83. "total" : {
  84. "value" : 1,
  85. "relation" : "eq"
  86. },
  87. "max_score" : null,
  88. "hits" : [
  89. {
  90. "_index" : "log-messages",
  91. "_id" : "4",
  92. "_score" : null,
  93. "_source" : {
  94. "message" : "2016-02-08T00:00:00+0000 Node 5 shutting down"
  95. },
  96. "sort" : [
  97. 1454889660000
  98. ]
  99. }
  100. ]
  101. }
  102. }
  103. },
  104. {
  105. "doc_count" : 1,
  106. "key" : "User logged off",
  107. "regex" : ".*?User.+?logged.+?off.*?",
  108. "max_matching_length" : 52,
  109. "hit" : {
  110. "hits" : {
  111. "total" : {
  112. "value" : 1,
  113. "relation" : "eq"
  114. },
  115. "max_score" : null,
  116. "hits" : [
  117. {
  118. "_index" : "log-messages",
  119. "_id" : "6",
  120. "_score" : null,
  121. "_source" : {
  122. "message" : "2016-02-08T00:00:00+0000 User foo_864 logged off"
  123. },
  124. "sort" : [
  125. 1454889840000
  126. ]
  127. }
  128. ]
  129. }
  130. }
  131. },
  132. {
  133. "doc_count" : 1,
  134. "key" : "User logging on",
  135. "regex" : ".*?User.+?logging.+?on.*?",
  136. "max_matching_length" : 52,
  137. "hit" : {
  138. "hits" : {
  139. "total" : {
  140. "value" : 1,
  141. "relation" : "eq"
  142. },
  143. "max_score" : null,
  144. "hits" : [
  145. {
  146. "_index" : "log-messages",
  147. "_id" : "5",
  148. "_score" : null,
  149. "_source" : {
  150. "message" : "2016-02-08T00:00:00+0000 User foo_325 logging on"
  151. },
  152. "sort" : [
  153. 1454889720000
  154. ]
  155. }
  156. ]
  157. }
  158. }
  159. }
  160. ]
  161. }
  162. }
  163. ]
  164. }
  165. }
  166. }