本文目录导读:

在Java中实现分布式KMeans聚类,通常有两种主要方式:
使用Apache Spark MLlib(推荐)
Spark提供了开箱即用的分布式KMeans实现:
import org.apache.spark.ml.clustering.KMeans;
import org.apache.spark.ml.clustering.KMeansModel;
import org.apache.spark.ml.evaluation.ClusteringEvaluator;
import org.apache.spark.ml.linalg.Vectors;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
public class SparkKMeansExample {
public static void main(String[] args) {
// 1. 创建SparkSession
SparkSession spark = SparkSession.builder()
.appName("KMeansExample")
.master("local[*]") // 分布式部署时改为yarn/mesos等
.getOrCreate();
// 2. 准备数据(示例数据)
Dataset<Row> dataset = spark.createDataFrame(
Arrays.asList(
RowFactory.create(Vectors.dense(0.0, 0.0)),
RowFactory.create(Vectors.dense(1.0, 1.0)),
RowFactory.create(Vectors.dense(9.0, 8.0)),
RowFactory.create(Vectors.dense(8.0, 9.0)),
RowFactory.create(Vectors.dense(5.0, 5.0))
),
new StructType()
.add("features", new VectorUDT(), false)
);
// 3. 训练KMeans模型
KMeans kmeans = new KMeans()
.setK(2)
.setSeed(1L)
.setMaxIter(20)
.setFeaturesCol("features")
.setPredictionCol("prediction");
KMeansModel model = kmeans.fit(dataset);
// 4. 评估模型(轮廓系数)
Dataset<Row> predictions = model.transform(dataset);
ClusteringEvaluator evaluator = new ClusteringEvaluator();
double silhouette = evaluator.evaluate(predictions);
System.out.println("轮廓系数: " + silhouette);
// 5. 获取聚类中心
Vector[] centers = model.clusterCenters();
System.out.println("聚类中心:");
for (Vector center : centers) {
System.out.println(center);
}
// 6. 预测新数据
Vector newPoint = Vectors.dense(0.5, 0.5);
int cluster = model.predict(newPoint);
System.out.println("点 " + newPoint + " 属于簇: " + cluster);
spark.stop();
}
}
Maven依赖:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-mllib_2.12</artifactId>
<version>3.4.0</version>
</dependency>
使用Apache Mahout(早已成熟)
Mahout与Hadoop集成,适合大规模数据:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.mahout.clustering.kmeans.KMeansDriver;
import org.apache.mahout.clustering.kmeans.Kluster;
import org.apache.mahout.common.distance.EuclideanDistanceMeasure;
import org.apache.mahout.math.VectorWritable;
public class MahoutKMeansExample {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
// 设置输入输出路径
Path input = new Path("hdfs://localhost:9000/input/data");
Path clusters = new Path("hdfs://localhost:9000/clusters");
Path output = new Path("hdfs://localhost:9000/output");
// 运行KMeans
KMeansDriver.run(conf, input, clusters, output,
new EuclideanDistanceMeasure(), // 距离度量
0.001, // 收敛阈值
10, // 最大迭代次数
true, // 是否聚类
0.0, // 聚类中心阈值
false); // 是否运行在本地
}
}
自定义分布式KMeans(基于MapReduce)
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.*;
import org.apache.hadoop.mapreduce.lib.output.*;
// Mapper类
public class KMeansMapper extends Mapper<LongWritable, Text, IntWritable, Text> {
private List<Vector> centers = new ArrayList<>();
@Override
protected void setup(Context context) {
// 从分布式缓存读取聚类中心
// 初始化centers列表
}
@Override
protected void map(LongWritable key, Text value, Context context) {
// 1. 解析数据点
Vector point = parsePoint(value.toString());
// 2. 找到最近的聚类中心
int nearestCenter = findNearestCenter(point, centers);
// 3. 输出:中心索引和点向量
context.write(new IntWritable(nearestCenter),
new Text(point.toString()));
}
}
// Reducer类
public class KMeansReducer extends Reducer<IntWritable, Text, IntWritable, Text> {
@Override
protected void reduce(IntWritable key, Iterable<Text> values, Context context) {
// 1. 计算新的聚类中心(所有点的平均值)
Vector sum = new DenseVector();
int count = 0;
for (Text value : values) {
Vector point = parsePoint(value.toString());
sum = sum.plus(point);
count++;
}
Vector newCenter = sum.divide(count);
// 2. 输出新的聚类中心
context.write(key, new Text(newCenter.toString()));
}
}
// Driver类
public class DistributedKMeansDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "Distributed KMeans");
job.setJarByClass(DistributedKMeansDriver.class);
job.setMapperClass(KMeansMapper.class);
job.setReducerClass(KMeansReducer.class);
job.setOutputKeyClass(IntWritable.class);
job.setOutputValueClass(Text.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 迭代执行直到收敛
int iteration = 0;
do {
System.exit(job.waitForCompletion(true) ? 0 : 1);
// 更新聚类中心
// 检查是否收敛
iteration++;
} while (iteration < MAX_ITERATIONS && !converged);
}
}
性能优化建议
- 数据分区:合理设置分区数(通常是集群CPU核心数的2-3倍)
// Spark分区优化 dataset.repartition(100); // 显式设置分区数
-
缓存中间结果:
Dataset<Row> cachedData = dataset.cache(); // 或 dataset.persist(StorageLevel.MEMORY_AND_DISK());
-
选择合适的K值:
// 使用肘部法则选择K double[] costs = new double[10]; for (int k = 2; k <= 10; k++) { KMeans kmeans = new KMeans().setK(k); KMeansModel model = kmeans.fit(dataset); costs[k-2] = model.computeCost(dataset); } -
并行度设置:
spark.conf().set("spark.sql.shuffle.partitions", "200");
适用场景对比
| 方案 | 适合场景 | 优势 | 劣势 |
|---|---|---|---|
| Spark MLlib | 大数据(GB-TB级) | 内存计算,速度快,易用 | 需要Spark集群 |
| Mahout | 超大数据(TB+) | 成熟稳定,支持Hadoop | 配置复杂,较慢 |
| 自定义MR | 学习/定制化需求 | 完全可控 | 开发工作量大 |
对于大多数生产环境,推荐使用Spark MLlib,它提供了最平衡的性能、易用性和功能完整性。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播