信息检索作业

来源:互联网 发布:c语言初始化程序 编辑:程序博客网 时间:2024/05/22 06:11
# -*- coding:utf-8 -*-  require './stemmable.rb'        #词干还原代码require './correct2.rb'         #peter novig拼写检查代码class Stringinclude Stemmable   #字符串类包含进 词干还原模块, 字符串可以使用stem函数进行词干还原endwordCountHash=Hash.new          #记录每个单词出现的频率fileListArray=Array.new         #检索对象文档集合reverseIndexArray=Array.new     #倒排记录表wordDfLocHash=Hash.new          #字典,用ruby的hash类实现docLenArray=Array.new           #记录文件距离 即每个文档的每个单词的权值平方和的二次根docNum=0                        #检索对象文档树木def fileList(docPath, fileListArray)    #获取指定路径下的所有文件名 并将文件名保存到数组 fileListArray 中nowPwd=Dir.pwd                  #获取当前路径Dir.chdir(docPath)              #将当前工作目录改为 检索对象集合 所在路径Dir.foreach("./"){|fileName| fileListArray.push(fileName) if(fileName!="." && fileName!="..")}#将路径下所有文件名 存入 数组 fileList中。 会包含. ..目录,需要剔除掉 只支持一层目录#fileList=%x(ls)#fileList.scan(/[a-zA-Z0-9_\.]+/){|fileName| fileListArray.push(fileName)}Dir.chdir(nowPwd)              #将当前工作目录 改为 最初的目录enddef file2word(docPath, fileName, fileID)           #将文件fileName文件 中的单词 放入wcHash中并返回wcHash=Hash.new                        #单词计数 的 hash结构nowPwd=Dir.pwd                         #保存当前工作目录Dir.chdir(docPath)                     #改变工作目录到 检索对象集合 所在目录docfh=File.open(fileName, 'r')              #打开文件fileNamewordArray=Array.new                         #保存文件中 词干还原处理过后 的单词docfh.readline.downcase.scan(/[a-z]+/){|word| wordArray.push(word.stem)} until docfh.eof wordArray.sort!        #对单词数组进行排序wordArray.each do |word|                if(word=="is" or word=="who" or word=="a" or word=="to")                         #去除停用词                  next                endif(wcHash[word])                                   #如果hash结构中存在该单词, 该单词计数+1wcHash[word][1]=wcHash[word][1]+1elsewcHash[word]=[fileID, 1]                   #如果hash结构中不存在该单词, 将该单词加入hash结构中,并加入当前文档ID, 单词计数为1endend       # p "xxxxxxxxxxxxxxxxxxxx\n"        #p wcHashDir.chdir(nowPwd)             #将当前工作目录进行恢复return wcHash                 #返回hash结构        enddef makeReverseIndex(wordCountHash, reverseIndexArray, wordDfLocHash)  #创建 词典 与 倒排记录表count=0wordCountHash.each do |key, value|#p wordCountHash[key]#p "========================="reverseIndexArray.push(value)                    #将 [ [文档ID,单词计数], ... ]信息存入倒排记录表wordDfLocHash[key]=[wordCountHash[key].length, count]   #将对应的单词的 [出现该单词的文档数, 该单词所在倒排记录表的位置] 存入词典count+=1                                         #位置信息+1endenddef df2idf(wordDfLocHash, docNum) #计算idf值       # p wordDfLocHash       # p docNumwordDfLocHash.each do |key, value|value[0]=Math.log(docNum.to_f/value[0], 10)   #计算log(N/df)end        #p "iiiiiiiiiiiiiiiiiiiiiii\n"        #p wordDfLocHashenddef tf2tftd(reverseIndexArray) #计算tftd值reverseIndexArray.each do |valueArray|      #对倒排记录表中每一个文档记录的单词频率进行处理 1+log(tf)valueArray.each do |value|value[1]=1+Math.log(value[1], 10)endendenddef tfdf2w(wordDfLocHash, reverseIndexArray)       #计算(1+log(tf))*log(N/df)wordDfLocHash.each do |key, value|idf=value[0]loc=value[1]reverseIndexArray[loc].each do |value|value[1]=value[1]*idfendendenddef makeDocLen(docLenArray, reverseIndexArray)    #计算每个文件的 距离#p docLenArrayreverseIndexArray.each do |valueArray|valueArray.each do |value|docLenArray[value[0]]=docLenArray[value[0]]+value[1]*value[1]endend#p docLenArraydocLenArray.each_index do |index|docLenArray[index]=Math.sqrt(docLenArray[index])end#p docLenArrayendfileList(ARGV[0], fileListArray)   #返回指定 检索集合目录 下的所有文件名数组p fileListArrayfileListArray.sort!                #对文件名数组进行排序#puts fileListArraydocNum=fileListArray.length        #得到检索对象集合 的文档 总数#fileListArray.each_index{|index| p "#{index}: #{fileListArray[index]}"}fileListArray.each_index do |fileID|             #对每一个属于检索对象集合的文件进行处理wcHash=file2word(ARGV[0], fileListArray[fileID], fileID)   #返回当前文件的单词hash结构  “word” => [文档ID, 文档ID中"word"的个数]#p wcHashwcHash.each do |key, value|if(wordCountHash[key])                 #如果所有文档单词hash中存在当前单词,则把当前文档的该单词信息存入所有文档单词hash中wordCountHash[key].push(value)elsewordCountHash[key]=Array.new.push(value)   #如果不存在,则对该单词(作为key)创建新的valueendend#wordCountHash.merge!(wcHash) do |key, oldval, newval|#oldval.push(newval)#p wordCountHashend                                                      # wordCountHash: {"word" => [ [文档ID, 该单词计数], [文档ID, 该单词计数] ]}#p wordCountHashmakeReverseIndex(wordCountHash, reverseIndexArray, wordDfLocHash)   #生成倒排记录表#p "============================================\n"#p reverseIndexArray#p "============================================\n"#p wordDfLocHash#p wordDfLocHashdf2idf(wordDfLocHash, docNum)    #计算log(N/df)#p wordDfLocHash#p docNumdocLenArray=Array.new(docNum, 0)   #docLenArray数组保存的 文档距离#p reverseIndexArraytf2tftd(reverseIndexArray)         #计算1+log(tf)#p "aaaaaaaaaaaaaaaaaaaaaaaaa\n"#p reverseIndexArray#p "cccccccccccccccccccccc\n"#p wordDfLocHashtfdf2w(wordDfLocHash, reverseIndexArray)  #计算(1+log(tf))*log(N/df)#p "=================================================="#p reverseIndexArraymakeDocLen(docLenArray, reverseIndexArray)  #计算每个文档 距离#p docLenArrayprint "===========OK============\n"   #索引建立完成def queryFunc(queryArray, wordDfLocHash, reverseIndexArray, fileListArray, docLenArray)   #实现查询函数positionArray=Array.new       qPositionArray=Array.newqReverseIndexArray=Array.newresultArray=Array.new        tmpResultArray=Array.newqueryArray.each_index do |index|         #对 查询数组 中的每个单词进行 词干还原queryArray[index]=queryArray[index].stem        end        queryArray.each do |value|      #如果 查询数组 中的单词在 词典 中,输出"We find word"          if(wordDfLocHash.has_key?(value))            puts "We find #{value}"          end        end#p queryArrayqueryArray.each do |word|      #根据 词典 中查询数组中每个单词 所在 倒排记录表 的位置存入数组positionArrayif(wordDfLocHash.has_key?(word))  positionArray.push(wordDfLocHash[word][1])#positionArray.sort!{|x, y| reverseIndexArray[x].length <=> reverseIndexArray[y].length}endendpositionArray.sort!{|x, y| reverseIndexArray[x].length <=> reverseIndexArray[y].length}  #将 位置信息 按照该位置元素所对应的倒排记录表记录项的长度进行排序(从小到大,从而最大限度减小 求交集的时间)if(positionArray.empty?) #如果位置信息数组为空,说明查询中的单词没有一个在字典中,输出"No doc matched"并退出print "No doc matched\n"returnend#p positionArray        reverseIndexArray[positionArray[0]].each do |value| #将位置信息中第一个 单词 的 倒排记录表内容存入结果数组中,然后与剩余其他的所有数组进行求交集操作          resultArray.push(value)        end       # p "cccccccccccccccccccc\n"       # p resultArray       # p "dddddddddddddddddddd\n" #       p reverseIndexArraypositionArray.each_index do |index|   #求交集并将文档中所有单词的权重相加       #   p "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\n"          position1=0          position2=0        #  p "resultArray: #{resultArray}"          if(index!=0)   #因为第一个数组信息已经存入结果中,所以从第2个开始求交            tmpResultArray=[]         #   p "timsssssssssssssssss\n"          #  p "position1=#{position1}"           # p "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n"           # p resultArray           # p reverseIndexArray[positionArray[index]]            while(resultArray[position1]!=nil and reverseIndexArray[positionArray[index]][position2]!=nil)              if(resultArray[position1][0]==reverseIndexArray[positionArray[index]][position2][0])                tmpResultArray.push([reverseIndexArray[positionArray[index]][position2][0], resultArray[position1][1]+reverseIndexArray[positionArray[index]][position2][1]])                position1+=1                position2+=1              elsif(resultArray[position1][0]<reverseIndexArray[positionArray[index]][position2][0])                position1+=1              else                position2+=1              end            end  #          p "index :#{index}"   #         p "tmpResultArray:#{tmpResultArray}"    #        p "resultArray   :#{resultArray}"            resultArray=[]            tmpResultArray.each do |value|              resultArray.push(value)            end          end          #resultArray, tmpResultArray=tmpResultArray, resultArray          #tmpResultArray.each do |value|          #  resultArray.push(value)          #endend     #   p "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"      #  p resultArray      #  p tmpResultArray        resultArray.each_index do |index|     #查询结果文档的单词权重之和除以该文档距离          resultArray[index][1]=resultArray[index][1]/docLenArray[resultArray[index][0]]        end        resultArray.sort!{|x, y| x[1] <=> y[1]}  #对查询结果按照权值大小进行排序(从小到大)        resultArray.reverse!  #求逆序 (从大到小)        resultArray.each_index do |index|  #输出排序结果          if(index<10)            print "rank: #{index+1}  \tfileName: ", fileListArray[resultArray[index][0]].ljust(30, ' '),"value:#{resultArray[index][1]}\n"          end        end     #   p "docLenArray: #{docLenArray}"     #   p "reverseIndexArray: #{reverseIndexArray}"     #   p "wordDfLocHash: #{wordDfLocHash}"#p wordDfLocHash#p reverseIndexArray#p fileListArray#        reverseIndexArray.each do |value|#          p value#        endendqueryArray=Array.newif $0==__FILE__ then#        p $stdin$stdin.each do |query|if(query=~/!!/)exit(0)endqueryArray=[]query.scan(/[a-zA-Z]+/){|word| queryArray.push(word) }#puts queryArray                cQueryArray=Array.new                allCorrect=1                queryArray.each do |word|                  cWord=correct(word)                  cQueryArray.push(cWord)                  if(cWord!=word)                    allCorrect=0                  end                end                print "The query you input: #{queryArray}\n"queryFunc(queryArray, wordDfLocHash, reverseIndexArray, fileListArray, docLenArray)                print "==========================================\n"                if(allCorrect==0)                  print "The query we correct: #{cQueryArray}\n"  queryFunc(cQueryArray, wordDfLocHash, reverseIndexArray, fileListArray, docLenArray)                  print "==========================================\n"                endendend
ruby read5.rb setPath


0 0
原创粉丝点击