热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ApacheSolr的新特性

Apache Solr 是一个开源的搜索服务器,主要基于 HTTP 和 Apache Lucene。2007 年,我在一个包含有两个部分的系列文章 使用 Apache Solr 实现更加灵巧的搜索 中向 developerWorks 读者介绍了 Solr。由于最近又发布了 Solr 1.3 版本,所有应该详述一下 Solr 自 2007 年以后的许多新特性和增强功能。

Solr 包含有很多的企业就绪特性,比如轻松的配置和管理、多客户机语言绑定、索引复制、缓存、统计数据以及日志记录。Solr 的 1.3 版本以 Apache Lucene 2.3 版本的巨大性能提升为基础,并增加了一个新的、向后兼容的、即插即用组件架构。该架构使开发人员踊跃创建可以进一步增强 Solr 的组件。例如,1.3 版本就包含能够实现以下功能的组件:

  • “您是不是要找……” 拼写检查
  • 查找 “类似的” Document
  • 根据编辑输入(又称付费排序)覆盖搜索结果

另外,查询解析、搜索、分类以及调试这样的现有功能也被组件化了。现在,您可以通过组合这些组件来自定义创建 SolrRequestHandler 。最后,Solr 还增加了直接为数据库内容创建索引的功能,并且通过分布式搜索来支持庞大的系统,这一点对很多企业都很重要。

本文快速温习了 Solr 的内容,但前提是您熟悉 Solr 的基本概念,包括(但不限于)schema.xml、solrconfig.xml、索引和搜索的基本概念,以及 SolrRequestHandler 在 Solr 中所起的作用。如果不熟悉这些概念的话,您可以查看 使用 Apache Solr 实现更加灵巧的搜索 系列文章,并参阅本文的 参考资料 部分。

首先,我将简单复习一下 Solr,然后介绍如何获取和安装最新版本的 Solr 以及升级早期版本的要点。接着,我会介绍 Solr 1.3 的一些重要的增强功能,最后再看一下 Solr 的新特性。

复习:Solr 概念

从概念上,Solr 可以被分成四大块:

  • 模式(schema.xml)
  • 配置(solrconfig.xml)
  • 索引
  • 搜索

要理解模式,需要先理解 Lucene 对 Document 的注释。一个 Document 包含一个或多个 Field 。一个 Field 由名称、内容和给出了内容的处理方法的元数据组成。分析内容可以使其被搜索到。而分析则是通过将一个 Tokenizer 与零个或零个以上的 TokenFilter 链接到一起来完成的,Tokenizer 能够将输入流拆分为单词(标记),TokenFilter 能够改变(例如,词干)或移除标记。Solr 模式能够在没有代码的情况下轻松配置分析过程。它还提供了更强大的键入功能,让您能够将 Field 具体指定为 Stringintfloat 或其他原有的或自定义的类型。

在配置方面,solrconfig.xml 文件不仅指定了 Solr 如何处理索引、突出显示、分类、搜索以及其他请求,还指定了用于指定缓存的处理方法的属性,以及用于指定 Lucene 管理索引的方法的属性。配置取决于模式,但模式不取决于配置。

索引和搜索都是通过向 Solr 服务器发送请求来实现的。索引的实现方法很简单,用 POST 一个描述所有 Field 及其内容的 XML 文档就可以了,如位于 apache-solr-1.3.0/example/exampledocs/ 目录下的 hd.xml 样例文档,如清单 1 所示:


清单 1. 样例 XML 文档

				
  
  
  SP2514N 
  Samsung SpinPoint P120 SP2514N - 
  hard drive - 250 GB - ATA-133 
  Samsung Electronics Co. Ltd. 
  electronics 
  hard drive 
  7200RPM, 8MB cache, IDE Ultra ATA-133 
  NoiseGuard, SilentSeek technology, Fluid 
  Dynamic Bearing (FDB) motor 
  92 
  6 
  true 
  
  

 

要实现搜索则只需要发送 HTTP GET ,比如:

http://localhost:8983/solr/select?indent=on&version=2.2&q=ipod&start=0&rows=10 
      &fl=*%2Cscore&qt=standard&wt=standard

 

在这个例子,查询 ipod 被提交,它要求 10 个结果。想知道更多有关各种可选查询选项的信息,请参看 Solr wiki(参见 参考资料 )。(现在,与 Solr 一起提供的还有一个称为 SolrJ 的客户机,它将 HTTP 请求的所有细节信息都隐藏在一组很容易使用的 Java™类中。我将在本文 后半部分 介绍 SolrJ)。

对于从更大的上下文理解 Solr 设计,这些关于 Solr 概念的快速复习已经足够。


回页首

安装 Solr 1.3

要使用 Solr 和本文中的样例,您必须先安装以下软件:

  • Java 1.5 或更高版本。

  • Web 浏览器,您将用它查看管理页面。我使用的是 Firefox,但可以使用其他现代浏览器。

  • 要运行 DataImportHandler 样例,需要一个数据库及其 JDBC 驱动。在本文的样例中,我使用的是 PostgreSQL;MySQL 或其他数据库应该也可以,但可能需要修改我编写的 SQL 以使它适合您的数据库。

  • 需要一个 servlet 容器。我在本文中使用的是 Jetty,它与 Solr 打包在一起,所以也就没必要使用其他容器了。但如果您偏爱 Tomcat 或其它容器的话,Solr 也能很好地适应它们。

Solr 的新起点

