【学习记录】MapReduce实现Kmeans Util包解读

源代码是别人的,我就一写笔记的

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吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值