源代码是别人的,我就一写笔记的
package k_means;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.util.LineReader;
public class Utils {
//读取中心文件的数据
public static ArrayList<ArrayList<Double>> getCenters(String CPath,boolean isDirectory) throws IOException{
//定义一个静态List ,它的成员都必须是ArrayList类型且ArrayList里面的成员都是Double类型成员组成的ArrayList
ArrayList<ArrayList<Double>> result = new ArrayList<ArrayList<Double>>();
//Path用于来表示文件路径和文件
Path path = new Path(CPath);
//构造接口
Configuration conf = new Configuration();
//建立文件系统
FileSystem fileSystem = path.getFileSystem(conf);
//如果是目录的话,读取目录内所有文件(常规操作,如果确定代码内文件只有一个且不是目录可以不写),也可以说是一个函数两用。
if(isDirectory){
//获取文件列表
FileStatus[] listFile = fileSystem.listStatus(path);
//遍历目录下所有的文件
for (int i = 0; i < listFile.length; i++) {
//传入一个List,将此List中的所有元素加入到当前List中,当前List会增加的元素个数为传入的List的大小
//其实就是确定全部都是文件不是目录的,存进list开始要一个一个读了
result.addAll(getCenters(listFile[i].getPath().toString(),false));
}
//如果是目录就返回目录下文件的路经(一个函数两用)
return result;
}
//打开,FileSystem.open()方法返回的是一个FSDataInputStream对象
/*
* (继承关系:
* java.io.InputStream -->
* java.io.FilterInputStream -->
* java.io.DataInputStream -->
* org.apache.hadoop.fs.FSDataInputStream)。
* 由于FSDataInputStream实现了Closeable, DataInput, PositionedReadable, Seekable
* 等接口,你可以从流中的任意一个位置读取数据。
* */
FSDataInputStream fsis = fileSystem.open(path);
//创建了一个lineReader实例在调用lineReader实例的readline(String)方法把输入流fsis中的一行写入到Text型的line中
LineReader lineReader = new LineReader(fsis, conf);
Text line = new Text();
//返回一个int型如果大于零说明这一行不为空
//
while(lineReader.readLine(line) > 0){
//textToArray把数据转化为double型的存成List
ArrayList<Double> tempList = textToArray(line);
result.add(tempList);
}
lineReader.close();
return result;
}
//删掉文件
public static void deletePath(String pathStr) throws IOException{
Configuration conf = new Configuration();
Path path = new Path(pathStr);
FileSystem hdfs = path.getFileSystem(conf);
hdfs.delete(path,true);
}
public static ArrayList<Double> textToArray(Text text){
ArrayList<Double> list = new ArrayList<Double>();
//因为我们的数据是多维数据,一个点的数据之间用逗号隔开,所以需要去除","
//因为是自行分片,每一组数据分成一片,数据一共178行,所以并行度为178.
String[] fileds = text.toString().split(",");
for(int i=0;i<fileds.length;i++){
//把fileds[i]转换成double类型存入list
list.add(Double.parseDouble(fileds[i]));
}
return list;
}
//对比新旧中心是否一致
public static boolean compareCenters(String centerPath,String newPath) throws IOException{
//由上面代码得知,得到了两组点
List<ArrayList<Double>> oldCenters = Utils.getCenters(centerPath,false);
//但是为何这里就变成true了呢?因为newPath是一个目录,存放了每一次迭代的数据在output之中,结果在out中
List<ArrayList<Double>> newCenters = Utils.getCenters(newPath,true);
int size = oldCenters.size();
int fildSize = oldCenters.get(0).size();
double distance = 0;
for(int i=0;i<size;i++){
for(int j=0;j<fildSize;j++){
double t1 = oldCenters.get(i).get(j);
double t2 = newCenters.get(i).get(j);
System.out.println(t1);
System.out.println(t2);
//虽然是求欧几里得距离,但是只是比较大小,是否开方无差别,故不进行开方处理
distance += Math.pow(t1 - t2, 2);
}
}
if(distance == 0.0){
//删掉新的中心文件以便最后依次归类输出
Utils.deletePath(newPath);
return true;
}else{
//先清空中心文件,将新的中心文件复制到中心文件中,再删掉中心文件
Configuration conf = new Configuration();
Path outPath = new Path(centerPath);
FileSystem fileSystem = outPath.getFileSystem(conf);
FSDataOutputStream overWrite = fileSystem.create(outPath,true);
overWrite.writeChars("");
overWrite.close();
Path inPath = new Path(newPath);
FileStatus[] listFiles = fileSystem.listStatus(inPath);
for (int i = 0; i < listFiles.length; i++) {
FSDataOutputStream out = fileSystem.create(outPath);
FSDataInputStream in = fileSystem.open(listFiles[i].getPath());
IOUtils.copyBytes(in, out, 4096, true);
}
//删掉新的中心文件以便第二次任务运行输出
Utils.deletePath(newPath);
}
return false;
}
}
参考代码
Kmeans在MapReduce中的实现
可以一个劲地溯源,不过这篇文章的从j=1开始我不同意,你会发现后面计算的时候还是有问题,而且只是实现kmeans初始的意思就没有去掉第一个数据的,所以规规矩矩j=0吧。