安装了上述软件之后,从 Apache Mirrors Web 站点 下载 Solr 1.3.0 版本,并将其解压缩到特定的目录下。解压缩包将创建一个名为 apache-solr-1.3.0 的目录。然后在一个终端(命令提示符)中完成以下步骤:

  1. cd apache-solr-1.3.0/example (在 Windows®上使用 \ )。
  2. java -jar start.jar

    然后等待,直到在日志输出中看到如下几行,它表明服务器已经启动:

     2008-10-01 09:57:06.336::INFO:  Started SocketConnector @ 0.0.0.0:8983 
     Oct 1, 2008 9:57:06 AM org.apache.solr.core.SolrCore registerSearcher 
     INFO: [] Registered new searcher [email protected] main 
    

  3. 将 Web 浏览器转到 http://localhost:8983/solr,您会看到一个 Solr 欢迎页面。
  4. 在另外一个终端中会出现 cd apache-solr-1.3.0/example/exampledocs
  5. java -jar post.jar *.xml 。这会自动向 Solr 添加一组文档。
  6. 在浏览器的管理员页面上尝试查询 (http://localhost:8983/solr/admin/form.jsp)。

    图 1 显示了在我的浏览器上尝试查询 ipod 产生的结果(有删节):



    图 1. 示例搜索结果
    Apache Solr 的新特性

现 在,您的电脑上已经安装并运行 Solr 1.3,可以工作了。在本文中,我将使用并修改位于 pache-solr-1.3.0/example/solr/conf 目录中的样例 solrconfig.xml 和 schema.xml。我先介绍一下与升级到 Solr 1.3 版本有关的一些问题,然后再介绍一下该最新版本中的增强功能。如果不需要升级的话,您可以直接跳到 增强功能 部分。

升级 Solr

Solr 1.3.0 与早期的 Solr 版本是兼容的。但升级时仍有几件事情需要注意。对于启动器来说,如果使用 复制 的话,需要首先升级 worker 节点,然后再升级 master 节点。

Solr 复制

Solr 中的复制可能会涉及到一个或多个 worker 节点,它们都运行 Solr,将索引的本地副本与 master 节点上的更改进行同步。复制允许 Solr 进行扩展,以很高的查询容量来满足应用程序的需求,而且不会降低性能。Solr 能够很有效地处理该过程。要获取更多的信息,请参见 参考资料 。

第二,这个版本的 Solr 包含新版本的 Lucene。其实,这就意味着 Solr 将会升级内部的 Lucene 文件格式,也就是说旧版的 Solr 可能无法读取新的版本。所以,在升级前先备份索引是明智之举,避免以后需要降级版本。

第 三,Solr 1.3 还包含 Dr. Martin Porter 的新版 Snowball 派生器。如果用它们派生单词的话,那么对于过去用某种方法派生的单词,现在可能(虽然可能性不大)不再使用相同的方法了。最保险的做法是为内容重新创建索 引,这样就避免查询时间分析和索引分析不匹配。

除了有些用户可能会遇到的这些问题以外,Solr 1.3 的确应该代替早期的版本。现在您已经准备好学习本文的重用部分:增强 Solr 现有的功能。


回页首

增强功能

Solr 1.1 和 1.2 使用起来很方便,但是,和所有最简单的软件一样,它们都留有改进的空间。Solr 1.3 包含有很多对服务器的稳定性和性能的故障修复功能和改进。

性能增强

首先,最新的版本将 Lucene 库升级到了最近的版本,该版本含有很多性能改进。在测试中,我看到索引速度提高了 5 倍,而有些人则声称提高了 2 到 8 倍。幸运的是,所有的 Solr 用户都可以享受到更快的索引,而且大部分的性能增进都不需要改变配置。

但 是,很容易改变 solrconfig.xml 中的一个配置,让应用程序更好地控制索引期间使用的内存量。在 1.1 和 1.2 版本中,Solr 会在内存中的文档达到一定数量时将索引的文档写到磁盘中,而不管文档的大小。这经常导致内存不被充分利用,因为文档较小时,尽管内存有剩余,文档还是被过 度刷新;而文档较大需要更大内存时,又不能及时刷新它。现在,solrconfig.xml 的 部分有了 选项,您可以指定用于缓冲内存中的文档的内存量,而不是由文档的数量来决定。

更多扩展点

在 Solr 1.3 中,扩展 Solr 以及配置和重新整理扩展变得十分简单。以前,您需要编写一个 SolrRequestHandler 来实现新功能。这个方法的问题是其他 SolrRequestHandler 很难重用该功能。例如,您可能有更好的分类方法,但却想保留现有的查询与突出显示功能。为了解决这个问题,Solr 项目提出了将各种 SolrRequestHandler (比如 StandardRequestHandlerDismaxRequestHandler )重构为组件 —称为 SearchComponent —的想法,这些组件可以链接起来,形成一个新的 SolrRequestHandler 。现在,您只要关注 SearchComponent 的新功能就可以了,不用再费神思考怎样才能最好地扩展、重用或复制其他功能。

不过请放心,现有的 SolrRequestHandler 仍然可以像以前一样无缝地工作,但它们现在仅仅是负责实际工作的围绕 SearchComponent 的包装器而已。表 1 介绍了一些新 SearchComponent 的详细信息。稍后,我还将在本文中提供有关表 1 中的两个组件的更多信息(MoreLikeThisComponentSpellCheckComponent 。参见 参考资料 中的 SearchComponent 链接)。


表 1. 常用的 SearchComponent

名称 说明和查询样例
QueryComponent 负责将查询提交到 Lucene 并返回 Document 的列表。

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10
FacetComponent 决定结果集的分类。

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&facet=true&facet.field=inStock
MoreLikeThisComponent 为每个搜索结果查找与结果类似的文档,并返回这些结果。

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&mlt=true&mlt.fl=features&mlt.count=1
HighlightComponent 在搜索结果的正文中突出显示查询词语的位置。

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&hl=true&hl.fl=name
DebugComponent 返回有关查询的解析方式的信息,以及每个文档的记录方式的详细信息。

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&debugQuery=true
SpellCheckComponent 根据索引的内容对输入查询进行拼写检查,并提供其他备选方法。

http://localhost:8983/solr/spellCheckCompRH?&q=iPood&start=0&rows=10&spellcheck=true&spellcheck.build=true

 

默认情况下,所有 SolrRequestHandler 都附带有 QueryComponentFacetComponentMoreLikeThisComponentHighlightComponentDebugComponent 。要添加自己的组件,您需要:

  1. 扩展 SearchComponent 类。
  2. 使 Solr 可以使用这些代码(参见 参考资料 中链接到 Solr Plugins wiki 页面的链接)。
  3. 在 solrconfig.xml 中配置它。

例如,假定我创建了一个名为 com.grantingersoll.MyGreatComponentSearchComponent ,并让 Solr 可以使用它,而现在我想要将其插入到 SolrRequestHandler 中以查询它。那么我首先需要声明该组件,如清单 2 所示,这样 Solr 才能知道如何实例化这个类:


清单 2. 组件声明

				
  

 

接下来,我需要告知 Solr 要将其连接到哪个 SolrRequestHandler 。在这个用例中,我可以使用三个选择之一:

  • 显式地声明所有 SearchComponent ,如清单 3 所示:

    清单 3. 显式地声明所有 SearchComponent
    						
      
         
          query 
          facet 
          myGreatComp 
          highlight 
          debug 
         
      
    

  • 预先将组件添加到现有的链接上,如清单 4 所示:

    清单 4. 预先将组件添加到现有的链接上
    						
      
         
          myGreatComp 
         
      
    

  • 将组件追加到现有链接上,如清单 5 所示:

    清单 5. 将组件追加到现有链接上
    						
      
         
          myGreatComp 
         
      
    

关于 DebugComponent的说明

当您使用 first-componentslast-components 方法时,DebugComponent 必须是链接的最后组件。当组件改变 DebugComponent 报告的值时(比如查询结果),这尤为有用。

现在,与 SearchComponent 重构类似,也可以将查询解析和 SolrRequestHandler 分开。因此,您可以把 DismaxQParser 与任何 SolrRequestHandler 一起使用。您可以通过输入 defType 参数来实现。例如:

http://localhost:8983/solr/select?&q=iPod&start=0&rows=10&defType=dismax&qf=name

 

使用 Dismax 查询解析器来解析查询,而不是标准 Lucene 查询解析器。

另外,您也可以通过扩展 QParserQParserPlugin 来创建您自己的查询解析器,并让 Solr 可以使用它们,然后在 solrconfig.xml 中配置它。例如,如果我创建了 com.grantingersoll.MyGreatQParsercom.grantingersoll.MyGreatQParserPlugin ,并使让 Solr 可以使用它们,那么我应该在 solrconfig.xml 中按以下方式配置它们:

 

随后,我可以将 defType=greatParser 键 / 值对添加到一个查询请求中,以查询这个新的解析器。

Solr 最近版本还包含了很多其他的改进。如果您有兴趣学习更多内容的话,可以看一下 参考资料 中的发布说明链接。从这里开始我们将学习 Solr 的新特性。


回页首

新特性

Solr 1.3 拥有很多功能强大的特性,这使它充满了吸引力。本文剩余的部分将介绍新 Solr 特性,以及将它们合并到您的应用程序中的方法。为了展示这些内容,我将构建一个简单的应用程序,它将 RSS 提要和该提要的评级结合起来。评级将储存在一个数据库中,RSS 提要来自我的 Lucene 博客的 RSS 提要。完成这个简单的设置后 ??? 我将展示如何使用:

  • DataImportHandler
  • MoreLikeThisComponent
  • QueryElevationComponent (我称之为 “编辑结果排序”)
  • SolrJ
  • 分布式搜索 (不带有设置细节信息的架构讨论)

如果要实践这个示例,请 下载样例应用程序 ,并按以下说明进行操作:

  1. 将 sample.zip 拷贝到 apache-solr-1.3.0/example/ 目录。

  2. 解压缩 sample.zip

  3. 启动(或重启动)Solr:java -Dsolr.solr.home=solr-dw -jar start.jar

  4. 以数据库管理员的身份创建一个名为 solr_dw 的数据库用户。具体做法请参看数据库说明。在 PostgreSQL 中,我的创建方法为:create user solr_dw;

  5. 为上述用户创建一个名为 solr_dw 的数据库:create database solr_dw with OWNER = solr_dw;

  6. 在命令行上执行 src/sql/create.sql 语句:psql -U solr_dw -f create.sql solr_dw 。我的输出为:
     [email protected]>psql -U solr_dw -f create.sql solr_dw 
     psql:create.sql:1: ERROR:  table "feeds" does not exist 
     psql:create.sql:2: NOTICE:  CREATE TABLE / PRIMARY KEY will create \ 
      implicit index "feeds_pkey" for table "feeds"
     CREATE TABLE 
     INSERT 0 1 
     INSERT 0 1 
     INSERT 0 1 
     INSERT 0 1 
     INSERT 0 1 
    

从数据库和其他数据源导入数据

在这个结构化数据和非结构化数据的数量都很庞大的年代,经常需要从数据库、XML/HTML 文件或其他数据源导入数据,并使数据可搜索。过去,要编写自定义代码才能创建到数据库、文件系统或 RSS 提要的自定义连接。但现在,Solr 的 DataImportHandler (DIH) 填补了这个空白,它使您能够从数据库(通过 JDBC)、RSS 提要、Web 页面和文件中导入数据。DIH 位于 apache-1.3.0/contrib/dataimporthandler 中,是 apache-1.3.0/dist/apache-solr-dataimporthandler-1.3.0.jar 中的一个 JAR 文件。

DataImportHandler警告

DataImportHandler 不是文件 /Web 爬行器(crawler),它不直接支持从二进制文件格式中提取内容,比如 MS Office、Adobe PDF 或其他专有格式。本文没有详尽地介绍 DIH,如果要了解更多信息,请参见 参考资料 。

在概念上,DIH 可以分解为几个简单的部分:

  • DataSource :获取内容的数据库、Web 页面、RSS 提要或 XML 文件。

  • 文档 / 实体声明:指定 DataSource 的内容与 Solr 模式之间的映射。

  • 导入:Solr 命令,使用它既可以进行完全导入,也可以只导入已经更改的实体的 增量导入

  • EntityProcessor :用于映射的代码。Solr 自带四个工具:
    • FileListEntityProcessor :在目录上迭代并导入文件。
    • SqlEntityProcessor :连接到一个数据库并导入记录。
    • CachedSqlEntityProcessor :将缓存添加到 SqlEntityProcessor
    • XPathEntityProcessor :使用 XPath 语句从 XML 文件抽取内容。
  • Transformer :用户定义的、可选的代码,用于在添加到 Solr 之前转换导入的内容。例如,DateFormatTransformer 能够标准化日期。

  • 变量替代:用运行时的值替代占位符变量。

首先,我需要设置一个 SolrRequestHandler 将 DIH 和 Solr 关联起来。该设置要在 solr-dw/rss/conf/solrconfig.xml 文件中进行,如清单 6 所示:


清单 6. 将 DIH 和 Solr 关联起来

				
  
  
  rss-data-config.xml 
  
  

 

该配置表明:我可以通过 http://localhost:8983/solr/rss/dataimport 找到 DataImportHandler 实例;该实例必须使用一个名为 rss-data-config.xml 的配置文件(位于 solr_dw/rss/conf 目录)来获取它的设置信息。到目前为止,一切都相当简单。

拨开下一层面纱,rss-data-config.xml 文件就是声明和使用 DataSource 、实体和 Transformer 的地方。在这个例子中,首先遇到的 XML 标记(在根元素后面)为 DataSource 声明,如清单 7 所示:


清单 7. DataSource 声明

				
  
  

 

清单 7 中的第一个声明设置一个与我的数据库相连接的 DataSource 。它被命名为 ratings ,因为我的评级信息就储存在里面。注意,虽然我没有为数据库用户设置密码,但实际可以向标记添加密码属性。如果了解 JDBC 设置的话,那么就应该很熟悉这个 DataSource 声明了。第二个 DataSource 名为 rss ,它声明内容将要通过 HTTP 来获取。稍后将声明这个 DataSource 的 URL。

下一个值得讨论的标记是 标记。它用来指定如何将 RSS 提要和数据库的内容映射到 Solr Document 。一个实体就是被索引为一个单一文档的内容单位。例如,在一个数据库中,实体声明规定了如何将每一行转换成 Document 中的 Field 。一个实体里又可以包含一个或多个实体,因此子实体就变成整体 DocumentField 结构。

至此,来自 rss-data-config.xml 的带注释的示例可以清楚地说明与实体相关的大部分信息。在这个例子中,主实体从一个 RSS 提要获取内容,并将其与数据库中的行相关联以获得评级。清单 8 是一个缩略的 RSS 提要示例:


清单 8. 缩略的 RSS 反提要

				
  
  
  
 http://lucene.grantingersoll.com 
 Thoughts on Apache Lucene, Mahout, 
    Solr, Tika and Nutch 
 Wed, 01 Oct 2008 12:36:02 +0000 
  
   
  http://lucene.grantingersoll.com/2008/10/01/ 
    charlotte-jug-%c2%bb-oct-15th-6pm-search-and-text-analysis/ 
  Wed, 01 Oct 2008 12:36:02 +0000 
   
   
  http://lucene.grantingersoll.com/?p=112 
  > OCT 15TH - 6PM - Search and Text Analysis 
 I will be speaking at the Charlotte Java Users Group on Oct. 15th, covering things 
 like Lucene, Solr, OpenNLP and Mahout, amongst other things. 
 ]]> 
  
  

 

