详见[1]5.5节,在短语查询及短语嵌套查询中,以上类能实现QueryPhrase不能实现的功能。
5.6 搜索过滤
过滤是Lucene中用于缩小搜索空间的一种机制,它把可能的搜索匹配结果仅限制在 所有文档的一个子集中。它们可以用来对已经得到的搜索匹配结果进行进一步搜索,以实现在搜索结果中的继续搜索(search-within-search)特性。此外,它们还可以用来限制文 档的搜索空间。安全过滤器允许用户只能看见属于“自己的”文档搜索结果,即使这些査 询实际上还匹配了其他的文档。
通过重载一个带有Filter对象参数的search()方法,你可以对任何一个Lucene搜索进行过滤。下面介绍一些Lucene内置的过滤器子类。
? TermRangeFilter只对包含特定项范围的文档进行匹配操作.功能与
TermRangeQuery—致,但前者没有评分操作.
? NumericRangeFilter只对特定域的特定數值范围进行文档匹配操作.功能与
NumericRangeQuery 一致,但前者没有评分搮作。
? FieldCacheRangeFilter针对某个项或者某个数值范围进行文档匹配操作,使用
时可以结合FieldCache (详见[1]5.1小节)获得更好的性能表现.
? FieldCacheTermsFilter针对特定项进行文档匹配操作,使用时可以结合
FieldCache获得更好的性能表现。
? QueryWrapperFilter可以将任意Query实例转换为Filter实例,转换时仅将
Query实例对应的匹配文档作为过滤空间,该操作忽略文档评分.
? SpanQueryFilter将SpanQuery实例转换成SpanFilter实例,这个操作会将Filter
基类派生为对应的子类并且会在子类中新增一个方法,用于为每个文档匹配操作提供位置跨度访问.该类与QueryWrapperFilter类似,只不过前者的转换结果为SpanQuery类。
? PrefixFilter只匹配包含特定域和特定前缀的项的文档.功能与PrefixQuery—致,
但前者没有评分操作。
? CachingWrapperFilter是其他过滤器的封装器(Decorator),它将结果缓存起来
以便再次使用,从而提高系统性能。
? CachingSpanFilter 与 CachingWrapperFilter 功能一致,但前者的缓冲目标是
SpanFilter.
? FilteredDocIdSet允许对过滤器进行过滤,一次处理一个文档。使用它时, 必
须首先派生它的子类,然后在该子类中定义匹配方法。 详见[1]5.6节
QueryWrapperFilter使用查询中匹配的文档来对随后搜索中可以访问的文档进行 限制。它允许你将带有评分功能的查询转换为不带评分功能的过滤器。使用 QueryWrapperFilter可以将被搜索文档限制在特定的类别范围内。 public void testQueryWrapperFiIter() throws Exception { TermQuery categoryQuery =
new TermQuery(new Term(\; Filter categoryFilter = new QueryWrapperFilter(categoryQuery); assertEquals(\1,
TestUtil.hitCount(searcher, allBooks, categoryFilter}); )
SpanQueryFilter与之类似。
对于一些安全权限应用,在索引期间将文档和用户或角色关联起来,然后使用上述类,就可以限定在一定范围内。
还可以进行反向操作,使用 ConstantScoreQuery将过滤器转换成查询以用于随后
的搜索。生成的查询只对过滤器 所包含的文档进行匹配,然后赋予它们与查询加权相等的评分。
FilteredDocldSet类是一个抽象类,它能够接受一个filter参数,在随后的匹配操作期间,只要碰到一个文档,它就会调用对应的match方法(即我们所实现的其子类的同名方法)来检查该文档是否匹配。这使得你能够自定义实现match方法 中的逻辑,并能够对其他过滤器进行动态过滤。该方法效率很高,因为 FilteredDocldSet从不为过滤器完全分配字节空间。而实际上,每个匹配操作都是 根据程序要求而运行的。
该方法可以用来加强权限操作,特别是在大量权限为静态(当前在索引中)但又需要动态检查一定数量权限的时候非常有用。对于这样一个使用案例,你需要创建一个基于索引内容的标准权限过滤器,然后实现FilteredDocIdSet子类,并覆盖其match 方法以实现自己的动态权限逻辑。
lucene contrib模块有一个ChainedFilter过滤器,可组成复杂的过滤器链。
5.7 使用功能查询实现自定义评分
功能查询带给你一定的自由度来通过编程的形式使用自己的逻辑来对匹配文档进 行评分。所有用到的类都来自于org .apache .lucene. search. function程序包。
所有功能査询类的基类是ValueSourceQuery。该查询会对所有文档进行匹配操作, 但对每个匹配文档的评分是通过该类初始化时传人的ValueSource而设置的。该程序包提供了一个FieldCacheSource子类,它负责从域缓存中导出域值。你还可以创建自 定义的ValueSource——举例来说,通过这个自定义的类从外部数据库中导出评分。但很可能最简单的方案是使用FieldScoreQuery,它是ValueSourceQuery的子类,并能从指定的索引域中静态导出每个文档的评分。该域必须是数值型的,并且不能使用 norms索引,以及每个文档中该域只能由一个语汇单元。通常你可以使用 Field. Index.NOT_ANALYZED_NO_NORMS参数进行语汇单元化处理。一个样例如下:
首先,文档中需要包含“score”域,如下所示:
doc.add(new Field(\\
Field.Store.NO,
Field.Index.NOT_ANALYZED_NO_NORMS)); 然后,创建功能查询:
Query g = new FieldScoreQuery(\
该查询会对所有文档进行匹配操作,并根据文档中的“score”域而对每个文档賦予 评分。你还可以使用SHORT、INT或FLOAT类型的常量。在程序后台,该功能査询会使 用域缓存,因此这里也需要对此进行[1]5.1小节中的所提到的性能权衡。
当你使用第二种功能查询CustomScoreQuery时,就能实 现一些有趣的功能。该查询使你能够将通常的Lucene査询和一个或多个其他功能查询 联合起来使用。 现在我们可以使用先前创建的FieldScoreQuery类以及一个CustomScoreQuery类来 计算评分:
Query q - new QueryParser(Version.LUCENE_30, \
new StandardAnalyzer( Version.LUCENE_3 0)) .parse{\;
FieldScoreQuery qf = new FieldScoreQuery(\FieldScoreQuery.Type.BYTE);
CustomScoreQuery customQ = new CustomScoreQuery(q, qf) {
public CustomScoreProvider getCustomScoreProvider(IndexReader r) { return new CustomScoreProvider(r) { public float customScore(int doc, float subQueryScore, float valSrcScore) {
return (float) (Math.sqrt(subQueryScore) * valSrcScore);
在本示例中,我们通过解析用户的搜索文本而创建了一个通常的查询q。接下来
我们将创建先前使用过的同样的FieldScoreQuery,并根据score域来对文档进行评最后,我们创建了 一个 CustomScoreQuery 类,并覆盖了其中的 getCustomScoreProvider 方法, 让其返回一个包含针对每个匹配文档所采用的自定义评分算法的类。在这个人为的案例中,我们将查询评分开平方,并随后用它与FieldScoreQuerry所提供的静态评分相乘。你可以使用任意的程序逻辑来创建自己的评分系统。
需要注意的是,传给getCustomScoreProvider的IndexReader参数是针对段的,意思是如果索引包含的段不止一个,那么搜索期间会多次调用这个方法。强调这点是重要的, 因为它使你的评分逻辑能够有效使用段reader来对域缓存中的值进行检索。 其他示例见[1]5.7节
5.8 针对多索引的搜索
某些应用程序需要保持多个分离的Lucene索引,但又需要在捜索过程中能够使针 对这几个索引的所有搜索结果合并输出。有时候,导致这类分离索引出现可能是为了方便程序运行或者管理上的原因——例如,如果不同的用户或者组织为不同的文档集合创建了不同的索引,就会导致多个分离索引的出现。有时这种情况的出现是为了增大文档容量。例如,一个新闻网站可能每月新创建一个索引,然后在搜索时指定该月份对应的索引即可。出于这些原因,Lucene提供了两个很实用的类来针对多索引进行搜索。
使用Multisearcher类可以搜索到所有索引,并以一种指定的顺序(或者是以评分递 减的顺序)将搜索结果合并起来。多索引搜索(MultiSearcher)类的使用是相对于单索引搜索(IndexSearcher)而言的,除非你通过一组IndexSearcher对象去搜索一个以上 的目录(因而这是一^髙效的封装模式,它将大部分工作都委托给了子搜索器完成)。
使用方法很简单,new MultiSearcher(IndexSearcher[] searchers),就可以直接使用了。
ParallelMultiSearcher是MultiSearcher的多线程版本,它会为每个