频繁项集聚合

编辑

一种用于查找频繁项集的桶聚合。它是一种关联规则挖掘的形式,用于识别经常一起出现的项。经常一起购买的商品或倾向于同时发生的日志事件都是频繁项集的示例。查找频繁项集有助于发现不同数据点(项)之间的关系。

聚合报告闭合项集。如果不存在具有相同文档比率(也称为其支持度值)的超集,则将频繁项集称为闭合项集。例如,我们有两个频繁项集候选项,它们具有相同的支持度值:1. apple, orange, banana 2. apple, orange, banana, tomato。仅返回第二个项集 (apple, orange, banana, tomato),而跳过第一个项集(它是第二个项集的子集)。如果它们的支持度值不同,则可能会返回这两个项集。

聚合的运行时长取决于数据和提供的参数。完成聚合可能需要相当长的时间。因此,建议使用异步搜索来异步运行您的请求。

语法

编辑

frequent_item_sets 聚合单独使用时如下所示

"frequent_item_sets": {
  "minimum_set_size": 3,
  "fields": [
    {"field": "my_field_1"},
    {"field": "my_field_2"}
  ]
}

表 51. frequent_item_sets 参数

参数名称

描述

必需

默认值

fields

(数组)要分析的字段。

必需

minimum_set_size

(整数)一个项集的最小大小

可选

1

minimum_support

(整数)一个项集的最小支持度

可选

0.1

size

(整数)要返回的顶部项集数量。

可选

10

filter

(对象)用于筛选分析文档的查询

可选

match_all

字段

编辑

支持的分析字段的字段类型是 keyword、numeric、ip、date 和这些类型的数组。您还可以将运行时字段添加到您的分析字段中。

如果分析字段的组合基数很高,则聚合可能需要大量的系统资源。

您可以使用 includeexclude 参数筛选每个字段的值。这些参数可以是正则表达式字符串或精确术语的字符串数组。筛选的值将从分析中删除,从而减少运行时间。如果同时定义了 includeexclude,则 exclude 优先;这意味着先评估 include,然后评估 exclude

最小集合大小

编辑

最小集合大小是集合需要包含的最小项数。值为 1 返回单项的频率。仅返回包含至少 minimum_set_size 项数的项集。例如,仅当最小集合大小为 3 或更小时,才会返回项集 orange, banana, apple

最小支持度

编辑

最小支持度值是项集必须存在于其中的文档比例,才能被认为是“频繁”的。特别是,它是 0 到 1 之间的标准化值。它是通过将包含项集的文档数除以文档总数来计算的。

例如,如果给定项集包含在五个文档中,且文档总数为 20,则该项集的支持度为 5/20 = 0.25。因此,仅当最小支持度为 0.25 或更小时,才会返回此集合。由于较高的最小支持度会修剪更多项,因此计算所需的资源较少。minimum_support 参数对所需的内存和聚合的运行时长有影响。

大小

编辑

此参数定义要返回的最大项集数。结果包含前 k 个项集;具有最高支持度值的项集。此参数对所需的内存和聚合的运行时长有重大影响。

过滤器

编辑

用于筛选文档以用作分析一部分的查询。在生成项集时,不匹配过滤器的文档将被忽略,但在计算项集的支持度时仍会计数。

如果要将项集分析范围缩小到感兴趣的字段,请使用过滤器。使用顶级查询来筛选数据集。

示例

编辑

在以下示例中,我们使用电子商务 Kibana 示例数据集。

具有两个分析字段和一个 exclude 参数的聚合

编辑

在第一个示例中,目标是基于交易数据找出 (1.) 客户经常一起购买的商品来自哪些产品类别,以及 (2.) 他们从哪些城市进行这些购买。我们想排除位置信息不可用(城市名称为 other)的结果。最后,我们对包含三个或更多项的集合感兴趣,并希望看到具有最高支持度的前三个频繁项集。

请注意,在第一个示例中,我们使用了异步搜索端点。

