位置信息倒排索引K词近邻搜索算法实现
2014-07-27 01:02
1346 查看
位置信息索引是在倒排索引的基础上实现的,在倒排记录表中添加了词项在文档中的位置信息。位置信息一般以下面的方式存储到倒排记录中:
以图中一个倒排记录为例,to是此项,993427为to的文档频率,即在993427篇文档中出现。最外层的括号中,1,2,4,5,7是包含to的文档ID,这里只列出5个,文档ID后是to的词频,即to在文档中出现的次数。最后内层的括号中即to在文档中的位置信息,以对文档开头的偏移量来表示。有了这“强化”过后的倒排索引表,我们可以对倒排索引查询的功能进行扩展。而这次我带来的是基于位置信息的倒排索引K词近邻搜索算法的实现,具体的含义就是对两个词项进行搜索,可规定两个词项在文档中的间隔。
举个例子:某个查询为to be or not to be,我们只看to be,to与be是挨着的,也就是说间隔k为0个词。首先,查找同时包含这两个词项的文档;然后,检查表中的位置看看是否有某个be的前面一个词条位置上正好出现to。下面中给出的倒排记录表中,可能存在的一个匹配为:
本文中给出的算法来源于《信息检索导论》一书中,王斌翻译,书中给出了算法伪代码。另外我的算法实现是在课程结束之后完成的,JAVA写的,只是很单纯的实现,代码写得也比较差劲,不值得拿来做研究使用,只是贴出来给大家进行参考。下面给出代码和索引文件。
下面是索引文件Index.txt截图,倒排记录间隔的符号是规定好的,方便程序中对各部分的划分。索引是手动构建的,并非使用程序构建。
文档ID:(位置1,位置2,…)而完整的包含位置信息的倒排记录表如下图所示:
以图中一个倒排记录为例,to是此项,993427为to的文档频率,即在993427篇文档中出现。最外层的括号中,1,2,4,5,7是包含to的文档ID,这里只列出5个,文档ID后是to的词频,即to在文档中出现的次数。最后内层的括号中即to在文档中的位置信息,以对文档开头的偏移量来表示。有了这“强化”过后的倒排索引表,我们可以对倒排索引查询的功能进行扩展。而这次我带来的是基于位置信息的倒排索引K词近邻搜索算法的实现,具体的含义就是对两个词项进行搜索,可规定两个词项在文档中的间隔。
举个例子:某个查询为to be or not to be,我们只看to be,to与be是挨着的,也就是说间隔k为0个词。首先,查找同时包含这两个词项的文档;然后,检查表中的位置看看是否有某个be的前面一个词条位置上正好出现to。下面中给出的倒排记录表中,可能存在的一个匹配为:
to: 〈. . . ; 4: 〈. . . ,429,433〉; . . . 〉 be: 〈. . . ; 4: 〈 . . ,430,434〉; . . . 〉
本文中给出的算法来源于《信息检索导论》一书中,王斌翻译,书中给出了算法伪代码。另外我的算法实现是在课程结束之后完成的,JAVA写的,只是很单纯的实现,代码写得也比较差劲,不值得拿来做研究使用,只是贴出来给大家进行参考。下面给出代码和索引文件。
import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import javax.annotation.PostConstruct; public class PositionalIndex { public PositionalIndex() { // TODO Auto-generated constructor stub //LTerm = new ArrayList<String>(); //LPostingList = new ArrayList<String>(); } @SuppressWarnings("resource") /******************** 按词条搜索出对应的倒排记录******************/ public static String findPostingList(String term) { List<String> LTerm = new ArrayList<>(); String szPostingList = ""; File file = new File("bin/Index.txt"); //读出倒排记录表文件 String szTermAndPosting; String szSub; //StringTokenizer szToken = null; BufferedReader br =null; int iSplitIndex; try { br = new BufferedReader(new FileReader(file)); while((szTermAndPosting = br.readLine())!=null) //按行读取出一条倒排记录 { iSplitIndex = szTermAndPosting.indexOf(","); //按','划分倒排记录 szSub = szTermAndPosting.substring(0, iSplitIndex); //得到词项 szSub.trim(); if(term.equals(szSub)) //判断搜索词条与词项是否匹配 { LTerm.add(term); iSplitIndex = szTermAndPosting.indexOf(":"); //划分文档频率与倒排记录 szSub = szTermAndPosting.substring(iSplitIndex+1); //得到倒排记录 //szSub = szSub.substring(iSplitIndex+1); szPostingList += szSub; break; } } br.close(); } catch(Exception e){} return szPostingList; //返回倒排记录 } /***********************根据k值来搜索出倒排记录表中间隔小于k的文档列表**************************/ public static List<String> PosIntersect(String termAndpList_1,String termAndpList_2,int k) { List<String> LAns = new ArrayList<>(); StringTokenizer strToken; List<String> szTerm_1 = new ArrayList<>(),szTerm_2 = new ArrayList<>(); List<String> szPList_1 = new ArrayList<>(),szPList_2 = new ArrayList<>(); //倒排记录 int iDocID_1,iDocID_2; List<String> LtermAndList_1 = new ArrayList<>(),LtermAndList_2 = new ArrayList<>(); strToken = new StringTokenizer(termAndpList_1, ";"); //按';'划分倒排记录 while(strToken.hasMoreTokens()) { LtermAndList_1.add(strToken.nextToken()); //文档id+位置信息 } strToken = new StringTokenizer(termAndpList_2, ";"); while(strToken.hasMoreTokens()) { LtermAndList_2.add(strToken.nextToken()); } for(int i = 0,j = 0;i<LtermAndList_1.size()&&j<LtermAndList_2.size();) { strToken = new StringTokenizer(LtermAndList_1.get(i)," "); //划分文档id+位置信息 szTerm_1.add(strToken.nextToken()); szPList_1.add(strToken.nextToken()); //位置信息 strToken = new StringTokenizer(LtermAndList_2.get(j), " "); szTerm_2.add(strToken.nextToken()); szPList_2.add(strToken.nextToken()); int iSplitIndex = szTerm_1.get(i).indexOf(","); iDocID_1 = Integer.parseInt(szTerm_1.get(i).substring(0, iSplitIndex)); //得到文档id iSplitIndex = szTerm_2.get(i).indexOf(","); iDocID_2 = Integer.parseInt(szTerm_2.get(j).substring(0, iSplitIndex)); /******************两个倒排记录根据文档id号进行比较*********************/ if(iDocID_1 == iDocID_2) //判断倒排记录中相同的文档 { List<String> Ltemp = new ArrayList<>(); List<String> Lposting_1 = new ArrayList<>(); List<String> Lposting_2 = new ArrayList<>(); StringTokenizer szPostingToken = new StringTokenizer(szPList_1.get(i),","); //划分位置信息 while(szPostingToken.hasMoreTokens()) { Lposting_1.add(szPostingToken.nextToken()); } szPostingToken = new StringTokenizer(szPList_2.get(j),","); while(szPostingToken.hasMoreTokens()) { Lposting_2.add(szPostingToken.nextToken()); } for(int p=0;p<Lposting_1.size();p++) { for(int q=0;q<Lposting_2.size();q++) { if(Math.abs(Integer.parseInt(Lposting_1.get(p))-Integer.parseInt(Lposting_2.get(q)))<=k) //计算文档中词项之间的距离与k进行比较 { Ltemp.add(Lposting_2.get(q)); //将与Lposting_1中位置相比符合条件的Lposting_2的位置信息进行存储 } else if(Integer.parseInt(Lposting_2.get(q))>Integer.parseInt(Lposting_1.get(p))) break; } /*for(int x=0;x<Ltemp.size()&&Math.abs(Integer.parseInt(Ltemp.get(x))-Integer.parseInt(Lposting_1.get(p)))>k;x++) { Ltemp.remove(0); }*/ for(int x=0;x<Ltemp.size();x++) { String ansTemp = Integer.toString(iDocID_1)+","+Lposting_1.get(p)+","+Ltemp.get(x); //将与Lposting_1比较符合条件的Ltemp中的位置信息组合成字符串进行存储 LAns.add(ansTemp); } Ltemp.clear(); } i++;j++; } else if(iDocID_1<iDocID_2) //iDocID_1<iDocID_2,IDocID_1的序号+1 i++; else j++; //同理,IDocID_2的序号+1,返回继续比较 } return LAns; } /** * @param args * @throws IOException */ public static void main(String[] args){ // TODO Auto-generated method stub String sztermAndpList_1 ; //词条与倒排记录 String sztermAndpList_2 ; String szReadline; String szTerm_1; //词条 String szTerm_2; int k; BufferedR 4000 eader Stdin = new BufferedReader(new InputStreamReader(System.in)); try { while((szReadline = Stdin.readLine())!=null&&!szReadline.equals("exit")) //控制台输入,exit退出 { List<String> LAnswer = new ArrayList<>(); StringTokenizer szArgsToken = new StringTokenizer(szReadline," "); //按空格划分出词条 szTerm_1 = szArgsToken.nextToken(); szTerm_2 = szArgsToken.nextToken(); k = Integer.parseInt(szArgsToken.nextToken()); //划分出k值 sztermAndpList_1 = findPostingList(szTerm_1); //按词条得出词项倒排记录组 sztermAndpList_2 = findPostingList(szTerm_2); LAnswer = PosIntersect(sztermAndpList_1, sztermAndpList_2, k); //存储结果 if(LAnswer.size()==0) //输出 System.out.println("not found..."); for(int i=0;i<LAnswer.size();i++) System.out.println(LAnswer.get(i)); } Stdin.close(); } catch(IOException e){} } }
下面是索引文件Index.txt截图,倒排记录间隔的符号是规定好的,方便程序中对各部分的划分。索引是手动构建的,并非使用程序构建。
相关文章推荐
- 一段有意思的代码:类实现中将信息存储到其他位置
- 脚本实现记录所有登录用户的信息,包括用户名、登录时间和登录位置
- iOS 地图显示比例设置 (这里是当前的位置信息代理方法中实现)
- Android中Xposed框架篇---修改系统位置信息实现自身隐藏功能
- Android中Xposed框架篇---修改系统位置信息实现自身隐藏功能实例
- 用SQLServer实现数据表中,将任意一条记录信息移动到该表中的任意位置
- Android中Xposed框架篇—修改系统位置信息实现自身隐藏功能
- Yii2实现表单客户端验证提示信息出现在指定位置
- AngularJS进阶(二十)HTML5实现获取地理位置信息并定位功能
- 利用jQuery插件imgAreaSelect实现图片上传裁剪(同步显示图像位置信息)
- 实现输入的四个数字找出最大最小并指出位置信息 动手修改程序3
- 求助!用openlayers如何实现读入数据库的地理位置信息,然后进行实时同步定位??万分感谢!
- 利用修改div的位置+js对象存储div信息 实现简单的div自定义布局功能
- C++实现在文本中找出某个单词的位置信息
- iOS:实现MKAnnotation协议,在地图上设置大头针,点击显示具体的位置信息
- 实现在编辑区位置显示收信人统计信息
- 用SQLServer实现数据表中,将任意一条记录信息移动到该表中的任意位置
- 基于thinkphp实现根据用户ip判断地理位置并提供对应天气信息的应用
- iOS版微信朋友圈识别图片位置信息 如何实现?
- iOS - 定位功能/获取当前位置信息的实现