基于lucene的索引和搜索功能的简单实现

基于lucene的索引和搜索功能的简单实现

Posted by dym on January 21, 2014

本文迁移自老博客,原始链接为 https://seven.blog.ustc.edu.cn/%e5%9f%ba%e4%ba%8elucene%e7%9a%84%e7%b4%a2%e5%bc%95%e5%92%8c%e6%90%9c%e7%b4%a2%e5%8a%9f%e8%83%bd%e7%9a%84%e7%ae%80%e5%8d%95%e5%ae%9e%e7%8e%b0/

首先是爬取网络上的资源,并提取出每个资源的描述信息,这种描述信息是资源检索的依据,而资源的描述信息的提取和保存是一个非常复杂的过程。本文只是介绍使用开源的搜索框架lucene进行索引和搜索的最简单实现。 本程序中资源的描述信息以一个xml文档的形式提供。每个资源服务器上的xml文件保存了这个服务器上所有资源的描述信息,它充当了一个数据库的角色。 关于资源xml文档的格式,下面进行一个详细的说明: <?xml version=”1.0” encoding=”UTF-8”?>// XML头部,显式定义文档使用UTF-8作为编码方式,以广泛地支持各种字符集。 <allresource  host=”192.168.0.2”  remote=”192.168.0.1”>//资源xml的根元素,代表该资源服务器上所有的资源,它有两个属性,一个是host,代表了这个资源服务器的ip地址,另一个是remote,代表了这个资源服务器需要向哪一个服务器去注册发布自己的信息。 <resourceitem>  //表示一条资源记录,下面的子结点是这个资源记录的描述信息。 <id>//为方便检索设置,为新增内容,这个id是该资源服务器上资源的唯一标识,是以1为增量不断递增的一个数字。 <title> //资源的标题信息,是该资源的一个概括性的标题描述。 <keywords> //资源关键字,3-5个,是从该资源提取的关键字信息。 <kind> //资源类型(资源文件的扩展名)。 <describe>/ /资源具体详细描述。 <date>  //资源在这个服务器上的发布日期 <url> //资源可访问的url地址,通过这个地址可以下载该资源或对这个资源进行预览和播放。 <author> //该资源的作者。 <publisher> //该资源的发布单位。 一、索引的建立: 1.数据源的预处理 读取xml数据源的节点信息,封装到javabean中,关键代码如下:

org.dom4j.Document doc = saxReader.read(fis);   
	  list = doc.selectNodes("/allresource//resourceitem");
      for(Iterator<?>  iterator =  list.iterator();iterator.hasNext();) {
		   result=new xmlbean();//每次循环都要新建一个新的Javabean对象;
		   Element element1 = (Element)iterator.next();
		   result.setTitle(( element1).selectSingleNode("title").getText());
		   result.setKeywords((( element1).selectSingleNode("keywords").getText()));
		   result.setKind(( element1).selectSingleNode("kind").getText());
		   result.setDescribe(( element1).selectSingleNode("describe").getText());
		   SearchResult.add(result);
		}

2.倒排索引的建立 建立索引主要是实现对document对象的封装。建立索引的关键代码如下:

for(int i = 0; i < SearchResult.size(); i++){
	xmlbean resource=SearchResult.get(i);
	Document document = new Document();    		  
	Title=newField("title", resource.getTitle(), Field.Store.YES, Field.Index.TOKENIZED);
	Keywords=newField("keywords",resource.getKeywords(),Field.Store.YES,Field.Index.TOKENIZED,TermVector.YES);
	Kind=newField("kind",resource.getKind(),Field.Store.YES,Field.Index.UN_TOKENIZED);
	Describe=newField("describe",resource.getDescribe(),Field.Store.YES,Field.Index.TOKENIZED);document.add(Title);	
	document.add(Keywords);	
	document.add(Kind);
	document.add(Describe);
	indexWriter.addDocument(document);	
	filenum++;
}

建立索引以及后续搜索时所采用的分词技术使用的Jeasy分词器,效果较好,默认是正向最大匹配的,实现类:MMAnalyzer。

public static  void doAnalyze(String key){
    	MMAnalyzer analyzer = new MMAnalyzer();
   	 	String[] s= new String[100];
    	Reader r= new StringReader(key);
    	TokenStream ts = (TokenStream)analyzer.tokenStream("",r);
    	org.apache.lucene.analysis.Token t;
    	t=ts.next();
    	for(int i=0;t!=null;i++,t=ts.next()){
    		s[i]=t.termText();}
    		str=new String[i];
    		for(int j=0;j<i;j++){
    			str[j]=s[j];
		}
         }
}

二、扩展基于lucene的搜索方法 下面以普通搜索为例讲述搜索方法的定制。 普通搜索对象的封装:

IndexSearcher searcher = new IndexSearcher(filepath);
for(int i=0;i<keyword.length;i++){
	TermQuery luceneQuery1 = new TermQuery(new Term("title",keyword[i]));
	TermQuery luceneQuery2 = new TermQuery(new Term("keywords",keyword[i]));
	TermQuery luceneQuery3 = new TermQuery(new Term("kind",keyword[i]));
	multiKeys.add(luceneQuery1, BooleanClause.Occur.SHOULD);
	multiKeys.add(luceneQuery2, BooleanClause.Occur.SHOULD);
	multiKeys.add(luceneQuery3, BooleanClause.Occur.SHOULD);
}

得到结果集: hits = searcher.search(multiKeys);然后遍历结果集,将搜索到的数据做一定的处理,如高亮显示,最后封装到javabean,存入新的结果集合中,然后将javabean返回指定页面,通过相应标签进行调用,代码省略。