resp = client.async_search.submit(
    index="kibana_sample_data_ecommerce",
    size=0,
    aggs={
        "my_agg": {
            "frequent_item_sets": {
                "minimum_set_size": 3,
                "fields": [
                    {
                        "field": "category.keyword"
                    },
                    {
                        "field": "geoip.city_name",
                        "exclude": "other"
                    }
                ],
                "size": 3
            }
        }
    },
)
print(resp)
const response = await client.asyncSearch.submit({
  index: "kibana_sample_data_ecommerce",
  size: 0,
  aggs: {
    my_agg: {
      frequent_item_sets: {
        minimum_set_size: 3,
        fields: [
          {
            field: "category.keyword",
          },
          {
            field: "geoip.city_name",
            exclude: "other",
          },
        ],
        size: 3,
      },
    },
  },
});
console.log(response);
POST /kibana_sample_data_ecommerce/_async_search
{
   "size":0,
   "aggs":{
      "my_agg":{
         "frequent_item_sets":{
            "minimum_set_size":3,
            "fields":[
               {
                  "field":"category.keyword"
               },
               {
                  "field":"geoip.city_name",
                  "exclude":"other"
               }
            ],
            "size":3
         }
      }
   }
}

以上 API 调用的响应包含异步搜索请求的标识符 (id)。您可以使用该标识符来检索搜索结果

resp = client.async_search.get(
    id="<id>",
)
print(resp)
const response = await client.asyncSearch.get({
  id: "<id>",
});
console.log(response);
GET /_async_search/<id>

API 返回类似于以下内容的响应

(...)
"aggregations" : {
    "my_agg" : {
      "buckets" : [ 
        {
          "key" : { 
            "category.keyword" : [
              "Women's Clothing",
              "Women's Shoes"
            ],
            "geoip.city_name" : [
              "New York"
            ]
          },
          "doc_count" : 217, 
          "support" : 0.04641711229946524 
        },
        {
          "key" : {
            "category.keyword" : [
              "Women's Clothing",
              "Women's Accessories"
            ],
            "geoip.city_name" : [
              "New York"
            ]
          },
          "doc_count" : 135,
          "support" : 0.028877005347593583
        },
        {
          "key" : {
            "category.keyword" : [
              "Men's Clothing",
              "Men's Shoes"
            ],
            "geoip.city_name" : [
              "Cairo"
            ]
          },
          "doc_count" : 123,
          "support" : 0.026310160427807486
        }
      ],
    (...)
  }
}

返回的项集数组。

key 对象包含一个项集。在这种情况下,它由 category.keyword 字段的两个值和 geoip.city_name 的一个值组成。

包含该项集的文档数。

项集的支持度值。它是通过将包含项集的文档数除以文档总数来计算的。

响应表明,客户最常一起购买的类别是 Women's ClothingWomen's Shoes,来自纽约的客户倾向于经常一起购买这些类别的商品。换句话说,购买带有 Women's Clothing 标签的商品的客户更有可能也购买 Women's Shoes 类别的商品,而来自纽约的客户最有可能一起购买这些类别的商品。支持度第二高的项集是 Women's ClothingWomen's Accessories,客户主要来自纽约。最后,支持度第三高的项集是 Men's ClothingMen's Shoes,客户主要来自开罗。

具有两个分析字段和一个过滤器的聚合

编辑

我们采用第一个示例,但希望将项集范围缩小到欧洲地区。为此,我们添加了一个过滤器,这次我们不使用 exclude 参数

resp = client.async_search.submit(
    index="kibana_sample_data_ecommerce",
    size=0,
    aggs={
        "my_agg": {
            "frequent_item_sets": {
                "minimum_set_size": 3,
                "fields": [
                    {
                        "field": "category.keyword"
                    },
                    {
                        "field": "geoip.city_name"
                    }
                ],
                "size": 3,
                "filter": {
                    "term": {
                        "geoip.continent_name": "Europe"
                    }
                }
            }
        }
    },
)
print(resp)
const response = await client.asyncSearch.submit({
  index: "kibana_sample_data_ecommerce",
  size: 0,
  aggs: {
    my_agg: {
      frequent_item_sets: {
        minimum_set_size: 3,
        fields: [
          {
            field: "category.keyword",
          },
          {
            field: "geoip.city_name",
          },
        ],
        size: 3,
        filter: {
          term: {
            "geoip.continent_name": "Europe",
          },
        },
      },
    },
  },
});
console.log(response);
POST /kibana_sample_data_ecommerce/_async_search
{
  "size": 0,
  "aggs": {
    "my_agg": {
      "frequent_item_sets": {
        "minimum_set_size": 3,
        "fields": [
          { "field": "category.keyword" },
          { "field": "geoip.city_name" }
        ],
        "size": 3,
        "filter": {
          "term": {
            "geoip.continent_name": "Europe"
          }
        }
      }
    }
  }
}

结果将仅显示从与过滤器匹配的文档创建的项集,即在欧洲的购买。使用 filter,计算出的 support 仍会将所有购买纳入考虑。这与在顶层指定查询不同,在这种情况下,support 仅根据在欧洲的购买计算。

通过使用运行时字段分析数值

编辑

频繁项聚合使您能够通过使用运行时字段来存储数值。下一个示例演示如何使用脚本向您的文档添加一个名为 price_range 的运行时字段,该字段根据单笔交易的含税总价格计算得出。然后,可以将运行时字段用在频繁项聚合中,作为要分析的字段。

resp = client.search(
    index="kibana_sample_data_ecommerce",
    runtime_mappings={
        "price_range": {
            "type": "keyword",
            "script": {
                "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        "
            }
        }
    },
    size=0,
    aggs={
        "my_agg": {
            "frequent_item_sets": {
                "minimum_set_size": 4,
                "fields": [
                    {
                        "field": "category.keyword"
                    },
                    {
                        "field": "price_range"
                    },
                    {
                        "field": "geoip.city_name"
                    }
                ],
                "size": 3
            }
        }
    },
)
print(resp)
const response = await client.search({
  index: "kibana_sample_data_ecommerce",
  runtime_mappings: {
    price_range: {
      type: "keyword",
      script: {
        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        ",
      },
    },
  },
  size: 0,
  aggs: {
    my_agg: {
      frequent_item_sets: {
        minimum_set_size: 4,
        fields: [
          {
            field: "category.keyword",
          },
          {
            field: "price_range",
          },
          {
            field: "geoip.city_name",
          },
        ],
        size: 3,
      },
    },
  },
});
console.log(response);
GET kibana_sample_data_ecommerce/_search
{
  "runtime_mappings": {
    "price_range": {
      "type": "keyword",
      "script": {
        "source": """
           def bucket_start = (long) Math.floor(doc['taxful_total_price'].value / 50) * 50;
           def bucket_end = bucket_start + 50;
           emit(bucket_start.toString() + "-" + bucket_end.toString());
        """
      }
    }
  },
  "size": 0,
  "aggs": {
    "my_agg": {
      "frequent_item_sets": {
        "minimum_set_size": 4,
        "fields": [
          {
            "field": "category.keyword"
          },
          {
            "field": "price_range"
          },
          {
            "field": "geoip.city_name"
          }
        ],
        "size": 3
      }
    }
  }
}

API 返回类似于以下内容的响应

(...)
"aggregations" : {
    "my_agg" : {
      "buckets" : [
        {
          "key" : {
            "category.keyword" : [
              "Women's Clothing",
              "Women's Shoes"
            ],
            "price_range" : [
              "50-100"
            ],
            "geoip.city_name" : [
              "New York"
            ]
          },
          "doc_count" : 100,
          "support" : 0.0213903743315508
        },
        {
          "key" : {
            "category.keyword" : [
              "Women's Clothing",
              "Women's Shoes"
            ],
            "price_range" : [
              "50-100"
            ],
            "geoip.city_name" : [
              "Dubai"
            ]
          },
          "doc_count" : 59,
          "support" : 0.012620320855614974
        },
        {
          "key" : {
            "category.keyword" : [
              "Men's Clothing",
              "Men's Shoes"
            ],
            "price_range" : [
              "50-100"
            ],
            "geoip.city_name" : [
              "Marrakesh"
            ]
          },
          "doc_count" : 53,
          "support" : 0.011336898395721925
        }
      ],
    (...)
    }
  }

响应显示客户最常一起购买的类别、倾向于购买这些类别商品的客户所在位置以及这些购买中最常见的价格范围。