用户名: 密 码:
您现在的位置:首页 >> 网络营销 >> 内容

Lucene 2.9.0 12月使用指南

时间:2009/12/7 18:01:39 点击:10135

  核心提示:Apache Lucene项目是一个完全用Java编写的高性能、全功能的文本搜索引擎库,最近它发布了2.9版。此次发布在2.4.1版的基础上进行了许多增强: * 单个Segment的查询及缓存,这使reopen操作的速度显著提高。 * 为IndexWriter增加了接近实时的搜索功能。 * 新的Qu...

Apache Lucene项目是一个完全用Java编写的高性能、全功能的文本搜索引擎库,最近它发布了2.9版。此次发布在2.4.1版的基础上进行了许多增强:

    * 单个Segment的查询及缓存,这使reopen操作的速度显著提高。
    * 为IndexWriter增加了接近实时的搜索功能。
    * 新的Query类型。
    * 更智能,伸缩性更强的多词(multi-term)查询(如Wildcard,Range等等)。
    * 最新优化过的Collector/Scorer API。
    * 新增的Unicode支持及字符集(Collation)。
    * 基于Attribute的TokenStream新API。
    * 在contrib中提供了新的QueryParser框架,并替换了核心实现。
    * 在基于字段搜索,或使用自定义的Collector的时候可取消Score功能,这样可以获得显著的性能提高。
    * 新的分析器(PesianAnalyzer,ArabicAnalyzer即SmartChineseAnalyzer)。
    * 为大型文本新增快速向量高亮工具(fast-vector-highlighter)。
    * 对数字字段提供了高性能的查询支持。这些字段使用前缀树的结构进行索引,能直接支持简单而高效的数字范围查询,而不需要在外部对数字进行处理。

虽然Lucene团队打算在小版本的更新上做到完整的兼容,但是Lucene 2.9在不少方面破坏了这一点。

下面是我使用过程中遇到的一些问题和解决方案:

1、添加索引

 

最新2.9的IndexWriter 建立方式:

Directory directory = new SimpleFSDirectory(new File(path),new SimpleFSLockFactory());  // 先要建立directory  
IndexWriter writer = new IndexWriter(directory,new WhitespaceAnalyzer(), cover,IndexWriter.MaxFieldLength.UNLIMITED); // 这里最大字段长度无限(大字段是content),cover为true表示覆盖写用于初始化,false用于更新,这里就用 WhitespaceAnalyzer()分词器 
Directory directory = new SimpleFSDirectory(new File(path),new SimpleFSLockFactory());  // 先要建立directory
IndexWriter writer = new IndexWriter(directory,new WhitespaceAnalyzer(), cover,IndexWriter.MaxFieldLength.UNLIMITED); // 这里最大字段长度无限(大字段是content),cover为true表示覆盖写用于初始化,false用于更新,这里就用 WhitespaceAnalyzer()分词器

IndexWriter 参数调整

writer.setMergeFactor(50); // 多少个合并一次  
writer.setMaxMergeDocs(5000); // 一个segment最多有多少个document 
writer.setMergeFactor(50); // 多少个合并一次
writer.setMaxMergeDocs(5000); // 一个segment最多有多少个document

 


把其他格式转化为lucene需要的Document格式

Document doc = new Document();  //每一个doc相当于数据库的一条记录  
doc.add(new Field("uid", line.getUid().toString(), Store.YES,Index.NO));  //每一个field,相当于数据库的字段  
 
doc.add(new Field("title", line.getTitle(), Store.NO,Index.ANALYZED));   
doc.add(new Field("content", line.getContent(),Store.NO, Index.ANALYZED));  
Document doc = new Document();  //每一个doc相当于数据库的一条记录
doc.add(new Field("uid", line.getUid().toString(), Store.YES,Index.NO));  //每一个field,相当于数据库的字段

doc.add(new Field("title", line.getTitle(), Store.NO,Index.ANALYZED));
doc.add(new Field("content", line.getContent(),Store.NO, Index.ANALYZED)); 

