頻出アイテムセットの集約

頻出アイテムセットを見つけるバケット集約です。これは、よく一緒に発生するアイテムを特定するアソシエーションルールマイニングの一形態です。頻繁に一緒に購入されるアイテムや、共に発生する傾向のあるログイベントは、頻出アイテムセットの例です。頻出アイテムセットを見つけることで、異なるデータポイント(アイテム)間の関係を発見するのに役立ちます。

集約は閉じたアイテムセットを報告します。頻出アイテムセットは、同じ文書の比率を持つスーパーセットが存在しない場合に閉じていると呼ばれます(これはそのサポート値としても知られています)。例えば、次の2つの候補が頻出アイテムセットとしてあり、同じサポート値を持っています:1. apple, orange, banana 2. apple, orange, banana, tomato。2番目のアイテムセット(apple, orange, banana, tomato)のみが返され、最初のセットは2番目のセットのサブセットであるためスキップされます。サポート値が異なる場合は、両方のアイテムセットが返される可能性があります。

集約の実行時間はデータと提供されたパラメータに依存します。集約が完了するまでにかなりの時間がかかる場合があります。このため、リクエストを非同期に実行するために非同期検索を使用することをお勧めします。

構文

単独でのfrequent_item_sets集約は次のようになります:

Js

  1. "frequent_item_sets": {
  2. "minimum_set_size": 3,
  3. "fields": [
  4. {"field": "my_field_1"},
  5. {"field": "my_field_2"}
  6. ]
  7. }

表49. frequent_item_sets パラメータ

パラメータ名 説明 必須 デフォルト値
fields (配列) 分析するフィールド。 必須
minimum_set_size (整数) 1つのアイテムセットの最小サイズ. オプション 1
minimum_support (整数) 1つのアイテムセットの最小サポート. オプション 0.1
size (整数) 返すトップアイテムセットの数。 オプション 10
filter (オブジェクト) 分析から文書をフィルタリングするクエリ オプション match_all

フィールド

分析対象のフィールドにサポートされているフィールドタイプは、キーワード、数値、IP、日付、およびこれらのタイプの配列です。分析対象のフィールドにランタイムフィールドを追加することもできます。

