Lucene读书笔记——3. 为应用程序添加搜索功能

来源:互联网 发布:域名 端口 编辑:程序博客网 时间:2024/04/30 07:23
实现简单的搜索功能
对特定项的搜索
Term t = new Term("fieldName", "key workd");
Query query = new TermQuery(t);

TopDocs topDocs = searcher.search(query, 10);
ScoreDocs scoreDocs : topDocs

解析用户输入的查询表达式:QueryParser
QueryParser parser = new QueryParser(Version.LUCENE_30, "contents", new SimpleAnalyzer());

查询表达式
匹配文档
java
默认匹配java项的文档
java junit
java or junit
默认包含java和junit中一个或两个的文档
+java +junit
java AND junit
默认域中同时包含java和junit文档
title:ant
title域中包含ant项的文档
title:extreme
-subject:sports
title:extreme AND not subject:sports
title域中包含extreme且subject域中不包含sports的文档
(agile OR extreme) AND methogy
默认域中包含methodology且包含agile和extreme中的一个或两个的文档
title:"junit in action"
title域为junit in action的文档
title:"junit action" ~5
title域中junit和action之间距离小于5的文档
java*
包含由java开头的项的文档
java~
包含与单词java相近的项的文档,如lava
lastmodified:[1/1/09 TO 12/31/09]
lastmodified域值在2009年1月1号和2009年12月31号之间的文档。


使用IndexSearcher类
创建IndexSearcher类
Directory dir = FSDirectory.open(new File("/data/index/data"));
IndexReader reader = IndexReader.open(dir);
IndexSearcher searcher = new IndexSearcher(reader);

是IndexReader 完成了诸如打开所有索引文件和提供底层reader API的繁重工作,打开一个IndexReader需要较大的系统开销,因此最好在索引期间都重复使用同一个IndexReader实例。只有必要的时候才建议打开新的IndexReader。

还可以直接从索引目录中直接创建IndexSearcher,这种情况下系统会在后台建立自己私有的IndexReader。如果关闭IndexSearcher,也会关闭这个私有的IndexReader。

IndexReader.reopen()来获取新IndexReader的有效手段,重启的IndexReader能在耗费较少系统资源的情况下使用当前reader来获取索引中所有的变更信息。

//这段代码要是线程安全的
IndexReader newrReader = IndexReader.reopen();
if(reader != newReader) {
     reader.close();
     reader = newReader;
     searcher = new IndexSearcher(reader);
}

实现搜索功能


IndexSearcher
使用时刻
TopDocs search(Query query, int n)
直接进行搜索,int n参数表示返回的评分最高的文档数量
TopDocs search(Query query, Filter filter, int n )
搜索受文档子集约束,约束条件基于过滤策略
TopFieldDocs search(Query query, Filter filter, int n, Sort sort)
接受文档子集的约束,约束条件基于过滤策略,结果排序通过自定义的Sort完成
void search(Query query, Collector results)
当使用自定义文档访问策略时使用,或者不想以默认的前N个搜索结果排序策略收集结果时使用
void search(Query query, Filter filter, Collector results)
同上,区别在于结果文档只有传入过滤策略时才能被接收


使用TopDocs

TopDocs方法或属性
返回值
totalHits
匹配搜索条件的文档数量
scoreDocs
包含搜索结果的ScoreDoc对象数组
getMaxScore
如果已经完成排序(当通过域进行排序时,程序需要分别控制是否对该域进行评分计算)则返回最大评分


搜索结果分页
1.将首次搜索获得的多页结果收集起来并保存在ScoreDocs和IndexSearcher实例中,并在用户换页浏览时展现这几页结果
2.每次用户换页时都重新换页查询

近实时搜索

IndexSearcher search = new IndexSearcher(reader);

IndexReader newrReader = IndexReader.reopen();
if(reader != newReader) {
     reader.close();
     reader = newReader;
     searcher = new IndexSearcher(newReader );
}


理解Lucene的评分机制
lucene如何评分
使用explain()理解搜索结果评分

Explanation explanation = searcher.explain(query, match.doc);

Lucene的多样化查询
通过项进行搜索:TermQuery类
Term t = new Term("fieldName", "java");
Query query = new TermQuery(t);
可以搜索Index.NOT_ANALYZED

在指定的项范围类搜索:TermRangeQuery类
索引中的各个Term对象会按照字典编排顺序进行排序,并允许在Lucene的TermRangeQuery对象提供的范围内进行文本项的直接搜索。