向IndexWriter添加doc,可以插入多条doc

writer.addDocument(doc);  
writer.addDocument(doc2);  
writer.addDocument(doc3); 
writer.addDocument(doc);
writer.addDocument(doc2);
writer.addDocument(doc3);

开始写入(close的时候为实际写入过程)

writer.close();  
writer = null; 
writer.close();
writer = null;

读取写入的索引数

writer.numDocs()  
writer.maxDoc() 
writer.numDocs()
writer.maxDoc()

在close之前可以进行优化(不建议在建立索引时候使用)

writer.optimize()

2、清空索引
Directory directory = new SimpleFSDirectory(new File(path),new SimpleFSLockFactory());  
IndexWriter.unlock(directory);  //关键是这一步要进行目录解锁,这里解的是write.lock锁  
IndexWriter writer = new IndexWriter(directory,new WhitespaceAnalyzer(), false,IndexWriter.MaxFieldLength.LIMITED);  
writer.deleteAll();  //标识删除全部  
writer.optimize();  //这个步骤才是实际删除的过程  
writer.close();  
Directory directory = new SimpleFSDirectory(new File(path),new SimpleFSLockFactory());
IndexWriter.unlock(directory);  //关键是这一步要进行目录解锁,这里解的是write.lock锁
IndexWriter writer = new IndexWriter(directory,new WhitespaceAnalyzer(), false,IndexWriter.MaxFieldLength.LIMITED);
writer.deleteAll();  //标识删除全部
writer.optimize();  //这个步骤才是实际删除的过程
writer.close(); 

3、删除指定索引(和清空差不多)
writer.deleteDocuments(new Term("uri", uri));  //这里是删除term满足条件的一条或多条  
writer.deleteDocuments(query); //这里是删除一个查询出来的内容 
writer.deleteDocuments(new Term("uri", uri));  //这里是删除term满足条件的一条或多条
writer.deleteDocuments(query); //这里是删除一个查询出来的内容

4、更新索引
就是先删除再添加的过程,没有直接update的办法

5、读取建立的索引分词
TermEnum terms = indexReader.terms(new Term(index, ""));  
Term term = terms.term();  //获取一条索引  
term().field(); //获取索引的field(字段名)  
term().text(); //获取索引的值 
TermEnum terms = indexReader.terms(new Term(index, ""));
Term term = terms.term();  //获取一条索引
term().field(); //获取索引的field(字段名)
term().text(); //获取索引的值

6、搜索
最新2.9的IndexSearcher 建立方式:

Directory directory = new SimpleFSDirectory(new File(path),new SimpleFSLockFactory());  
IndexSearcher indexSearcher = new IndexSearcher(directory, true); 
Directory directory = new SimpleFSDirectory(new File(path),new SimpleFSLockFactory());
IndexSearcher indexSearcher = new IndexSearcher(directory, true);

创建查询条件(这里建一个最复杂的,根据多个限定条件查找,并且有的限定条件放在多个field中查找,有精确限定和范围限定)

 


BooleanQuery bQuery = new BooleanQuery();  
Query query1 = null, query2 = null, query3 = null;  
BooleanClause.Occur[] flags = new BooleanClause.Occur[] {BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD };  
query1 = MultiFieldQueryParser.parse(params.get("keywords"),new String[] { "title", "content" }, flags, new WhitespaceAnalyzer());  
bQuery.add(query1, Occur.MUST); //query1是把关键字分别在title和content中匹配!  
query2 = new TermQuery(new Term("startgui", params.get("startgui")));  
bQuery.add(query2, Occur.MUST); //query2是精确匹配  
Long minPriceLong = Long.parseLong(params.get("minPrice"));  
Long maxPriceLong = Long.parseLong(params.get("maxPrice"));  
query5 = NumericRangeQuery.newLongRange("price", minPriceLong,  
maxPriceLong, true, true);  
bQuery.add(query5, Occur.MUST);  //query3是按范围匹配 
BooleanQuery bQuery = new BooleanQuery();
Query query1 = null, query2 = null, query3 = null;
BooleanClause.Occur[] flags = new BooleanClause.Occur[] {BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD };
query1 = MultiFieldQueryParser.parse(params.get("keywords"),new String[] { "title", "content" }, flags, new WhitespaceAnalyzer());
bQuery.add(query1, Occur.MUST); //query1是把关键字分别在title和content中匹配!
query2 = new TermQuery(new Term("startgui", params.get("startgui")));
bQuery.add(query2, Occur.MUST); //query2是精确匹配
Long minPriceLong = Long.parseLong(params.get("minPrice"));
Long maxPriceLong = Long.parseLong(params.get("maxPrice"));
query5 = NumericRangeQuery.newLongRange("price", minPriceLong,
maxPriceLong, true, true);
bQuery.add(query5, Occur.MUST);  //query3是按范围匹配
 

排序情况

 

SortField[] sortField = new SortField[] { SortField.FIELD_SCORE,new SortField(null, SortField.DOC, true) }; // 默认排序  
SortField sortPriceField = new SortField("sortPrice",SortField.LONG, sortPrice);  
sortField = new SortField[] { sortPriceField,SortField.FIELD_SCORE,new SortField(null, SortField.DOC, true) };  //按自定义价格排序 
SortField[] sortField = new SortField[] { SortField.FIELD_SCORE,new SortField(null, SortField.DOC, true) }; // 默认排序
SortField sortPriceField = new SortField("sortPrice",SortField.LONG, sortPrice);
sortField = new SortField[] { sortPriceField,SortField.FIELD_SCORE,new SortField(null, SortField.DOC, true) };  //按自定义价格排序
 

2.9最新查询方式,只是获取id

TopFieldDocs docs = indexSearcher.search(query, null, indexSearcher.maxDoc(), new Sort(sortField));  
ScoreDoc[] scoreDocs = docs.scoreDocs;  
docCount = scoreDocs.length;  
TopFieldDocs docs = indexSearcher.search(query, null, indexSearcher.maxDoc(), new Sort(sortField));
ScoreDoc[] scoreDocs = docs.scoreDocs;
docCount = scoreDocs.length; 

加入分页

List<Document> docList = new ArrayList<Document>();  
int max = ((startIndex + pageSize) >= docCount) ? docCount : (startIndex + pageSize); // max防止arrayindexoutofbounds  
for (int i = startIndex; i < max; i++) {   
    ScoreDoc scoredoc = scoreDocs[i];  
    Document doc = indexSearcher.doc(scoredoc.doc); // 新的使用方法  
    docList.add(doc);  

List<Document> docList = new ArrayList<Document>();
int max = ((startIndex + pageSize) >= docCount) ? docCount : (startIndex + pageSize); // max防止arrayindexoutofbounds
for (int i = startIndex; i < max; i++) {
 ScoreDoc scoredoc = scoreDocs[i];
 Document doc = indexSearcher.doc(scoredoc.doc); // 新的使用方法
 docList.add(doc);
}
 

循环解析docList中的Document获取所需要的值

doc.get("title");

...

7、关于分词
注意建立索引和搜索时候的analyzer必须一致,而且建立索引和搜索时候目录也要保持一致

lucene自带的一些分词器

StandardAnalyzer() 会按空格和标点符号划分

WhitespaceAnalyzer() 会按空格划分

中文分词这里使用的是paoding的中文分词

是先按词库划分,当词库中不存在时按二分法进行划分

 

 

文章来源:http://www.xinxilong.com

作者:不详 来源:网络
相关评论
发表我的评论
  • 大名:
  • 内容:
  • 论坛群发大师(www.xinxilong.com) © 2008 版权所有 All Rights Resverved.
  • Email:4984672[at]qq.com 沪ICP备12025887号-1
  • Powered by 论坛群发大师