与此同时,数据库中的一行包含提要中的文章的 URL、一个评级(我随便编的)和一个修改日期。现在,我只需将它映射到 Solr 就可以了。为了完成此工作,我将逐行解释 rss-data-config.xml 中的实体声明,如清单 9 所示(它包含行数和换行符,以获得良好的格式):


清单 9. 实体声明

				
 1.  
 8.   
 9.   
 10.   
 11.   
 12.   
 13.   
 14.   
 15.   
 16.   
 20.     
 21.   
 22.  

 

  • 第 1 行 :实体名(solrFeed )。
  • 第 2 行 :该项的可选主键,只有在导入增量时才用得到。
  • 第 3 行 :将要获取的 URL —在这个用例中是我在 Solr 上的博客站点。
  • 第 4 行 :用于从原始源映射内容的 EntityProcessor
  • 第 5 行 :用于指定如何从 XML 获取记录的 XPath 表达。(XPath 提供一种在 XML 文件中指定特定元素或属性的方法。如果不熟悉 XPath 表达的话,请参阅 参考资料 )。
  • 第 6 行 :要使用的 DataSource 的名称。
  • 第 7 行 :用于将字符串解析成 java.util.DateDateFormatTransformer
  • 第 8 行 :将通道名称(博客名称)映射到以 Solr 模式字段命名的数据源。此过程每个通道只发生一次,因此 commonField 属性指定该值必须用于每一个数据项。
  • 第 9-14 行 :将 RSS 提要的其他部分映射到 Solr Field
  • 第 15 行 :映射出版日期,但使用 DateFormatTransformer 将值解析为一个 java.util.Date 对象。
  • 第 16-21 行 :从数据库获取每一篇文章的评级的子实体。
  • 第 16 行query 属性指定要运行的 SQL。${solrFeed.link} 值被代替变量解析为每一篇文章的 URL。
  • 第 17 行 :导入增量时要运行的查询。${dataimporter.last_index_time} 由 DIH 提供。
  • 第 18 行 :使用 JDBC DataSource
  • 第 20 行 :将数据库中的评级栏映射到评级字段。如果未指定名称属性,将默认使用栏名。

下一步是运行导入。这可以通过提交 HTTP 请求来实现:

http://localhost:8983/solr/rss/dataimport?command=full-import

 

该 请求先将所有的文档从索引中移除,然后再进行完全导入。再强调一遍,这个请求首先从索引中移除全部文档,一定要警惕这一点。您可以随时浏览 http://localhost:8983/solr/rss/dataimport 获取 DIH 的状态。在这个用例中,我的输出如清单 10 所示:


清单 10. 导入结果

				
  
  
 0 
 0 
  
  
  
  rss-data-config.xml 
  
  
 idle 
  
  
 11 
 13 
 0 
 2008-10-03 10:51:07 
 Indexing completed. Added/Updated: 10 documents. 
  Deleted 0 documents. 
 2008-10-03 10:51:18 
 2008-10-03 10:51:18 
 0:0:11.50 
  
 This response format is experimental.  It is 
  likely to change in the future. 
  

 

增量导入功能

使用数据库时,在完全导入之后,下一次只需导入那些改变了的记录。这个功能就叫做 增量导入 。不幸的是,它还不能适用于 RSS 提要。要是可以的话,命令应该是这样的:
http://localhost:8983/solr/rss/dataimport?command=delta-import

 

您为其创建索引的文档的数量可能与我不同(因为我有可能会把其他 Solr 文章添加到提要)。为文档创建索引之后,我就可以查询索引了,就像在 http://localhost:8983/solr/rss/select/?q=*%3A*&version=2.2&start=0&rows=10&indent=on 中一样,它返回了带索引的全部文档,共 10 篇。

有了这些准备,您就可以使用 DIH 了。再深入一些,就是如何替换变量和如何编写 Transformer 了。要想学习更多有关此话题的知识,请参见 参考资料 中的 DataImportHandler wiki 页面链接。下面将介绍:如何使用 MoreLikeThisComponent 查找相似页面。

查找相似页面

MoreLikeThisComponent和 Solr 模式

MLT 要求字段被储存或使用 检索词向量 ,检索词向量以一种以文档为中心的方式储存信息。MLT 通过文档的内容来计算文档中关键词语,然后使用原始查询词语和这些新词语创建一个新的查询。提交新查询就会返回其他查询结果。所有这些都可以用检索词向量来完成:只需将 termVectors="true" 添加到 schema.xml 中的 声明。

在 Google 上尝试一个查询,您会注意到每一个结果都包含一个 “相似页面” 链接,单击该链接,就会发布另一个搜索请求,查找出与起初结果类似的文档。Solr 使用 MoreLikeThisComponent (MLT)和 MoreLikeThisHandler 实现了一样的功能。如上所述,MLT 是与标准 SolrRequestHandler 集成在一起的;MoreLikeThisHandler 与 MLT 结合在一起,并添加了一些其他选项,但它要求发布一个单一的请求。我将着重讲述 MLT,因为使用它的可能性更大一些。幸运的是,不需要任何设置就可以查询它,所以您现在就可以开始查询。

您可以向请求添加很多 HTTP 查询参数,并且大部分参数都有智能的默认值,因此我将着重讲述使用 MLT 必须了解的参数。(要了解更多的详细信息,请参见 参考资料 获得 Solr wiki 的 MLT 页面链接)。


表 2. MoreLikeThisComponent 参数

参数 说明 值域
mlt 在查询时,打开 / 关闭 MoreLikeThisComponent 的布尔值。 真 | 假
mlt.count 可选。每一个结果要检索的相似文档数。 > 0
mlt.fl 用于创建 MLT 查询的字段。 模式中任何被储存的或含有检索词向量的字段。
mlt.maxqt 可选。查询词语的最大数量。由于长文档可能会有很多关键词语,这样 MLT 查询可能会很大,从而导致反应缓慢或可怕的 TooManyClausesException ,该参数只保留最关键的词语。 > 0

 

尝试下面的样例查询,然后检查返回结果中的 moreLikeThis 部分:

http://localhost:8983/solr/rss/select/?q=*%3A*&start=0&rows=10&mlt=true 
  &mlt.fl=description&mlt.count=3

 

http://localhost:8983/solr/rss/select/?q=solr&version=2.2&start=0&rows=10 
  &indent=on&mlt=true&mlt.fl=description&mlt.fl=title&mlt.count=3

 

接下来,我将介绍如何向应用程序添加 “您是不是要找……”(拼写检查)。

提供拼写建议

Lucene 和 Solr 很久以前就开始提供拼写检查功能了,但直到添加了 SearchComponent 架构之后,这些功能才可以无缝使用。现在您可以输入一个查询,让它不仅返回查询结果,并且为查询词语提供拼写建议(如果存在的话)。然后可以利用这些建议像 Google 那样显示 “您是不是要找……”,或者像 Yahoo! 那样显示 “请尝试……”。

集成拼写检查的妙处在于它能够(而且必须)根据索引中的标记给出建议。也就是说,它不必根据词典给出正确拼写的词语,而是根据与查询词语相似的拼写给出拼写建议(包括错误拼写)。例如,假设很多很多的人都将单词 hockey 错误拼写成 hockei 。查询 hockey 的用户很可能是想查找里面带有单词 hockei 的文档,因为它们是相关的(尽管是这些文档的作者不会拼写)。

SpellCheckComponent 与 MLT 不同,它不需要在 solrconfig.xml 和 schema.xml 文件中进行配置。首先,模式必须先声明一个 Field 和一个相关联的、其内容能够发挥拼写词典的作用的 FieldType 。按常规,该 FieldType 的分析过程要保持简单,而且不要派生词语或修改其他标志。我的样例 FieldType 声明了它的 ,如清单 11 所示:


清单 11. 声明一个

				
  
   
     
     
     
   
  

 

负责基本的标志化(尤其是拆分空格),然后将标志变成小写并移除复制。不用派生词语,也不用扩展同义词。就是这么简单。接下来我在 schema.xml 文件中声明了一个 field ,名为 spell ,它使用 textSpell 。接着,我声明了 ,将 solrconfig.xml 文件中的必要的部分连接起来,如清单 12 所示:


清单 12. 声明

				
  
    textSpell 
     
      default 
      spell 
      ./spellcheckerDefault 
     
  

 

在这个例子中,我将前面声明的 textSpell queryAnalyzerFieldType 关联起来。(注意,我使用前面讲述的 last-components 技术将组件到 Dismax 和 solrconfig.xml 中的标准 SolrRequestHandler 声明)。这能够确保正确分析输入查询,从而与拼写索引进行比较。其余的配置选项指定拼写检查器的名称、包含构建拼写索引所用的内容的 Field ,以及索引在磁盘上的储存位置。

完成全部配置之后,您必须构建拼写索引。这可以通过用 HTTP 向组件发送请求来完成,比如:

http://localhost:8983/solr/rss/select/?q=foo&spellcheck=true&spellcheck.build=true

 

拼写检查构建工作流程

要查询拼写检查索引,必须先构建它。初始构建完成后,您需要确定(通过您的应用程序)重新构建索引的频率。您也可以在用 solrconfig.xml 中的 postCommit 事件监听器完成提交之后再重新构建它。重构建的频率一定要以索引的更改数量为基准,但这一点并不是很重要,因为初始索引创建之后,很大地改动词典的可能性不大。

构建了索引之后,像往常一样查询并添加 spellcheck=true 参数就会返回建议了。例如,清单 13 打开了拼写检查特性:


清单 13. 显示拼写检查的查询

				
 http://localhost:8983/solr/rss/select/?q=holr&spellcheck=true

 

运行清单 13 中的查询会返回零个结果,但是它会提供以下建议:

  
  
   
	 1 
	 0 

	 4 
	  
	 solr 
	  
   
  
  

 

再深入一步,多个词语的查询也可以使用拼写检查。组件甚至能够自动地创建一个推荐的新查询,该查询将所有词语的最佳建议结合起来。这可以通过添加 spellcheck.collate=true 参数来实现。就像在错误拼写查询中一样,

 http://localhost:8983/solr/rss/select/?q=holr+foo&spellcheck=true&indent=on 
 &spellcheck.collate=true 

 

它生成了作为建议的一部分的结果 solr for 。但是要注意,这个合并的结果可能不会返回结果,这取决于您是否用 AND 将查询词语连接起来。

另外,拼写检查器还能采用与返回的建议数量和结果质量有关的查询参数。要想更多地了解 SpellCheckComponent 的详细信息,请参见 参考资料 中的 Solr wiki 页面链接。

接下来,我将介绍如何用 “付费排序” 来覆盖结果的自然排序。

编辑结果排序

在 理想的情况下,搜索引擎只返回与用户查询相关的文档。而在现实的查询中,编辑(没发现更合适的表达)通常需要指定特定文档在搜索结果中的特定位置。这样做 有很多原因。或许 “置顶” 的文档就是最好的查询结果。也可能是公司想让客户从相似的选择中找到利润率较高的产品。还可能是由第三方付费,提高某些查询词语的排名。不管是什么原因, 对于一般的查询,要根据相关度来排名,让特定的文档出现在特定的位置,通常是很困难的(甚至是不可能的)。而且,即便搜索引擎能为某个查询达到这个目的, 它也很可能会在这个过程中破坏其他 50 个查询。因此,现实中的搜索有这样一条基本规则:用户输入查询并不等于您必须搜索索引并给文档评级 。我知道,以构建搜索引擎为生的人说这件事有点奇怪,但这是事实。您可以缓存普通的查询,或只查找结果(Solr 可以完成),或根据上述的某个原因 “硬编码” 结果。

Solr 使用一个神秘命名的 SearchComponent (即 QueryElevationComponent )实现了简单排名。为了在样例应用程序中配置它,我按清单 14 所示的方法声明它:


清单 14. 声明一个 QueryElevationComponent

				
  
     
    string 
    elevate.xml 
   

 

queryFieldType 属性指定如何将传入的查询与要提升的查询相匹配。为简单起见,string FieldType 意味着查询必须是一个精确匹配的字符串,因为在 string FieldType 上是不会执行任何分析的。config-file 属性指定包含查询和相关联的结果的文件。它储存在一个单独的文件中,这样才能够从外部编辑它。文件必须位于 Solr 配置目录中或 Solr 数据目录中。如果它不在数据目录中,那么它会在 Solr 需要重新装载索引时再载入。

样例应用程序将 elevate.xml 储存在配置目录中。在它的内部,我为查询 “Charlotte” 添加了一个条目,以及其他 3 个条目,如清单 15 所示:


清单 15. 样例 elevate.xml 配置

				
  
  
  
  
  

 

清单 15 表明第一个链接出现的位置应该高于第二个链接,而第三个链接必须排除在结果之外。此后的结果按正常的顺序排列。想要查看正常的结果(包含这个组件时,默认打开提升),运行以下查询:

http://localhost:8983/solr/rss/select/?q=Solr&version=2.2&start=0&rows=10&indent=on 
  &fl=link&enableElevation=false

 

想要查看提升打开时的结果,请尝试:

http://localhost:8983/solr/rss/select/?q=Solr&version=2.2&start=0&rows=10&indent=on 
  &fl=link&enableElevation=true

 

应该会看到插入的提升输出。

这就是编辑排序。现在您已经能够轻松地为搜索改变查询结果,而且不会损害其他结果的质量。

SolrJ

在系列文章 使用 Apache Solr 实现更加灵巧的搜索 中, 我借用了一个简单的客户机,它通过 Java 平台使用 Apache HTTPClient 与 Solr 通信。现在,在 1.3 版本中,Solr 提供了一个易于使用的、基于 Java 的 API,它避免了 HTTP 链接和 XML 命令的所有弊端。这个称为 SolrJ 的新客户机使得通过 Java 代码处理 Solr 更加轻松。SolrJ API 通过良好定义的方法调用简化了索引创建、搜索、排序和分类。

同样,简单的例子或许是最好的老师。样例下载 包 含一个名为 SolrJExample.java 的 Java 文件。(参见下载中的 README.txt,查看有关编译的说明)。它展示了如何为 Solr 创建一些文档的索引,然后再运行一个对结果进行分类的查询。它做的第一件事是建立一个到 Solr 实例的连接,就像在 SolrServer server = new CommonsHttpSolrServer("http://localhost:8983/solr/rss"); 中一样。这会创建一个 SolrServer 实例,该实例通过 HTTP 和 Solr 通信。接下来,我将创建一个 SolrInputDocument ,用它将要创建索引的内容打包起来,如清单 16 所示:


清单 16. 使用 SolrJ 创建索引

				
 Collection docs = new HashSet(); 
 for (int i = 0; i <10; i++) { 
  SolrInputDocument doc = new SolrInputDocument(); 
  doc.addField("link", "http://non-existent-url.foo/" + i + ".html"); 
  doc.addField("source", "Blog #" + i); 
  doc.addField("source-link", "http://non-existent-url.foo/index.html"); 
  doc.addField("subject", "Subject: " + i); 
  doc.addField("title", "Title: " + i); 
  doc.addField("content", "This is the " + i + "(th|nd|rd) piece of content."); 
  doc.addField("category", CATEGORIES[rand.nextInt(CATEGORIES.length)]); 
  doc.addField("rating", i); 
  //System.out.println("Doc[" + i + "] is " + doc); 
  docs.add(doc); 
 } 

 

清单 16 中的循环只是创建了 SolrInputDocument (实际是一个夸张的 Map ),然后给它添加 Field 。我将它添加到了一个集合中,这样一次就能将所有的文档发送到 Solr。借助这个功能可以极大地加索引的创 ??,并减少通过 HTTP 发送请求导致的开销。然后我调用了 UpdateResponse respOnse= server.add(docs); ,它负责序列化文档并将其提交到 Solr。UpdateResponse 返回的值包含处理文档所用的时间的信息。为了让这些文档能够被搜索到,我又发出一个提交命令:server.commit();

当然,创建索引之后必须查询服务器,如清单 17 带注释的代码所示:


清单 17. 查询服务器

				
 //create the query 
 SolrQuery query = new SolrQuery("content:piece"); 
 //indicate we want facets 
 query.setFacet(true); 
 //indicate what field to facet on 
 query.addFacetField("category"); 
 //we only want facets that have at least one entry 
 query.setFacetMinCount(1); 
 //run the query 
 QueryResponse results = server.query(query); 
 System.out.println("Query Results: " + results); 
 //print out the facets 
 List facets = results.getFacetFields(); 
 for (FacetField facet : facets) { 
  System.out.println("Facet:" + facet); 
 } 

 

在这个简单的查询例子中,我设置了一个带有 content:piece 请求的 SolrQuery 实例。接下来,我表明自己对至少一个条目的所有的分类的分类信息感兴趣。最后,我通过 server.query(query) 调用提交查询,然后把一些结果打印了出来。这的确是一个过于简单的例子,但是它展示使用 Solr 时常见的任务,因此使您想到可以实现什么功能(突出显示、排序等)。要学习更多有关用 SolrJ 查询的可用选项的知识,请参见 参考资料 中的 SolrJ 链接。

用分布式搜索扩展索引大小

直 到 1.3 版本,Solr 才能通过复制轻松进行扩展,以满足更大容量的查询需求。但是,如果没有应用程序帮助完成大部分工作,要提供超出单个机器的承载额度的索引还是很困难的。例 如,通常可以在 Solr 中设置多个服务器,其中每一个服务器都有自己的索引,然后再让应用程序来管理搜索 —但这需要大量的自定义代码。在 1.3 版本中,Solr 添加了分布式搜索功能。应用程序将文档分布到几个计算机上,Solr(和其他程序)通常称之为 片(shard) 。 每一个片都包含自己的独立索引,而且 Solr 能够跨片协调索引查询。不幸的是,应用程序仍然需要将要创建索引的文档发送到每一个片,但这可能会添加到将来的 Solr 版本中。同时,可以使用一个简单的散列函数根据文档的唯一 ID 确定将文档发送到什么片。与此同时,我将关注搜索的等式方面。

Solr 机器容量

一个机器可以容纳的索引大小取决于机器的配置(RAM、CPU、磁盘等)、查询和索引的量,以及文档的大小和搜索模式。但是通常一个机器能够容纳的文档数量约在几百万到 1 亿之间。

要 开始使用分布式搜索,用户需要花些时间考虑架构。如果仅需要几个片,而且不考虑复制的话,那么可以在每个机器上放置一个片,并且每一个片都能够创建索引和 提供搜索。但如果索引和查询量很大的话,就必须复制每一个片。设置这种系统的常用的方法就是将每一个片及其复制放到一个载入平衡器的后面。图 2 展示了这个架构:


图 2. 分布式和复制 Solr 架构
Apache Solr 的新特性

分布式搜索的问题

Solr 的分布式搜索有几个缺点。第一,master 节点不容错,因此它一旦停止,系统就不能为新的文档创建索引或执行复制了。这并不会阻止搜索,而且对于可以手动或通过脚本和外部监控工具来管理片的较小分 布式设置而言,这并不是个问题。换句话说,您不会使用当前的架构来构建下一个 Google,但一定能够提供一个大索引。第二,并不是所有的 1.3 版本中的 SearchComponent 都是分布式感知的。搜索、分类、调试和突出显示组件是分布是感知的;而其他的不常用的组件,正在努力实现这个功能。在分布式搜索的 wiki 链接中,可以看到一些小警告和所有细节信息(参见 参考资料 )。

注意,图 2 中输入的请求可以进入任何一个复制的片中,因为它们是功能齐全的 Solr 实例。然后,检索节点会将请求发送到其他片。这些请求仅仅是普通的 Solr 请求。要将请求提交到 Solr 服务器并分发请求,需要将 shards 参数添加到请求,比如:

http://localhost:8983/solr/select? 
  shards=localhost:8983/solr,localhost:7574/solr&q=ipod+solr

 

在 这个例子中,我假定在本地主机上运行了两个 Solr 服务器(它不是真正的分布式的;它适合于这里的


推荐阅读
  • 一:什么是solrSolr是apache下的一个开源项目,使用Java基于lucene开发的全文搜索服务器;Lucene是一个开放源代 ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 第二章:Kafka基础入门与核心概念解析
    本章节主要介绍了Kafka的基本概念及其核心特性。Kafka是一种分布式消息发布和订阅系统,以其卓越的性能和高吞吐量而著称。最初,Kafka被设计用于LinkedIn的活动流和运营数据处理,旨在高效地管理和传输大规模的数据流。这些数据主要包括用户活动记录、系统日志和其他实时信息。通过深入解析Kafka的设计原理和应用场景,读者将能够更好地理解其在现代大数据架构中的重要地位。 ... [详细]
  • ZooKeeper 学习
    前言相信大家对ZooKeeper应该不算陌生。但是你真的了解ZooKeeper是个什么东西吗?如果别人面试官让你给他讲讲ZooKeeper是个什么东西, ... [详细]
  • 部署solr建立nutch索引
    2019独角兽企业重金招聘Python工程师标准接着上篇nutch1.4的部署应用,我们来部署一下solr,solr是对lucene进行了封装的企 ... [详细]
  • camel_使用Camel在来自不同来源的Solr中索引数据
    camelApacheSolr是建立在Lucene之上的“流行的,快速的开源企业搜索平台”。为了进行搜索(并查找结果),通常需要从不同的源(例如内容管理 ... [详细]
  • Lucene 全文检索技术入门
    一、搜索引擎的历史萌芽:Archie、Gopher起步:Robot(网络机器人)的出现与spider(网络爬虫)发展:excite、galax ... [详细]
  • Flume 开源分布式日志收集系统
    为什么80%的码农都做不了架构师?Flume--开源分布式日志收集系统Flume是Cloudera提供的一个高可用的、高可靠的开源分布式海量日志收集系统 ... [详细]
  • 本文详细探讨了几种常用的Java后端开发框架组合及其具体应用场景。通过对比分析Spring Boot、MyBatis、Hibernate等框架的特点和优势,结合实际项目需求,为开发者提供了选择合适框架组合的参考依据。同时,文章还介绍了这些框架在微服务架构中的应用,帮助读者更好地理解和运用这些技术。 ... [详细]
  • 本文详细介绍了如何安全地手动卸载Exchange Server 2003,以确保系统的稳定性和数据的完整性。根据微软官方支持文档(https://support.microsoft.com/kb833396/zh-cn),在进行卸载操作前,需要特别注意备份重要数据,并遵循一系列严格的步骤,以避免对现有网络环境造成不利影响。此外,文章还提供了详细的故障排除指南,帮助管理员在遇到问题时能够迅速解决,确保整个卸载过程顺利进行。 ... [详细]
  • 首先我们在taotao-search-interface工程中新建一个SearchService接口,并在接口中添加一个方法,如下图所示。接着,我们到taotao-search-s ... [详细]
  • javajigsaw2015年12月1日,星期二,在OpenJDK邮件列表中,MarkReinhold确认了许多人的期望:J ... [详细]
author-avatar
reisen_辉
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有