扩展功能点

通过前面几章中关于搜索内容的介绍,你可能会以为本书有关搜索的话题已经结束了。其实不然,在本章中我们将继续讲述此主题的内容。

在前面的第3章和第5章,我们分别讨论了 Lucene 基本的内置搜索功能以及在这些功能之上的一些更高级的搜索特性。

在这两章中,我们只探究了 Lucene 的内置特性。

除此之外, Lucene 还具有一些令人叫绝的扩展功能点。

首先,我们介绍第一个自定义的扩展特性——Lucene 的自定义排序特性,我们可以利用这个特性进行搜索,并将搜索结果按照它们和用户当前所处地理位置的距离远近程度以升序排列。接下来,我们不使用惯用的 Hits 而是使用自定义的 HitCollector 来探测匹配结果;当应用程序查找到相应的匹配结果时, HitCollector 实际上就相当于一个事件监听器。

QueryParser 也可以在几个方面进行有效的扩展,比如可以用丁控制口期解析和数值格式化;以及禁用一些可能会降低性能的查询,如通配符查询和模糊查询等。自定义的过滤器允许向搜索限制条件中加入索引之外的信息,比如我们可以把关系数据库中的信息加入到 Lucene 的可搜索数据中。

最后,我们使用 JUnitPerf 工具对 Lucene 的性能进行测试。我们提供的这个性能测试用例是一个非常有价值的测试范例,事实上它已经成为一个设计工具而不仅仅是一个简单的确认测试。

6.1 使用自定义的排序方法

如果按搜索结果的评分、文档ID或域值进行排序都不能满足你对排序的需求,Lucene允许我们实现自定义的排序方法,而这个排序方法是通过实现SortComparatorSource接口来完成的。当你还无法在索引过程中确定某种排序标准时,这种用户自定义的排序机制就会显示出它的优越性。

自定义的排序机制中有一个很有意思的应用——根据搜索结果和指定位置的地理距离的远近对它们进行排序”。这里的指定位置只有在进行搜索时才能确定。我们已经为这个概念创建了一个简单的范例,它围绕着一个很重要的问题—“What Mexican foodrestaurant is nearest to me?”(最近的墨西哥餐馆在哪里?)。

6.2 编写自定义的 HitCollector

在大多数具有全文搜索功能的应用程序中,用户需要查找的是和查询条件最相关的文档。

实际上,用户使用这些程序时通常也只是访问得分最高的那些文档。当然了,也会有一些特殊的情况,如用户只想显示所有和查询条件匹配的文档(通过ID)而无需查看这些文档的内容;对于我们在5.5小节中讨论过的搜索过滤器,在这种情况下, 使用HitCollector 类会变得更加有效。此外,我们在本小节还将介绍 HitCollector 的另一种可能的用法:即以一种直接的方式从搜索结果中访问每个文档的内容。

即使你已经在 Hits 中费尽心思地采用了缓存机制,但如果你遍历返回的所有 Hits 对象并且手工处理它们,那么当使用返回 Hits 对象的 search 方法时, Lucene 就必须收集查询到的所有文档。而使用自定义的 HitCollector 类则可以避免对 Hits 对象的收集。

6.3 扩展 QueryParser

在3.5节中,我们介绍了 QueryParser 并解释了它用于控制其自身行为的一些设置项。

比如,用于解析日期的 locale 设置和控制缺省短语的slop 设置等。

QueryParser 类也是可扩展的,例如:允许通过继承该类并重写一部分创建查询的函数等。在本节中,我们向你示范了如何继承QureyParser,用于禁用效率很低的通配符查询和模糊查询,并对日期范围的解析进行自定义的处理。

此外,还要将短语查询转换为 SpanNearQuery 而不是PhraseOuery。

6.3.1自定义 QueryParser 的行为

尽管 QueryParser 存在一些怪异之处,比如和分析器之间的交互等,不过它确实包含一些可以由用户自定义的扩展功能。

表 6.1 详述了为继承该类而设计的一些方法以及对它们进行重写的原因。

6.1

6.4 使用自定义过滤器

如果执行过滤操作需要的所有信息都存储在索引中,我们就没有必要自己编写过滤器,因为使用 QueryFilter 就可以完成过滤操作。不过在某些情况下,我们必须编写一些自定义的过滤器。基于本书提供的示例数据,假设我们正在经营一家网上书店,而且我们希望用户能够对今天特价热销图书进行搜索。一种可供选择的方案就是使用一个特殊标记表示书籍的特价、热销信息并存储在索引域中。但是,这些特价、热销书目经常发生变化。在这类书目发生变化时,我们不需要重新索引这些书目信息而只要把这些特殊标记存储在我们假定的关系数据库中就可以了。

为了能很好地实现这个功能,我们希望程序是测试驱动并且可以示范 SpecialsFilter如何从外部资源中获取信息,即便是所需的外部资源并可能不存在的情况下。下面我们开始向读者展示如何使用一个接口、一个 mock 对象 object) 以及 Junit 测试用例来实现上述的功能。首先列出的是检索特价图书的接口程序:

参考资料

《Lucene in Action II》