一、lucene2.4的创建和查询及其分词显示

作者: wxwzy738
发布时间:2015-07-08 16:57:43

1、工程目录

2、lucene的创建搜索过程


3、建立索引的示意图



4、硬盘和内存中创建索引示意图


5、lucene的创建及其搜索的代码

package cn.hj.lucene.helloworld; import jeasy.analysis.MMAnalyzer; import org.Apache.lucene.analysis.Analyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Filter; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.highlight.Formatter; import org.apache.lucene.search.highlight.Fragmenter; import org.apache.lucene.search.highlight.Highlighter; import org.apache.lucene.search.highlight.QueryScorer; import org.apache.lucene.search.highlight.Scorer; import org.apache.lucene.search.highlight.SimpleFragmenter; import org.apache.lucene.search.highlight.SimpleHTMLFormatter; import org.junit.Test; import cn.hj.lucene.utils.File2DocumentUtils;  public class HelloWorld { 	//资源文件的路径,也就是要进行索引的文件 //	String filePath = "D:\\Workspaces\\lucenedemo\\luceneDatasource\\IndexWriter addDocument's a javadoc .txt"; 	String filePath = "D:\\Workspaces\\lucenedemo\\luceneDatasource\\小笑话_总统的房间 Room.txt"; 	//索引文件所存放的路径 	String indexPath ="D:\\Workspaces\\lucenedemo\\luceneIndex"; 	//标准分词器 //	Analyzer analyzer = new StandardAnalyzer(); 	Analyzer analyzer = new MMAnalyzer(); 	 	/** 	 * 创建索引 	 * IndexWriter是用来操作(增、删、改)索引库的 	 */ 	@Test 	public void createIndex() throws Exception{ 		Document doc = File2DocumentUtils.file2Document(filePath); 		//可以对某些文档设置权重,数字越大权重越高 		doc.setBoost(3.0f); 		//第三个参数设置为true的话表示每次执行都会创建目录和删除之前文件重新创建 		//	设置为false如果目录不存在会生成目录,但是如果是第一次生成文件的话,会报错, 		//如果原来的索引存在则不会保存,原来的索引文件也不会删除,会再生成一份索引和原来合并 		//第四个参数表示每个字段中有多少个索引词来进行限定的,防止内存溢出等, 		//	比如有一个字段有几十万字,那索引出来的词便会很多 		//MaxFieldLength.LIMITED表示为一万 MaxFieldLength.UNLIMITED表示为无限大 		IndexWriter indexWriter = new IndexWriter(indexPath,analyzer,false,MaxFieldLength.LIMITED); 		indexWriter.addDocument(doc); 		indexWriter.close(); 		System.out.println("create ok..."); 	} 	 	/** 	 * 搜索 	 * IndexSearcher是用来在索引库中进行查询的 	 * @throws Exception  	 */ 	@Test 	public void search() throws Exception{ 		String queryString = "document";//要查询的关键字 		 		//1、把要搜索的文本解析为Query 		String[] fields = {"name","content"};//要在哪些字段上进行查询 		//QueryParser为解析器 		//MultiFieldQueryParser为多个字段的解析器,参数为字段数组和分词器 		QueryParser queryParser = new MultiFieldQueryParser(fields, analyzer); 		//分析器经过解析之后得到一个查询器 		Query query = queryParser.parse(queryString); 		//2、进行查询 		IndexSearcher indexSearcher = new IndexSearcher(indexPath); 		//过滤器是对查询后的结果进行过滤,比如包含哪些词,文件大小超过多少等 		Filter filter = null; 		//过滤器为null为表示没有,不进行过滤 		//第三个参数表示一次查询多少个结果,默认是50,一般1000~10000即可 		//如果设置为1000,但是要取2000条,那么会分两次查询 		 		//得到搜索结果的集合存放入TopDocs中 		TopDocs topDocs = indexSearcher.search(query, filter, 1000); 		int totalHits = topDocs.totalHits; 		System.out.println("共有【"+totalHits+"】条匹配结果."); 		 		//3、打印结果 		//得到的结果并不是真正的结果,只是文档编号的结果,这样数据量少,速度快 		ScoreDoc[] scoreDocs = topDocs.scoreDocs; 		for(ScoreDoc scoreDoc : scoreDocs){ 			int docNum = scoreDoc.doc;//得到文档编号 			Document doc = indexSearcher.doc(docNum);//通过文档编号得到文档 			//在得到文档的时候对关键字来进行高亮显示 			Highlighter highlighter = getHighlighter(query); 			String hc = highlighter.getBestFragment(analyzer, "content", doc.get("content")); 			//返回高亮后的结果,如果当前属性值中没有出现关键字,则返回null 			if(hc != null){ 			//对原来的全部内容进行清除,把摘要信息进行赋值,比如在列表中需要只显示摘要不显示全部信息 				doc.getField("content").setValue(hc); 			} 			File2DocumentUtils.printDocument(doc); 		} 	} 	 	/** 	 * 准备高亮器 	 * @param query 	 */ 	public Highlighter getHighlighter(Query query){ 		//指定要显示的是什么样的格式,这里是直接加红 		Formatter formatter = new SimpleHTMLFormatter("<font color='red'>", "</font>"); 		Scorer scorer = new QueryScorer(query); 		Highlighter highlighter = new Highlighter(formatter, scorer); 		//取关键字出现最频繁的那一段文本附近的指定个数的字符作为摘要 		//截取摘要信息50个字符 		Fragmenter fragmenter = new SimpleFragmenter(50); 		highlighter.setTextFragmenter(fragmenter); 		return highlighter; 	}  }

6、lucene创建索引的两种方式


package cn.hj.lucene.director;  import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.RAMDirectory; import org.junit.Test; import cn.hj.lucene.utils.File2DocumentUtils;  /**  * 创建索引的两种方式  * 1、创建的索引存放在硬盘中  * 2、创建的索引放入内存当中,程序结束索引也消失  */ public class DirectorTest { 	//资源文件的路径,也就是要进行索引的文件 	String filePath = "D:\\Workspaces\\lucenedemo\\luceneDatasource\\IndexWriter addDocument's a javadoc .txt"; 	//索引文件所存放的路径 	String indexPath ="D:\\Workspaces\\lucenedemo\\luceneIndex"; 	//标准分词器 	Analyzer analyzer = new StandardAnalyzer(); 	 	@Test 	public void test1() throws Exception{ //		Directory directory = FSDirectory.getDirectory(indexPath);//硬盘索引 		Directory directory = new RAMDirectory(indexPath);//内存索引 		 		Document doc = File2DocumentUtils.file2Document(filePath); 		//若第一个参数传入文件路径,默认内部会封装成Directory对象 		//create属性不填的话默认第一次会创建,接着的话会重新生成一份和原来的索引合并 		IndexWriter indexWriter = new IndexWriter(directory, analyzer,MaxFieldLength.LIMITED); 		indexWriter.addDocument(doc); 		indexWriter.close(); 	} 	 	/** 	 * 1、把索引文件建在硬盘中存放,这样web应用关闭不会丢失 	 * 2、可以在启动web应用的时候把硬盘的索引通过RAMDirectory写入内存中进行操作 	 * 3、web应用不用或退出的时候把操作的数据保存入硬盘中,从而不让数据丢失 	 * 一个实际应用: 	 * 因为在网站运营的时候需要经常创建索引,讲究及时性,那么可以先把索引放入内存 	 * 中创建,最后把内存中的索引写入硬盘,这样总体速度变快 	 */ 	public void fsDir2ramDir() throws Exception{ 		Directory fsDir = FSDirectory.getDirectory(indexPath); 		 		//1、启动时读取 		Directory ramDir = new RAMDirectory(fsDir);//直接把硬盘中的数据读入内存 		 		//运行程序时操作ramDir 		IndexWriter ramIndexWriter = new IndexWriter(ramDir, analyzer, MaxFieldLength.LIMITED); 		//往内存索引中添加Document 		Document doc = File2DocumentUtils.file2Document(filePath); 		ramIndexWriter.addDocument(doc); 		ramIndexWriter.close();//如果不关闭的话数据会在缓存中 		 		//2、退出时保存 		//如果这里第三个参数是否重新创建   不写成true的话,那么会有问题 		//假设刚开始硬盘中有2个document文件,这2个文档写入内存后,又在内存中添加一个文档,内存共3个文档 		//这三个文档又重新写入到硬盘,那么硬盘就有5个文档了,其中两个文档是重复的,所以硬盘的索引要重新创建 		IndexWriter fsIndexWriter = new IndexWriter(fsDir,analyzer,true,MaxFieldLength.LIMITED); 		//把内存的索引写入硬盘,同时NoOptimize不做优化 		fsIndexWriter.addIndexesNoOptimize(new Directory[]{ramDir}); 		fsIndexWriter.close(); 	} 	 	/** 	 * 当文件很多的时候,那么io操作就慢,那么需要合并和优化 	 */ 	@Test 	public void optimize() throws Exception{ 		Directory fsDir = FSDirectory.getDirectory(indexPath); 		IndexWriter fsIndexWriter = new IndexWriter(fsDir,analyzer,MaxFieldLength.LIMITED); //		fsIndexWriter.flush();//过时了,用commit()代替 		fsIndexWriter.commit();//把索引刷出缓存 		fsIndexWriter.optimize();//进行优化 		fsIndexWriter.close(); 	} }


7、中英文分词器的分词结果显示及测试

package cn.hj.lucene.analyzer;  import java.io.StringReader; import jeasy.analysis.MMAnalyzer; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.SimpleAnalyzer; import org.apache.lucene.analysis.Token; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.cjk.CJKAnalyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.junit.Test;  /**  * 中英文分词器的分词结果显示及测试  */ public class AnalyzerTest { 	 	String enText = "IndexWriter addDocument's a javadoc.txt"; 	String cnText = "我们是中国人"; 	 	Analyzer en1 = new StandardAnalyzer(); 	/* 	    ------------>分词器:class org.apache.lucene.analysis.standard.StandardAnalyzer 		(indexwriter,0,11,type=<ALPHANUM>) 		(adddocument,12,25,type=<APOSTROPHE>) 		(javadoc.txt,28,39,type=<HOST>) 	 */ 	Analyzer en2 = new SimpleAnalyzer(); 	/* 		------------>分词器:class org.apache.lucene.analysis.SimpleAnalyzer 		(indexwriter,0,11) 		(adddocument,12,23) 		(s,24,25) 		(a,26,27) 		(javadoc,28,35) 		(txt,36,39) 	 */ 	Analyzer cn1 = new StandardAnalyzer();//单字分词 	/* 		------------>分词器:class org.apache.lucene.analysis.standard.StandardAnalyzer 		(我,0,1,type=<CJ>) 		(们,1,2,type=<CJ>) 		(是,2,3,type=<CJ>) 		(中,3,4,type=<CJ>) 		(国,4,5,type=<CJ>) 		(人,5,6,type=<CJ>) 	 */ 	Analyzer cn2 = new CJKAnalyzer();//二分法分词 	/* 		------------>分词器:class org.apache.lucene.analysis.cjk.CJKAnalyzer 		(我们,0,2,type=double) 		(们是,1,3,type=double) 		(是中,2,4,type=double) 		(中国,3,5,type=double) 		(国人,4,6,type=double) 	 */ 	Analyzer cn3 = new MMAnalyzer();//极易分词,按词库来分词,还有庖丁分词也类似 	/* 		------------>分词器:class jeasy.analysis.MMAnalyzer 		(我们,0,2) 		(中国人,3,6) 	 */ 	//最好的还是按语义分词,据说中科院已经研究出 	@Test 	public void test() throws Exception{ 		analyzer(cn3, cnText); 	} 	 	/** 	 * 把一段文本按照分词器进行分词得到分词后的集合进行展示 	 * @param analyzer 	 * @param text 	 * @throws Exception 	 */ 	public void analyzer(Analyzer analyzer, String text)throws Exception{ 		System.out.println("------------>分词器:"+analyzer.getClass()); 		TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text)); 		for(Token token = new Token();(token = tokenStream.next(token)) != null;){ 			System.out.println(token); 		} 	} } 

8、lucene的工具方法

package cn.hj.lucene.utils; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.NumberTools; import org.apache.lucene.document.Field.Index; import org.apache.lucene.document.Field.Store;  public class File2DocumentUtils { 	 	/** 	 * 把文件内容转化为Document 	 * @param path 	 * @return 	 */ 	public static Document file2Document(String path){ 		File file = new File(path); 		Document doc = new Document(); 		doc.add(new Field("name",file.getName(),Store.YES,Index.ANALYZED)); 		try { 		doc.add(new Field("content",FileUtils.readFileToString(file),Store.YES,Index.ANALYZED)); 		} catch (IOException e) {e.printStackTrace();} 		doc.add(new Field("size",String.valueOf(path.length()),Store.YES,Index.NOT_ANALYZED)); 		doc.add(new Field("path",path,Store.YES,Index.NO)); 		return doc; 	} 	 	/** 	 * 打印搜索结果信息 	 */ 	public static void printDocument(Document doc){ 		//第一种方式的获取值 //		Field field = doc.getField("name"); //		String name = field.stringValue(); 		//第二种方式的获取值 		System.out.println("----------------------------------"); 		System.out.println("name    = "+doc.get("name")); 		System.out.println("content = "+doc.get("content")); //		System.out.println("size    = "+doc.get("size")); 		System.out.println("size    = "+NumberTools.stringToLong(doc.get("size"))); 		System.out.println("path    = "+doc.get("path")); 	} } 

工程代码:http://download.csdn.net/detail/wxwzy738/5248905


版权声明:本文为博主原创文章,未经博主允许不得转载。

标签: Lucene
来源:http://blog.csdn.net/wxwzy738/article/details/8792311

推荐: