Lucene的学习与总结
一、Lucene的基础(2017-05-11 10:40:46)
1、Lucene的下载
2、Lucene的使用
IndexWriter writer = null; try { writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35))); Document doc = null; for(int i=0;i<ids.length;i++){ doc = new Document(); doc.add(new Field("id",ids[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS)); doc.add(new Field("email",emails[i],Field.Store.YES,Field.Index.NOT_ANALYZED)); doc.add(new Field("content",contents[i],Field.Store.NO,Field.Index.ANALYZED)); doc.add(new Field("name",names[i],Field.Store.YES,Field.Index.NOT_ANALYZED_NO_NORMS)); //存储数字 doc.add(new NumericField("attach",Field.Store.YES,true).setIntValue(attachs[i])); //存储日期 doc.add(new NumericField("date",Field.Store.YES,true).setLongValue(dates[i].getTime())); //加权操作 String et = emails[i].substring(emails[i].lastIndexOf("@")+1); writer.addDocument(doc); } } catch (CorruptIndexException e) { e.printStackTrace(); } catch (LockObtainFailedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if(writer != null) writer.close(); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
/** * 搜索 */ public void searcher(){ try { //1、创建Directory Directory directory = FSDirectory.open(new File("d:/import/studytool/Lucene/index01")); //2、创建IndexReader IndexReader reader = IndexReader.open(directory); //3、根据IndexReader创建IndexSearcher IndexSearcher searcher = new IndexSearcher(reader); //4、创建搜索的Query //创建parser来确定要搜索文件的内容,第二个参数表示搜索的域 QueryParser parser = new QueryParser(Version.LUCENE_35, "content", new StandardAnalyzer(Version.LUCENE_35)); //创建query,表示搜索域为content中包含come的文档 Query query = parser.parse("come"); //5、根据Seacher搜索并返回TopDocs TopDocs tds = searcher.search(query, 10); //6、根据TopDocs获取ScoreDoc对象 ScoreDoc[] sds = tds.scoreDocs; for(ScoreDoc sd : sds){ //7、根据seacher和ScordDoc对象获取具体的Document对象 Document d = searcher.doc(sd.doc); //8、根据Document对象获取需要的值 System.out.println(d.get("filename")+"["+d.get("path")+"]"); } //9、关闭reader reader.close(); } catch (CorruptIndexException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } }
3、基本实例
4、系统架构
5、索引过程的核心类
5.1、IndexWriter
5.2、Directory
5.3、Analyzer
5.4、Document
5.5、Field
6、搜索过程的核心类
6.1、IndexSearcher
6.2、Term
6.3、Query
6.4、TermQuery
6.5、TopDocs
6.6、SocreDoc
二、索引的建立
1、基本概念
2、索引过程
3、索引建立步骤
3.1、创建Directory
3.2、创建Writer
3.3、创建文档并且添加索引
文档和域的概念很重要
文档相当于表中的每一条记录,域相当于表中的每一个字段
3.4、查询索引的基本信息
使用IndexReader进行查询
3.5、删除和更新索引
1、删除
可能得到结果:
2、恢复
3、强制删除(不建议使用)
4、优化和合并(不建议使用)
5、更新索引
4、域选项
4.1、索引域选项
使用Field.Index.*来进行操作
Index.ANALYZED:进行分词和索引,适用于标题、内容等
Index.NOT_ANALYZED:进行索引,但是不进行分词,如果身份证号、姓名、ID等,适用于精确搜索
Index.ANALYZED_NOT_NORMS:进行分词但是不存储norms信息,这个norms中包含了创建索引的时间和权值等信息
Index.NOT_ANALYZED_NOT_NORMS:即不进行分词也不进行存储norms信息
Index.NO:不进行索引
4.2、存储域选项
Field.Store.*
YES:(可以还原)
将会存储域值,原始字符串的值会保存在索引,以此可以进行相应的恢复操作,对于主键,标题可以是这种方式存储
NO:(无法完全还原),可以索引
不会存储域值,通常与Index.ANAYLIZED合起来使用,索引一些如文章正文等不需要恢复的文档
4.3、最佳实践
NOT_ANALYZED_NOT_NORMS | YES | 标志符(主键、文件名),电话号码,身份证号,姓名,日期 |
ANAYLZED | YES | 文档标题和摘要 |
ANAYLZED | NO | 文档正文 |
NO | YES | 文档类型,数据库主键(不进行索引) |
NOT_ANALYZED | NO | 隐藏关键字 |
.fnm 保存的是域选项的信息
.fdt/.fdx 保存的是域Store.YES的信息
.frq 保存的是域选项中词出现的次数(搜索"java"这个词,这个文件就会保存每个文章中java出现的次数)
.norm 保存一些评分信息
.prx 偏移量
.tii/.tis 索引里面所有的索引信息
5、其他知识
5.1、对数字和日期进行索引
5.2、常用的Directory
FSDirectory.open会根据当前的运行环境打开一个最合理的基于File的Directory
new RAMDirectory会从内存中打开directory,好处是速度快,缺点是无法持久化
5.3、IndexReader和IndexWriter的生命周期
三、搜索功能
1、搜索的简单实现(TermQuery)
1.1、创建IndexReder
public IndexSearcher getSearcher() {
try {
if(reader == null) {
reader = IndexReader.open(directory);
} else {
IndexReader tr = IndexReader.openIfChanged(reader);
if(tr != null){
reader.close();
reader = tr;
}
}
return new IndexSearcher(reader);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
1.2、创建IndexSearcher
return new IndexSearcher(reader);
1.3、创建Term和TermQuery
IndexSearcher searcher = getsercher();
Query query = new TermQuery(new Term(field,name));
1.4、根据TermQuery获取TopDocs
TopDocs tds = searcher.search(query,num);
System.out.println(“一共查询了:”+tds.totlHits);
tds.totlHits是总记录数,和传出的num没有任何关系
1.5、根据TopDocs获取ScoreDoc
for(ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
}
1.6、根据ScoreDoc获取相应文档
for(ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
}
2、其他搜索(Query)
2.1、TermRangerQuery(范围查找)
IndexSearcher searcher = getSearcher();
//field:要查询的field start:开始字符 end:结束字符 TRUE:开区间
Query query = new TermRangeQuery(field,start,end,true,true);
TopDocs tds = searcher.search(query,num);
System.out.println(“一共查询了:”+tds.totlHits);
for(ScoreDoc sd : tds.scoreDocs) {
Document doc = searcher.doc(sd.doc);
System.out.println();
}
2.2、NumericRange(查询某个数字的范围)
Query query = NumericRangeQuery.newIntRange(field,start,end,true,true);
TopDocs tds = searcher.search(query,num);
System.out.println("一共查询了:"+tds.totalHits);
2.3、PreflxQuery(前缀搜索)
//此时value的值就是通过前缀来匹配
Query query = new PrefixQuery(new Term(field,value));
2.4、WildcardQuery(通配符搜索*)
//在传入的value中可以使用通配符:?和*,?表示匹配一个字符,*表示匹配任意多个字符 Query query = new WildcardQuery(new Term(field,vlaue));
2.5、BooleanQuery
BoolenQuery可以连接多个子查询
Occur.Must表示必须出现
Occur.SHOULD表示可以出现
Occur.MUST_NOT表示不能出现
//可以连接多个文件
BooleanQuery query = new BoolenQuery();
query.add(new TermQuery(new Term("name","zhangsan")),Occur.Must);
query.add(new TermQuery(new Term("content","like")),Occur.Must);
2.6、PhraseQuery(短语查询,不能用于中文搜索)
PhraseQuery query = new PhraseQuery();
query.setSlop(1);
query.add(new Term("content","I"));
query.add(new Term("content","football");
2.7、FuzzyQuery(模糊查询)
Query query = new FuzzyQuery(new Term(“name”,"Make"),0.4f,0);
3、Queryparser
3.1、制定项查找
3.2、制定范围查找
3.3、搜索数字和日期范围
3.4、前缀查找
3.5、布尔查询
4、分页搜索
四、分页