TermRangeQuery query= new TermRangeQuery("title2", "d", "j", true, true); //true包含边界

在指定的数字范围内搜索:NumericRangeQuery类
NumericRangeQuery query = new NumericRangeQuery.newIntRange("pubmonth", 200605, 200609, true, true);

precisionStep 参数,如果索引时变了,搜索期间输入(如果的话!)的参数也要相同

通过字符串搜索:PrefixQuery
搜索程序使用PrefixQuery类搜索包含以指定字符串开头的项的文档。

Term term = new Term("category", "/technology/computers/programing");
PrefixQuery query = new PrefixQuery(term); // 以/technology/computers/programing开头

组合查询:BooleanQuery类
通过使用BooleanQuery类可以将本章讨论的各种查询类型组合成复杂的查询方式,而BooleanQuery本身是一个Boolean子句的容器。

public void add(Query query, BooleanClause.Occur occur)

BooleanClause.Occur.MUST
BooleanClause.Occur.SHOULD
BooleanClause.Occur.MUST_NOT

BooleanQuery对象还可以作为另一个BooleanQuery对象的子句

TermQuery searchQuery = new TermQuery(new Term("subject", "search"));

Query books2010 = NumericRangeQuery.newIntRange("pubmonth", 201001, 201012, true, true);

BooleanQuery searchingBooks2010 = new BooleanQuery();
searchingBooks2010.add(searchQuery, BooleanClause.Occur.MUST); //该条件是必须的,相当于AND
searchingBooks2010.add(books2010, BooleanClause.Occur.SHOULD);//该条件是非必须的,相当于OR
MUST_NOT 相当于非


通过短语搜索:PhraseQuery类

PhraseQuery query = new PhraseQuery();
query.setSlop(slop); //两个项位置直接允许的最大间隔距离称为slop
for(String word : phrase) {
     query.add(new Term("field", word)); //添加短语项序列
}

支持2个以上的phrase查询

项之间的距离越小,具有的权重也就越大。距离越大的匹配其评分就越低。

QueryParser: "quick fox" ~3 为quick 项和fox项生成一个slop因子为3的PhraseQuery对象。


通配符查询:WildcardQuery类
Query query = new WildcardQuery(new Term("contents", "?ild*")); //对评分没有影响

搜索类似项:FuzzyQuery类
FuzzyQuery query = new FuzzyQuery(new Term("contents", "wuzza")); //即模糊查询,实际索引的是fuzza,但是却可以通过wuzza 查到fuzza

匹配所有文档:MathcAllDocsQuery类
Query query = new MatchAllDocsQuery(field);


理解查询表达式 QueryParser
Query.toString   使用该方法查看查询表达式被QueryParser对象解析后的内容

TermQuery
QueryParser parser= new QueryParser(Version.LUCENE_30, "subject", analyzer);  //默认是subject 域
Query query = parser.parse("computers");  //内容

即: subject:computers

项范围查询
QueryParser parser= new QueryParser(Version.LUCENE_30, "subject", analyzer);  // 默认是 subject 域
parser.parse("title2:[Q TO V]"); //确认边界在搜索范围内
parser.parse("title2:{Q TO \"Tapestry in action\"}"); //确认边界在搜索范围外

QueryParser.setLowercaseExandedTerms(false) ,这样的话程序不会对输入的文本进行分析。

数值范围搜索和日期范围搜索


前缀查询和通配符查询
Query q = new QueryParser(Version.LUCENE_30, "field", analyzer).parse("PrefixQuery*");

setAllowLeadingWildcard 支持项开端包含通配符,但是会牺牲掉一些程序性能。


布尔操作符
QueryParser parser = new QueryParser(Version.LUCENE_30, "field", analyzer);
parser.setDefaultOperator(QueryParser.AND_OPERATOR);
针对某项的否定操作必须与至少一个非否定项的操作联合起来进行,否则程序不会返回结果

布尔查询操作符的快捷方式


详细语法
快捷语法
a AND b
+a +b
a OR b
ab
a AND NOT b
+a -b


短语查询

"fox brown ~5" 双引号是短语查询

模糊查询
parser.parse("kountry~");

MatchAllDocsQuery
*:*

分组查询
使用(  )构建复杂的嵌套查询子句
(agile OR extreme) AND methodology

域选择


为子查询设置加权
junit^2.0 testing

是否一定要使用QueryParser
0 0
原创粉丝点击