您的位置:首页 > 其它

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

2013-04-12 11:13 369 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: