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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值