如何使用 transform 来跟踪你最近的客户订单

创建一个以实体为中心的索引,其中只包含每个实体的最新文档,在许多情况下都很有用。 例如,你可能正在管理一个电子商务网站,并且想要跟踪每个客户的最新订单。 或者,你可能想要针对在特定时期内不活跃的客户开展营销活动。 编译和组织此类数据的最快和最有效的方法是什么?

Elasticsearch 中的转换使你能够基于事件索引和转换函数创建和维护以实体为中心的索引。 直到最近,唯一可能的功能是 pivot,它是一个连续的 group-by plus 聚合。 在 7.12 版本中,我们又添加了一个转换函数,称为 latest。 它将源索引转换为目标索引,以便目标索引仅包含每个实体的一个最新文档。 在这篇博文中,我们将设置一个转换来做到这一点。
 

性能注意事项

在转换中引入 latest 之前,你可以通过使用 pivotscripted_metric 聚合来实现类似的效果。但是,基于脚本的解决方案存在许多问题:

  1. 它需要用 Painless 编写的代码,使其:

             - 不太高级的用户更难创建和维护

             - 容易出错(想想所有在 Painless 代码中很容易产生的意外错误)

  1. 它利用集群中的更多资源。
  2. 它的性能较慢。

缓慢的原因是对于每个检查点,转换执行源索引的完整扫描,以便为每个实体找到最新的文档。因为脚本对 transform 来说是个黑盒,它不知道将搜索限制为仅最近的文档。这使得计算成本随着时间的推移而增长,并给集群带来不必要的压力。

latest 函数就是为了满足这一特定目的而设计的,所以它被优化了,latest 转换不需要搜索整个源索引。它知道最新的文档必须在当前检查点中,或不需要更新目标索引。

 

准备数据

在本博客中,我们将使用 Kibana 的 “Sample eCommerce orders” 数据集。

如果你想继续学习,最简单的方法是在 Elastic Cloud 中开始免费试用

进入 Kibana 后,你可以通过单击 “Add data” 按钮从 “Sample data” 目录中获取数据集。

kibana_sample_data_ecommerce 索引将被创建。 索引中的每个文档都是某个客户(由 customer_id 字段标识)制作的订单(由名为 order_id 的字段标识)。

我们将 kibana_sample_data_ecommerce 索引转换为一个新索引(我们称之为 latest_order_per_customer),其中仅包含每个客户的最新订单。

 

设置目标索引模板

首先,我们需要目标索引使用的索引模板。

执行此步骤的基本原理是,与数据透视(pivot)不同,latest 不会自动推断目标索引映射。 因此,如果没有预先存在的目标索引(或索引模板),将使用动态索引映射,这可能不是你想要的。

目标索引的映射应该与源索引的映射匹配,所以让我们执行以下操作:

1)在 Stack Management > Index Management 页面中确定源索引的映射,并将完整的映射 JSON 复制到剪贴板。

我们需要在一个编辑器中编辑拷贝下来的 mapping,并修改为如下的格式:

{
  "properties": {
    "category": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword"
        }
      }
    },
    "currency": {
      "type": "keyword"
    },
    "customer_birth_date": {
      "type": "date"
    },
    "customer_first_name": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword",
          "ignore_above": 256
        }
      }
    },
    "customer_full_name": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword",
          "ignore_above": 256
        }
      }
    },
    "customer_gender": {
      "type": "keyword"
    },
    "customer_id": {
      "type": "keyword"
    },
    "customer_last_name": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword",
          "ignore_above": 256
        }
      }
    },
    "customer_phone": {
      "type": "keyword"
    },
    "day_of_week": {
      "type": "keyword"
    },
    "day_of_week_i": {
      "type": "integer"
    },
    "email": {
      "type": "keyword"
    },
    "event": {
      "properties": {
        "dataset": {
          "type": "keyword"
        }
      }
    },
    "geoip": {
      "properties": {
        "city_name": {
          "type": "keyword"
        },
        "continent_name": {
          "type": "keyword"
        },
        "country_iso_code": {
          "type": "keyword"
        },
        "location": {
          "type": "geo_point"
        },
        "region_name": {
          "type": "keyword"
        }
      }
    },
    "manufacturer": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword"
        }
      }
    },
    "order_date": {
      "type": "date"
    },
    "order_id": {
      "type": "keyword"
    },
    "products": {
      "properties": {
        "_id": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "base_price": {
          "type": "half_float"
        },
        "base_unit_price": {
          "type": "half_float"
        },
        "category": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "created_on": {
          "type": "date"
        },
        "discount_amount": {
          "type": "half_float"
        },
        "discount_percentage": {
          "type": "half_float"
        },
        "manufacturer": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        },
        "min_price": {
          "type": "half_float"
        },
        "price": {
          "type": "half_float"
        },
        "product_id": {
          "type": "long"
        },
        "product_name": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          },
          "analyzer": "english"
        },
        "quantity": {
          "type": "integer"
        },
        "sku": {
          "type": "keyword"
        },
        "tax_amount": {
          "type": "half_float"
        },
        "taxful_price": {
          "type": "half_float"
        },
        "taxless_price": {
          "type": "half_float"
        },
        "unit_discount_amount": {
          "type": "half_float"
        }
      }
    },
    "sku": {
      "type": "keyword"
    },
    "taxful_total_price": {
      "type": "half_float"
    },
    "taxless_total_price": {
      "type": "half_float"
    },
    "total_quantity": {
      "type": "integer"
    },
    "total_unique_products": {
      "type": "integer"
    },
    "type": {
      "type": "keyword"
    },
    "user": {
      "type": "keyword"
    }
  }
}

我们把上面的 mapping 拷贝下来,并在下面的步骤中进行使用。另外,我们也可以使用如下的命令来得到这个 mapping:

GET kibana_sample_data_ecommerce/_mapping

2)在 Create Template 页面中创建一个新的索引模板,并将其模式设置为 latest_order* 以匹配你稍后将在转换配置中指定的目标索引的名称。


3)使用加载 JSON 选项填充映射部分并粘贴剪贴板中的映射。

应用这些正确的映射后,目标索引已准备好由 transform 进行填充。

 

设置转换

现在我们准备创建一个 transform,为每个客户维护最新的订单。

转到 Stack Management > Transforms,然后选择 Create transform 页面上的最新按钮:

2)在屏幕下面的 transform 配置里,将 Unique keys 选项配置为具有 customer_id 的值并将 Sort 字段设置为 order_date:

将 transform 设置为连续运行很重要。 连续转换不会在处理历史数据后立即停止,而是继续处理实时到达的任何新数据:

确保使用与你在模板中指定的索引模式匹配的目标索引名称。

此外,启用 “Creat Kibana index pattern” 选项。

最后,让我们点击 Create and start 按钮来启动我们刚刚配置的转换:

正在运行的转换现在将处理 kibana_sample_data_ecommerce 索引并使用每个客户的最新订单不断更新目标索引 latest_order_per_customer。 如果有额外的订单到达,转换将相应地更新目标索引。

 

设置保留策略

如上所述,latest transform 将使用每个客户的最新订单不断更新目标索引。 但是,如果客户不再在我们的电子商务网站上购物怎么办? 此客户的条目将保留在目标索引中,但不会再收到任何更新。 如果你希望清除旧条目,请为转换中的目标索引设置保留策略。

1)转到 transform 的编辑页面,输入 order_date 作为字段并将 30d 设置为最大年龄:

2)单击 Update 按钮以应用新策略。


根据此保留政策,任何在过去 30 天内未下订单的客户都将从目标索引中删除。

顺便说一句,retention_policy 也可以用于 pivot,不仅是 latest!

 

结论

总之,我们利用了 latest transform 选项(lastest功能)来跟踪数据集中每个客户的最新订单。我们还制定了合理的保留政策,以自动清理和删除在特定时间范围内不再购买商品的客户。

lastest 功能还有许多其他可能的用例,包括:

  • 识别和激励在规定时间内没有订购任何东西的客户
  • 维护数据中心每台机器的最新心跳状态
  • 维护每个空气污染传感器(站)的当前空气污染测量值

如果你想试用新功能,请在 Elastic Cloud 中开始免费试用

相关推荐