西南交大互联网搜索引擎课程设计(二)--建立搜索引擎

1、项目介绍
1.1 项目需求分析
1.2 技术可行性分析
1.2.1 建立并实现搜索引擎功能
1.2.2 比较文档之间的相似度
1.2.3 对下载的文档,利用K-Means聚类算法进行聚类
1.3 项目环境介绍
1.3.1 运行环境
1.3.2 第三方工具包
1.3.3 数据来源

2、 项目实现
2.1 建立索引
2.1.1 新建文件工具类
2.1.2 对中英文预处理文件建立索引
2.2 搜索引擎界面
2.2.1 中英文选择和搜索以及执行查询
2.2.2 查询结果显示
2.2.3 打开目标预处理文件及源文件
2.3 比较文档之间的相似度
2.3.1 余弦距离原理
2.3.2 TF-IDF算法原理
2.3.3 建立文档相似度比较的界面
2.3.4 相似度计算
2.3.5 结果展示
2.4对下载的文档,利用K-Means聚类算法进行聚类
2.4.1 算法原理
2.4.2 中文文档的处理
2.4.3 中文文档的处理结果
2.4.4 英文文档的处理
2.4.5 英文文档的处理结果

3、 附录
3.1 项目总结
3.2 参考文献

java工程链接
工程目录

参考文档1:TF-IDF与余弦相似性的应用(一):自动提取关键词

参考文档2:TF-IDF与余弦相似性的应用(二):找出相似文章

根据K-means算法写了java版的多文本聚类算法:

package com.search;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class KmeansTest {

    static String FileAddr1 = "E:\\eclipse\\java\\IR\\text1\\"; //中文
    static String fileContent1 = ""; //中文文档内容

    static double temp0,temp1,temp2,temp,minV;
    static int CPR[] = new int[500],minI;

    //获取所有文章的各自的向量
    public static double[][]  getVectors() {

        double CV[][] = new double[500][100]; //未初始化,默认为0.0  因为如果取最大的向量数,会导致程序溢出,则只取前100向量

        for(int i = 0;i < 500; i ++) {
            try   
            {       
                File f = new File(FileAddr1 + "school_" + String.valueOf(i+1) + "_C.txt");      
                if(f.isFile()&&f.exists())  
                {       
                    InputStreamReader read = new InputStreamReader(new FileInputStream(f),"utf-8");       
                    BufferedReader reader=new BufferedReader(read);       
                    String line;       
                    while ((line = reader.readLine()) != null)   
                    {        
                        fileContent1 += line + "\n";       
                    }         
                    read.close();      
                }
                Map<String, Integer> fileContent1TfMap=TfIdfAlgorithm.segStr(fileContent1);
                List<Map.Entry<String, Integer>> fileContent1List = new ArrayList<Map.Entry<String, Integer>>(fileContent1TfMap.entrySet());
                //获取每个文章的向量
                for(int j = 0; j < 98; j ++) {
                    CV[i][j] = fileContent1List.get(j).getValue().doubleValue();
                }

                //倒数第二位记录这是哪个文章,即文章的编号
                CV[i][98] = i+1;


            } catch (Exception ee)   
            {         
                ee.printStackTrace();     
            } 
        }
        //返回所有文档的向量
        return CV;
    }

    public static double[][] kmeans(){
        KmeansTest km = new KmeansTest();
        double CV[][] = km.getVectors();
        double CP[][] = new double[20][100];
        double CPM[] = new double[500];  //新中心点的暂时存放
        //1.初始化中心点(取前20个点为中心点)
        for(int i = 0; i < 20; i ++) {
            for(int j = 0; j < 100; j ++ ) {
                CP[i][j] = CV[i][j];
            }
            CP[i][99] = 1.0; //最后一位为1则表示此点为中心点,为0则表示普通点(默认为0)
            CV[i][99] = 1.0; //最后一位为1则表示此点为中心点,为0则表示普通点(默认为0)


        }

        //输出第一次的中心点
        System.out.println("** 第1次初始化的中心点: **");
        for(int i = 0; i < 20; i ++) {
            System.out.print((int)CP[i][98] + " | ");
        }


        //初始化聚类记录
        for(int i = 0; i < 500; i ++) {
            CPR[i] = -1;
        }


        //2.计算剩余文章与中心点的余弦距离最小的,进行聚类
        for(int j = 0; j < 500; j ++) {
            if(CV[j][99] != 1.0) {//非中心点
//          System.out.println("j = "+String.valueOf(j));
            for(int i = 0; i < 20; i ++) { 
                for(int k = 0; k < 98; k ++) {
                    temp0 = temp0 + CV[j][k] * CP[i][k];
                    temp1 = temp1 + CV[j][k] * CV[j][k];
                    temp2 = temp2 + CP[i][k] * CP[i][k];
                }
                temp = temp0/(Math.sqrt(temp1)*Math.sqrt(temp2));
                if(i == 0) {
                    minV = temp;
                    minI = 0;
                }else if(minV > temp) {
                    minV = temp;
                    minI = i;
                }
                if(i == 19) {
                    CPR[j] = minI; //记录剩余的文章与20个中心文章余弦距离最小的序号
//                  System.out.println("minI: "+String.valueOf(minI) + "--"+String.valueOf(j)+"--"+String.valueOf(minV));
                }
                }
            }
        }

        //3.显示第一次聚类的结果
        System.out.println("\n=====第1次聚类的结果:=====");
        for(int i = 0; i < 20; i ++) {
            System.out.print(String.valueOf(i)+" : ");
            for(int j = 0; j < 500; j ++) {
                if(CPR[j] == i) {
                    System.out.print(String.valueOf(j)+" / ");
                }
            }
            System.out.println();
        }



        //4.重新计算中心点
        //4.1计算新的伪中心点
        int dex;
        for(int i = 0; i < 20; i ++) {
            //聚类数目初始化
            dex = 1;
            //CPM初始化
            for(int k = 0; k < 500; k ++) {
                CPM[k] = 0;
            }
            //
            for(int j = 0; j < 500; j ++) { 
                if(CV[j][99] != 1.0) {//如果为普通点
                    if(CPR[j] == i) { 
                        for(int m = 0; m < 98; m ++) {
                            CPM[m] += CP[i][m] + CV[j][m];
                            dex ++;
                        }
                    }
                }
            }
            for(int n = 0; n < 98; n ++) {//获取该类的平均值点,准备计算新的中心点
                if(dex == 1) {
                    CPM[n] = CP[i][n];
                }else {
                    CPM[n] = CPM[n] / dex;
                }
            }
//          System.out.println("\n** 计算得到的伪中心点: **");
//          for(int n = 0; n < 98; n ++) {//获取该类的平均值点,准备计算新的中心点
//              System.out.print(String.valueOf(CPM[n]) + " ");
//          }
//          System.out.println("\n");


            //4.2计算新的实际中心点
            int isfirst = -1;
            for(int j = 0; j < 500; j ++) {//以最靠近新的中心点的点为新的中心点
                if(dex == 1) {
                    //中心点不变,不做操作
                }else if(CV[j][99] != 1.0) { //非中心点
                    for(int m = 0; m < 98; m ++) {
                        temp0 = CV[j][m] * CPM[m];
                        temp1 = CV[j][m] * CV[j][m];
                        temp2 = CPM[m] * CPM[m];
                    }
                    temp = temp0/(Math.sqrt(temp1)*Math.sqrt(temp2));
                    if(isfirst == -1) {
                        isfirst *= -1;
                        minV = temp;
                        minI = j;
                    }else if(temp < minV) {
                        minV = temp;
                        minI = j;
                    }
                    if(j == 499) {
                        //更新中心点
                        for(int m = 0; m < 97; m ++) {
                            CP[i][m] = CV[minI][m];
                        }
                        CP[i][98] = CV[minI][98];
                        //已经变成中心点的改变中心点标志
                        CV[minI][99] = 1;
                    }
                }
            }
        }
        //输出第二次的中心点
        System.out.println("\n\n\n** 第2次初始化的中心点: **");
        for(int i = 0; i < 20; i ++) {
//          for(int j = 0; j < 100; j ++ ) {
//              System.out.print(CP[i][j] + " ");
//          }
            System.out.print((int)CP[i][98] + " | ");
        }



        System.out.println("\n\n\n** 继续聚类: **");

        //接下来进行“重复”聚类工作
        //聚类完成标志
        boolean isStop = false;
        int ndex = 2;
        while(true) {
            //1.初始化
            //初始化CV中非中心点的中心点标志为0,为中心点的标号为1
            for(int i = 0; i < 500; i ++) {
                CV[i][99] = 0;
            }
            for(int j = 0; j < 20; j ++) {
                for(int i = 0; i < 500; i ++) {
                    if(CP[j][98] == CV[i][98]) {
                        CV[i][99] = 1;
                    }
                }
            }
            //初始化聚类记录
            for(int i = 0; i < 500; i ++) {
                CPR[i] = -1;
            } 

            //2.计算剩余文章与中心点的余弦距离最小的,进行聚类
            for(int j = 0; j < 500; j ++) {
                if(CV[j][99] != 1.0) {  //非中心点
//              System.out.println("j = "+String.valueOf(j));
                for(int i = 0; i < 20; i ++) {
                    for(int k = 0; k < 98; k ++) {
                        temp0 = temp0 + CV[j][k] * CP[i][k];
                        temp1 = temp1 + CV[j][k] * CV[j][k];
                        temp2 = temp2 + CP[i][k] * CP[i][k];
                    }
                    temp = temp0/(Math.sqrt(temp1)*Math.sqrt(temp2));
                    if(i == 0) {
                        minV = temp;
                        minI = 0;
                    }else if(minV > temp) {
                        minV = temp;
                        minI = i;
                    }
                    if(i == 19) {
                        CPR[j] = (int)CP[minI][98]; //记录剩余的80个文章中的该文章与20个中心文章余弦距离最小的序号
//                      System.out.println("minI: "+String.valueOf(minI) + "--"+String.valueOf(j)+"--"+String.valueOf(minV));
                    }
                    }
                }
            }

            //3.显示第n次聚类的结果
            System.out.println("\n=====第"+(ndex++)+"次聚类的结果:=====");
            for(int i = 0; i < 20; i ++) {
                System.out.print((int)CP[i][98]+" : ");
                for(int j = 0; j < 500; j ++) {
                    if(CPR[j] == CP[i][98]) {
                        System.out.print(String.valueOf(j)+" / ");
                    }
                }
                System.out.println();
            }

            //4.重新计算中心点
            //4.1计算新的伪中心点
            int dex1;
            for(int i = 0; i < 20; i ++) {
                //聚类数目初始化
                dex = 1;
                //CPM初始化
                for(int k = 0; k < 500; k ++) {
                    CPM[k] = 0;
                }
                //
                for(int j = 0; j < 500; j ++) { 
                    if(CV[j][99] != 1.0) {//如果为普通点
                        if(CPR[j] == i) { 
                            for(int m = 0; m < 98; m ++) {
                                CPM[m] += CP[i][m] + CV[j][m];
                                dex ++;
                            }
                        }
                    }
                }
                for(int n = 0; n < 98; n ++) {//获取该类的平均值点,准备计算新的中心点
                    if(dex == 1) {
                        CPM[n] = CP[i][n];
                    }else {
                        CPM[n] = CPM[n] / dex;
                    }
                }
//              System.out.println("\n** 计算得到的伪中心点: **");
//              for(int n = 0; n < 98; n ++) {//获取该类的平均值点,准备计算新的中心点
//                  System.out.print(String.valueOf(CPM[n]) + " ");
//              }
//              System.out.println("\n");
                //4.2计算新的实际中心点
                int isfirst = -1;
                for(int j = 0; j < 500; j ++) {//以最靠近新的中心点的点为新的中心点
                    if(dex == 1) {
                        //中心点不变,不做操作
                    }else if(CV[j][99] != 1.0) { //非中心点
                        for(int m = 0; m < 98; m ++) {
                            temp0 = CV[j][m] * CPM[m];
                            temp1 = CV[j][m] * CV[j][m];
                            temp2 = CPM[m] * CPM[m];
                        }
                        temp = temp0/(Math.sqrt(temp1)*Math.sqrt(temp2));
                        if(isfirst == -1) {
                            isfirst *= -1;
                            minV = temp;
                            minI = j;
                        }else if(temp < minV) {
                            minV = temp;
                            minI = j;
                        }
                        if(j == 499) {
                            //更新中心点
                            for(int m = 0; m < 98; m ++) {
                                CP[i][m] = CV[minI][m];
                            }
                            CP[i][98] = CV[minI][98];
                            //已经变成中心点的改变中心点标志
                            CV[minI][99] = 1;
                            //标识已参与聚类
                            CV[minI][97] = 1;
                        }

                    }
                }
            }

            if(ndex == 10) {
                System.out.println("\n\n* 聚类结束,共聚类" + ndex + "次*");
                break;
            }
            //输出第n次的中心点
            System.out.println("\n\n\n** 第"+ndex+"次初始化的中心点: **");
            for(int i = 0; i < 20; i ++) {
                System.out.print((int)CP[i][98] + " | ");
            }
        }
        return CP;
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis(); 
        KmeansTest kk = new KmeansTest();
        double CVV[][] = kk.kmeans();
        long end = System.currentTimeMillis();        
        System.out.println("运行时间:"+(end-start)/1000+"秒");
    }
}

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值