原文 http://www.aptusource.org/2014/06/searching-is-what-its-all-about/
Solr 的主要功能就是强大的查询处理。在本文中,你将会看到 Solr 的查询处理,这将会帮助你了解为什么说 Solr 是强大的搜索技术。
在本文中,请注意每个查询和 Solr 返回的文档之间的链接,以及返回的结果文档中的排序。这将有助于你像搜索引擎那样去思考问题,以后我们会逐渐覆盖核心的搜索概念。
探索 Solr 的查询表单
你可能已经使用过 Solr 的查询表单来执行查找所有文档的查询。现在,我们来快速看看这个表单的其它特性,这样可以让你对 Solr 支持的查询类型有个直观的了解。下图对这个表单的重点部分进行了注释。请花点时间来逐个了解这些注释:
在上图中,我们编写了一个查询,并且如果使用《[Solr] 快速入门》中添加的文档的话,那么结果中将会返回两个示例文档。像上图中的表单那样填写,并在你自己的环境中执行一次,看看是否真的返回了两个示例文档?
所有和 Solr 核心服务的交互过程都是使用 HTTP 请求。当你填写了查询表单并点击查询后,将会发起一个 HTTP GET 请求到 Solr。下图展示了你在上图中点击查询后发起的 HTTP GET 请求,注意,真正的 HTTP GET 请求是没有换行符的,这里使用换行符是为了更加清晰地看清楚每个参数:
更多的查询示例?
我们以后会更深入地理解查询。如果你现在就想看更多的查询示例,那么建议你使用浏览器打开 $SOLR_INSTALL/docs/tutorial.html 这个 HTML 文档,你将会看到使用示例文档进行查询的更多示例。
Solr 的这个查询表单并不是为最终用户设计的。Solr 提供了这个查询表单是为开发人员和管理员提供了一种发起 HTTP 查询的简单方式,而不用去手动编写 HTTP 请求或使用客户端应用程序。但是,我们必须要很清楚的知道,编写基于 Solr 的应用程序,你有责任要开发用户界面(UI)。本文的后面你将会看到,Solr 提供了可定制的查询 UI,可以帮助你编写你自己的需要的查询界面。
当你执行查询后 Solr 返回了什么?
我们前面已经看到了发送到 Solr 的数据是什么,接下来我们看看从 Solr 返回的结果。Solr 返回的是匹配查询条件的文档,以及让你的 Solr 客户端提供高质量搜索体验的附加信息。操作数据是通过 Solr 客户端,而 Solr 本身只会返回原始数据和 features,你需要自己为用户创建高质量的搜索体验。
下图展示了上一节中的例子返回的结果。可以看到,返回的是 XML 格式并且按价格从低到高排序。每个文档都包含了 iPod 关键字。结果中没有分页,因为一共只有两条数据。
目前为止,我们只看过 XML 格式的返回值,但是 Solr 还支持其它格式,例如 CSV(comma-separated values), JavaScript Object Notation (JSON), 和满足流行语言语言规范的格式。例如,Solr 可以返回 Python 标准格式,可以通过 eval 方法将响应安全地转换为 Python 对象。
检索排名
Solr 的检索过程与数据库检索和其他 NoSQL 数据库检索的组要不同就是检索排名。Solr 通过检索的相关度来对文档排序,相关度最高的文档最先列出。
我们使用前面已经添加好索引的例子来看看检索排名是如何工作的。最开始,输入 iPod 到 q 文本框,输入 name,features,score 到 fl 文本域,然后点击执行。那么将会返回三个文档,并且按照评分降序排列。检查一下查询结果,看看是否同意这个简单查询的排序。
直观看来,这样的排序是在情理之中的,因为关键字 iPod 在第一个文档中一共出现了三次,两次在 name 中,一次在 features 中;而在另外两个文档中都只出现了一次。score 字段的数字用于 Lucene 内部进行相关度排序,这个值在不同的查询之间没有可比性。每个匹配查询的文档都会分配一个针对这个查询的相关性得分,结果按照得分降序排列。
接下来,将查询关键字改为 iPod power,你将会看到返回相同的三个文档,并且顺序也和之前是一样的。这是因为所有三个文档中的 name 或 features 字段中都包含了查询的关键字。但是我们可以看到前两个文档的得分非常接近:第二个查询的得分是 1.521 和 1.398,第一个查询的得分是 1.333 和 0.770。这也是合理的,因为 power 在第二个文档中出现了两次,所以用 iPod power 进行查询的得分应该比通过 iPod 进行查询的得分要高。
现在,将查询关键字改为 iPod power^2,这将会把 power 关键字的权重提升为 2。简单说来,这意味着进行查询的时候 power 关键字比 iPod 关键字重要两倍,默认的权重是 1。执行查询后,返回了相同的三个文档,但是它们的顺序有所不同。现在,结果中最顶部的文档是 Belkin Mobile Power Cord for iPod w/ Dock,因为在它的 name 和 features 字段中包含了 power 关键字,我们之前说过,在这次查询中 Solr 会认为 power 关键字比 iPod 重要两倍。
现在,你已经感受过了什么是搜索排名。我们接下来看看搜索处理的其它特性,我们先来看看如何使用分页和排序。
分页和排序
我们的样例中,Solr 只索引了 32 个文档,但是真实的 Solr 项目一般会包含数百万的文档。你可以想象一下将 Solr 应用到一个电子产品的网上商店,如果使用 iPod 关键字进行查询,可能会匹配到几千个产品和周边配件。要确保快速返回结果,特别是在带宽有限的手持设备上面,你不可能一次性返回几千条数据,即便将最相关的数据一次性返回也是不行的。
分页
解决方案是通过分页来返回数据,并通过导航来请求更多页的数据。在 Solr 查询处理中,分页是是第一类的概念,在每个查询中都需要控制每页的记录数(rows)和开始位置(start)。如果在请求中没有设置,那么 Solr 使用的默认每页记录数是 10,但是你可以在发起查询请求的时候通过 rows 参数进行控制。要请求下一页的结果,可以通过每页记录数来增加 start 参数的值。例如,如果你现在返回了第一页的结果(start=0),现在你要查询下一页,你可以通过每页记录数来增加 start 参数的值,例如 start = 10。
要记住很重要的一点是让每页记录数在满足需求的情况下,尽可能的小,因为底层的 Lucene 所有并没有为一次返回大量文档做优化。相反,底层的 Lucene 是对查询过程进行了优化,因此底层的数据结构是设计用于返回最佳匹配和最高评分的文档。一旦搜索结果确定下来,Solr 需要重新构建每个文档结构,大多数情况下是从磁盘读取数据。为了效率,它使用了智能缓存,但是相比查询过程来说,构建查询结果是一个比较慢的过程,尤其是当每页记录数大的时候。因此,为了更高的效率,在 Solr 中要让每页记录数尽可能的小。
排序
就像前文所述,返回结果是按评分来进行降序排列(从高到低)。但是,你也可以请求 Solr 的返回结果按照某个字段来进行排序。前面已经看过了结果按照价格来升序排列,产品价格最低的排在最前面。
排序和分页具有很强的相关性,因为排序规则决定了页面的位置。为了帮助你更好的了解排序和分页,我们考虑一下这个问题,如果只设置了分页规则而没有设置排序规则,Solr 是否每次都会返回固定的结果?
表面上看来,这个问题的结果很明显,因为如果没有设置排序规则,那么结果就会按照评分来进行降序排列。但是,如果查询的结果中有相同的评分呢?例如,如果你查询 inStock:true,那么所有匹配的文档都有相同的评分;你可以通过查询表单来验证这个结果。
事实证明,尽管评分一致,Solr 也能保持每次返回值的排序是固定的。这是因为 Solr 找到所有匹配的文档然后再应用排序和分页。Solr 将会保持跟踪整个文档集的排序和分页。另外,顺便说一下,如果所有文档的评分都一样,那么将会返回索引顺序,这是基于内部由 Lucene 管理的文档 ID。这个内部的文档 ID 大致等同于文档被索引的顺序,但是你不需要依赖这个值来进行排序,因为当你的索引发生变更时这个值有可能改变。