一、K-Means(离线版):有限数据上的迭代聚类
1)输入列(Input Columns)
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
featuresCol |
Vector | "features" |
特征向量 |
2)输出列(Output Columns)
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
predictionCol |
Integer | "prediction" |
预测所属簇 ID(簇中心编号) |
3)参数(Parameters)详解
KMeansModel(预测侧)参数
| Key | 默认值 | 类型 | 说明 |
|---|---|---|---|
distanceMeasure |
EuclideanDistanceMeasure.NAME |
String | 距离度量(当前支持欧式距离) |
featuresCol |
"features" |
String | 特征列名 |
predictionCol |
"prediction" |
String | 输出列名 |
k |
2 | Integer | 簇数量(最大聚类数) |
KMeans(训练侧)额外参数
| Key | 默认值 | 类型 | 说明 |
|---|---|---|---|
initMode |
"random" |
String | 初始化方式(当前支持 random) |
seed |
null | Long | 随机种子(保证可复现) |
maxIter |
20 | Integer | 最大迭代次数 |
4)Java 示例代码解读(离线 KMeans)
示例流程很标准:
- 构造输入数据(DenseVector 流)
- DataStream → Table,并命名为
features kmeans.fit(table)训练得到KMeansModelmodel.transform(table)输出每条数据的簇 ID- collect 打印 features + clusterId
关键代码片段:
java
DataStream<DenseVector> inputStream =
env.fromElements(
Vectors.dense(0.0, 0.0),
Vectors.dense(0.0, 0.3),
Vectors.dense(0.3, 0.0),
Vectors.dense(9.0, 0.0),
Vectors.dense(9.0, 0.6),
Vectors.dense(9.6, 0.0));
Table inputTable = tEnv.fromDataStream(inputStream).as("features");
KMeans kmeans = new KMeans().setK(2).setSeed(1L);
KMeansModel kmeansModel = kmeans.fit(inputTable);
Table outputTable = kmeansModel.transform(inputTable)[0];
输出打印(预测列是 Integer):
java
DenseVector features = (DenseVector) row.getField(kmeans.getFeaturesCol());
int clusterId = (Integer) row.getField(kmeans.getPredictionCol());
二、Online K-Means:无界流上的持续聚类(mini-batch + 遗忘)
1)为什么需要 Online K-Means?
离线 KMeans 训练出来的中心是"固定"的。
但很多业务数据分布会随时间变化,例如:
- 用户行为习惯变了
- 商品/内容热点变化
- 流量来源变化
这时你希望模型能"持续学习",让聚类中心跟着数据漂移而更新,就需要 Online K-Means。
2)Online K-Means 的核心思想(mini-batch + decayFactor)
Online K-Means 基于"mini-batch KMeans"的更新规则,并加入遗忘机制(decay):
- 每次从训练流中积累一个 mini-batch
- 基于这个 batch 计算临时中心(estimated centroids)
- 用加权平均更新旧中心(original centroids):
decayFactor 解释(非常关键):
decayFactor = 1:历史与新数据同等重要(几乎不遗忘)decayFactor = 0:完全由最新数据决定中心(强遗忘)- 值越小 → 遗忘越强 → 模型越"跟新"
- 值越大 → 趋于稳定 → 变化越慢
3)输入输出列(Online)
输入列同离线:
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
featuresCol |
Vector | "features" |
特征向量 |
输出列同离线:
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
predictionCol |
Integer | "prediction" |
所属簇 ID |
4)参数(OnlineKMeans)详解
OnlineKMeansModel(预测侧)
| Key | 默认值 | 类型 | 说明 |
|---|---|---|---|
distanceMeasure |
EuclideanDistanceMeasure.NAME |
String | 距离度量(欧式距离) |
featuresCol |
"features" |
String | 特征列名 |
predictionCol |
"prediction" |
String | 输出列名 |
k |
2 | Integer | 簇数量 |
OnlineKMeans(训练侧)额外参数
| Key | 默认值 | 类型 | 说明 |
|---|---|---|---|
batchStrategy |
COUNT_STRATEGY |
String | mini-batch 构造策略 |
globalBatchSize |
32 | Integer | 全局 batch 大小 |
decayFactor |
0.0 | Double | 遗忘系数(历史中心贡献缩放) |
seed |
null | Long | 随机种子 |
5)Java 示例代码解读(OnlineKMeans)
示例里做了非常"演示型"的设计:训练数据分两段周期性出现,观察聚类结果如何随时间变化。
(1)训练流是无限流,周期性吐两批不同分布的数据
trainData1:大致在 (0~10) 附近trainData2:分布跳到了 (10,100) 与 (-10,-100) 两块
这等于让数据分布发生"漂移",你就能看到在线聚类中心被新数据影响。
(2)predict 也是周期性吐同一组预测点
java
List<Row> predictData =
Arrays.asList(
Row.of(Vectors.dense(10.0, 10.0)),
Row.of(Vectors.dense(-10.0, 10.0)));
输出里会不停打印:
- 两个点是否被分到同一个簇
因为随着训练数据改变、中心改变,聚类结果可能随时间变化。
(3)初始化模型数据 initialModelData
在线聚类必须有初始中心,否则没法开始迭代。示例使用:
java
.setInitialModelData(
KMeansModelData.generateRandomModelData(tEnv, 2, 2, 0.0, 0)
)
含义是:
- k=2 个中心
- 每个中心 2 维
- 随机生成初始中心
(4)globalBatchSize=6:每 6 条数据更新一次中心
java
.setGlobalBatchSize(6)
这与训练数据每批 6 条刚好对应,便于演示"每批更新一次"的效果。
三、离线 KMeans vs 在线 OnlineKMeans:怎么选?
选离线 KMeans 的典型场景
- 你有明确的历史数据窗口(按天、按周)
- 模型周期性训练发布,追求稳定可控
- 线上只是推理(transform),不希望训练影响延迟
选 OnlineKMeans 的典型场景
- 数据持续流入且分布变化快
- 你希望模型能持续适应新模式(概念漂移)
- 你可以接受聚类结果随时间变化
四、实战建议(非常重要)
1)KMeans 之前强烈建议做标准化
KMeans 基于距离(欧式距离),特征尺度不同会导致"某个维度支配聚类"。典型做法:
- VectorAssembler(拼特征)
- StandardScaler(标准化)
- KMeans / OnlineKMeans
2)k 的选择不要拍脑袋
常见方法:
- 肘部法(Elbow)
- 轮廓系数(Silhouette)
- 结合业务可解释性(比如用户分群常选 5/8/10)
3)OnlineKMeans 的 decayFactor 是控制"跟新程度"的旋钮
简单经验:
- 数据分布很稳定:decayFactor 接近 1
- 数据漂移明显:decayFactor 取 0.1~0.5 让模型更灵活
- 想快速跟随热点:decayFactor 更小
4)batch size 与更新频率要结合吞吐与稳定性
- batch 小:更新快但抖动大
- batch 大:更稳定但响应慢
五、小结
Flink ML 的 KMeans 家族可以覆盖绝大多数"聚类/分群"需求:
- KMeans(离线):有限数据、迭代训练、中心稳定
- OnlineKMeans(在线):无界流、mini-batch 更新、支持遗忘机制
掌握了 k / maxIter / globalBatchSize / decayFactor 这些关键参数,你就能把聚类从"demo"落到"线上可用"。