分析対象のフィールドの組み合わせのカーディナリティが高い場合、集約にはかなりのシステムリソースが必要になる可能性があります。

  1. ### 最小セットサイズ
  2. 最小セットサイズは、セットが含む必要があるアイテムの最小数です。値が1の場合、単一アイテムの頻度が返されます。`````minimum_set_size`````アイテムを少なくとも含むアイテムセットのみが返されます。例えば、アイテムセット`````orange, banana, apple`````は、最小セットサイズが3以下の場合にのみ返されます。
  3. ### 最小サポート
  4. 最小サポート値は、アイテムセットが「頻出」と見なされるために存在しなければならない文書の比率です。特に、これは01の間の正規化された値です。アイテムセットを含む文書の数を総文書数で割ることによって計算されます。
  5. 例えば、特定のアイテムセットが5つの文書に含まれ、総文書数が20の場合、アイテムセットのサポートは5/20 = 0.25です。したがって、このセットは最小サポートが0.25以下の場合にのみ返されます。より高い最小サポートはより多くのアイテムを削減するため、計算はリソース集約的ではなくなります。`````minimum_support`````パラメータは、集約の必要なメモリと実行時間に影響を与えます。
  6. ### サイズ
  7. このパラメータは、返すアイテムセットの最大数を定義します。結果にはトップkアイテムセットが含まれ、サポート値が最も高いアイテムセットです。このパラメータは、集約の必要なメモリと実行時間に大きな影響を与えます。
  8. ### フィルター
  9. 分析の一部として使用する文書をフィルタリングするためのクエリです。フィルターに一致しない文書は、アイテムセットを生成する際に無視されますが、アイテムセットのサポートを計算する際には依然としてカウントされます。
  10. フィルターを使用して、アイテムセット分析を関心のあるフィールドに絞り込みます。データセットをフィルタリングするためにトップレベルのクエリを使用します。
  11. ### 例
  12. 以下の例では、eコマースKibanaサンプルデータセットを使用します。
  13. ### 2つの分析フィールドと除外パラメータを持つ集約
  14. 最初の例では、取引データ(1.)に基づいて、顧客がどの製品カテゴリから製品を頻繁に一緒に購入するか、(2.)どの都市からその購入を行うかを調べることが目的です。位置情報が利用できない結果(都市名が`````other`````である場合)を除外したいと考えています。最後に、3つ以上のアイテムを持つセットに興味があり、サポートが最も高い最初の3つの頻出アイテムセットを見たいと思います。
  15. この最初の例では、[非同期検索](/read/elasticsearch-8-15/de9d10f1e665749f.md)エンドポイントを使用していることに注意してください。
  16. #### Python
  17. ``````python
  18. resp = client.async_search.submit(
  19. index="kibana_sample_data_ecommerce",
  20. size=0,
  21. aggs={
  22. "my_agg": {
  23. "frequent_item_sets": {
  24. "minimum_set_size": 3,
  25. "fields": [
  26. {
  27. "field": "category.keyword"
  28. },
  29. {
  30. "field": "geoip.city_name",
  31. "exclude": "other"
  32. }
  33. ],
  34. "size": 3
  35. }
  36. }
  37. },
  38. )
  39. print(resp)
  40. `

Js

  1. const response = await client.asyncSearch.submit({
  2. index: "kibana_sample_data_ecommerce",
  3. size: 0,
  4. aggs: {
  5. my_agg: {
  6. frequent_item_sets: {
  7. minimum_set_size: 3,
  8. fields: [
  9. {
  10. field: "category.keyword",
  11. },
  12. {
  13. field: "geoip.city_name",
  14. exclude: "other",
  15. },
  16. ],
  17. size: 3,
  18. },
  19. },
  20. },
  21. });
  22. console.log(response);

コンソール

  1. POST /kibana_sample_data_ecommerce/_async_search
  2. {
  3. "size":0,
  4. "aggs":{
  5. "my_agg":{
  6. "frequent_item_sets":{
  7. "minimum_set_size":3,
  8. "fields":[
  9. {
  10. "field":"category.keyword"
  11. },
  12. {
  13. "field":"geoip.city_name",
  14. "exclude":"other"
  15. }
  16. ],
  17. "size":3
  18. }
  19. }
  20. }
  21. }

上記のAPI呼び出しの応答には、非同期検索リクエストの識別子(id)が含まれています。この識別子を使用して検索結果を取得できます:

Python

  1. resp = client.async_search.get(
  2. id="<id>",
  3. )
  4. print(resp)

Js

  1. const response = await client.asyncSearch.get({
  2. id: "<id>",
  3. });
  4. console.log(response);

コンソール

  1. GET /_async_search/<id>

APIは、次のような応答を返します:

コンソール-結果

  1. (...)
  2. "aggregations" : {
  3. "my_agg" : {
  4. "buckets" : [
  5. {
  6. "key" : {
  7. "category.keyword" : [
  8. "Women's Clothing",
  9. "Women's Shoes"
  10. ],
  11. "geoip.city_name" : [
  12. "New York"
  13. ]
  14. },
  15. "doc_count" : 217,
  16. "support" : 0.04641711229946524
  17. },
  18. {
  19. "key" : {
  20. "category.keyword" : [
  21. "Women's Clothing",
  22. "Women's Accessories"
  23. ],
  24. "geoip.city_name" : [
  25. "New York"
  26. ]
  27. },
  28. "doc_count" : 135,
  29. "support" : 0.028877005347593583
  30. },
  31. {
  32. "key" : {
  33. "category.keyword" : [
  34. "Men's Clothing",
  35. "Men's Shoes"
  36. ],
  37. "geoip.city_name" : [
  38. "Cairo"
  39. ]
  40. },
  41. "doc_count" : 123,
  42. "support" : 0.026310160427807486
  43. }
  44. ],
  45. (...)
  46. }
  47. }
返されたアイテムセットの配列。
keyオブジェクトには1つのアイテムセットが含まれています。この場合、category.keywordフィールドの2つの値とgeoip.city_nameの1つの値で構成されています。
アイテムセットを含む文書の数。
アイテムセットのサポート値。これは、アイテムセットを含む文書の数を総文書数で割ることによって計算されます。

応答は、顧客が最も頻繁に一緒に購入するカテゴリがWomen's ClothingWomen's Shoesであり、ニューヨークの顧客はこれらのカテゴリからアイテムを頻繁に一緒に購入する傾向があることを示しています。言い換えれば、Women's Clothingラベルの付いた製品を購入する顧客は、Women's Shoesカテゴリの製品も購入する可能性が高く、ニューヨークの顧客はこれらのカテゴリから製品を一緒に購入する可能性が最も高いです。サポートが2番目に高いアイテムセットはWomen's ClothingWomen's Accessoriesで、顧客は主にニューヨークからです。最後に、サポートが3番目に高いアイテムセットはMen's ClothingMen's Shoesで、顧客は主にカイロからです。

2つの分析フィールドとフィルターを持つ集約

最初の例を取り上げますが、アイテムセットをヨーロッパの場所に絞り込みたいと思います。そのため、フィルターを追加し、今回はexcludeパラメータを使用しません:

Python

  1. resp = client.async_search.submit(
  2. index="kibana_sample_data_ecommerce",
  3. size=0,
  4. aggs={
  5. "my_agg": {
  6. "frequent_item_sets": {
  7. "minimum_set_size": 3,
  8. "fields": [
  9. {
  10. "field": "category.keyword"
  11. },
  12. {
  13. "field": "geoip.city_name"
  14. }
  15. ],
  16. "size": 3,
  17. "filter": {
  18. "term": {
  19. "geoip.continent_name": "Europe"
  20. }
  21. }
  22. }
  23. }
  24. },
  25. )
  26. print(resp)

Js

  1. const response = await client.asyncSearch.submit({
  2. index: "kibana_sample_data_ecommerce",
  3. size: 0,
  4. aggs: {
  5. my_agg: {
  6. frequent_item_sets: {
  7. minimum_set_size: 3,
  8. fields: [
  9. {
  10. field: "category.keyword",
  11. },
  12. {
  13. field: "geoip.city_name",
  14. },
  15. ],
  16. size: 3,
  17. filter: {
  18. term: {
  19. "geoip.continent_name": "Europe",
  20. },
  21. },
  22. },
  23. },
  24. },
  25. });
  26. console.log(response);

コンソール

  1. POST /kibana_sample_data_ecommerce/_async_search
  2. {
  3. "size": 0,
  4. "aggs": {
  5. "my_agg": {
  6. "frequent_item_sets": {
  7. "minimum_set_size": 3,
  8. "fields": [
  9. { "field": "category.keyword" },
  10. { "field": "geoip.city_name" }
  11. ],
  12. "size": 3,
  13. "filter": {
  14. "term": {
  15. "geoip.continent_name": "Europe"
  16. }
  17. }
  18. }
  19. }
  20. }
  21. }

結果は、フィルターに一致する文書から作成されたアイテムセットのみを表示します。つまり、ヨーロッパでの購入です。filterを使用すると、計算されたsupportはすべての購入を考慮に入れます。これは、トップレベルでクエリを指定する場合とは異なり、その場合supportはヨーロッパでの購入からのみ計算されます。

ランタイムフィールドを使用した数値値の分析

頻出アイテム集約を使用すると、ランタイムフィールドを使用して数値値をバケット化できます。次の例では、個々の取引の税金を含む合計価格から計算されるランタイムフィールドprice_rangeを文書に追加するスクリプトの使用方法を示します。このランタイムフィールドは、その後、頻出アイテム集約で分析するフィールドとして使用できます。

Python

  1. resp = client.search(
  2. index="kibana_sample_data_ecommerce",
  3. runtime_mappings={
  4. "price_range": {
  5. "type": "keyword",
  6. "script": {
  7. "source": "\n def bucket_start = (long) Math.floor(doc['taxful_total_price'].value / 50) * 50;\n def bucket_end = bucket_start + 50;\n emit(bucket_start.toString() + \"-\" + bucket_end.toString());\n "
  8. }
  9. }
  10. },
  11. size=0,
  12. aggs={
  13. "my_agg": {
  14. "frequent_item_sets": {
  15. "minimum_set_size": 4,
  16. "fields": [
  17. {
  18. "field": "category.keyword"
  19. },
  20. {
  21. "field": "price_range"
  22. },
  23. {
  24. "field": "geoip.city_name"
  25. }
  26. ],
  27. "size": 3
  28. }
  29. }
  30. },
  31. )
  32. print(resp)

Js

  1. const response = await client.search({
  2. index: "kibana_sample_data_ecommerce",
  3. runtime_mappings: {
  4. price_range: {
  5. type: "keyword",
  6. script: {
  7. source:
  8. "\n def bucket_start = (long) Math.floor(doc['taxful_total_price'].value / 50) * 50;\n def bucket_end = bucket_start + 50;\n emit(bucket_start.toString() + \"-\" + bucket_end.toString());\n ",
  9. },
  10. },
  11. },
  12. size: 0,
  13. aggs: {
  14. my_agg: {
  15. frequent_item_sets: {
  16. minimum_set_size: 4,
  17. fields: [
  18. {
  19. field: "category.keyword",
  20. },
  21. {
  22. field: "price_range",
  23. },
  24. {
  25. field: "geoip.city_name",
  26. },
  27. ],
  28. size: 3,
  29. },
  30. },
  31. },
  32. });
  33. console.log(response);

コンソール

  1. GET kibana_sample_data_ecommerce/_search
  2. {
  3. "runtime_mappings": {
  4. "price_range": {
  5. "type": "keyword",
  6. "script": {
  7. "source": """
  8. def bucket_start = (long) Math.floor(doc['taxful_total_price'].value / 50) * 50;
  9. def bucket_end = bucket_start + 50;
  10. emit(bucket_start.toString() + "-" + bucket_end.toString());
  11. """
  12. }
  13. }
  14. },
  15. "size": 0,
  16. "aggs": {
  17. "my_agg": {
  18. "frequent_item_sets": {
  19. "minimum_set_size": 4,
  20. "fields": [
  21. {
  22. "field": "category.keyword"
  23. },
  24. {
  25. "field": "price_range"
  26. },
  27. {
  28. "field": "geoip.city_name"
  29. }
  30. ],
  31. "size": 3
  32. }
  33. }
  34. }
  35. }

APIは、次のような応答を返します:

コンソール-結果

  1. (...)
  2. "aggregations" : {
  3. "my_agg" : {
  4. "buckets" : [
  5. {
  6. "key" : {
  7. "category.keyword" : [
  8. "Women's Clothing",
  9. "Women's Shoes"
  10. ],
  11. "price_range" : [
  12. "50-100"
  13. ],
  14. "geoip.city_name" : [
  15. "New York"
  16. ]
  17. },
  18. "doc_count" : 100,
  19. "support" : 0.0213903743315508
  20. },
  21. {
  22. "key" : {
  23. "category.keyword" : [
  24. "Women's Clothing",
  25. "Women's Shoes"
  26. ],
  27. "price_range" : [
  28. "50-100"
  29. ],
  30. "geoip.city_name" : [
  31. "Dubai"
  32. ]
  33. },
  34. "doc_count" : 59,
  35. "support" : 0.012620320855614974
  36. },
  37. {
  38. "key" : {
  39. "category.keyword" : [
  40. "Men's Clothing",
  41. "Men's Shoes"
  42. ],
  43. "price_range" : [
  44. "50-100"
  45. ],
  46. "geoip.city_name" : [
  47. "Marrakesh"
  48. ]
  49. },
  50. "doc_count" : 53,
  51. "support" : 0.011336898395721925
  52. }
  53. ],
  54. (...)
  55. }
  56. }

応答は、顧客が最も頻繁に一緒に購入するカテゴリ、これらのカテゴリからアイテムを購入する傾向のある顧客の場所、およびこれらの購入の最も頻繁な価格帯を示しています。