喜糖 2008-07-07
第5章搜索引擎
5.1简介
CompassCore提供了一个抽象层再加上精彩的Lucene的搜索引擎。在Lucene之上compasscore还提供一些附加的功能,例如,两相交易(事务)管理,快速更新,以及优化。在试图解释compass协同搜索引擎是如何工作之前,我们首先需要理解搜索引擎的域模型。
5.2别名,资源和属性
资源代表了属性的集合。你可以想一想,它作为一个虚拟文档-一大块数据,例如:一个网页,一封电子邮件,或者一系列的作者对象。一个资源总是有一个单一的别名,多个资源能够有同样的别名。别名就起到了连接资源和其映射定义(OSEM/XSEM/RSEM)的作用。属性就是一个保存名字以及相应值的地方(都为字符串)。资源当中的属性代表了一些元数据,类似这些元数据与其他资源相关联(例如作者名字)。
每个资源都与一个或多个id属性关联。这些资源要求compass能够管理资源基于id属性的加载以及资源的更新(总所周知直接使用Lucene达到这个要求比较困难)。ID属性在RSEM中有明确的定义在OSEM/XSEM当中则没有。
对于Lucene用户,Compass资源映射了到了Lucene文档,Compass属性映射到了Lucene领域。
5.2.1.UsingResource/Property
5.2.1使用资源/属性
在使用RSEM的时候,资源就相当于你的主要数据模型。它们构建起可搜索的内容,同时可以操纵它。当搜索的时候,资源就是搜索的结果。
另一个重要的资源能被用到的地方,也是常常被忽略的地方,就是OSEM/XSEM。当通过应用域模型(OSEM的情况),或者是xml数据结构(XSEM的情况)操纵搜索内容的时候,资源很少会被用到。使用搜索操作的时候这些资源能被用到。基于你的映射定义,语义模型通过资源和属性这种不一样的方式所访问。
让我们通过一个例子来简化这个声明,如果我们的应用有两种对象类型,配方和成分,我们可以同时映射配方标题和成分标题成同一个语义元数据名字,标题(资源属性名称),这将使我们在显示搜索结果的时候只是停留在资源级别,同时展示了属性标题的结果同时列举返回的资源结果。
5.3分析仪
分析仪是一个预先处理输入文字的组件。它们在查找的时候仍被使用(搜索的字符串同样也同样会被处理,同时索引文字将会被处理)。因此,对于索引和搜索来说使用同一个分析仪非常重要。
分析器是Lucene的一个类(符合org.apache.lucene.analysis.Analyzer类的标准)。Lucenecore自身带有几个分析器,你可以配置compass使其与当中的任何一个协同工作。以以下句子为例,"Thequickbrownfoxjumpedoverthelazydogs",我们可以看看不同的分析器是如何处理的。
Lucene同样带有扩展的库,拥有许多分析仪的实现(包括语言特性分析器),Compass能够配置与这些分析器一同工作。
5.3.1.配置分析器
Compass实例就相当于注册了一个分析器,每个分析仪都绑定到了一个名称。Compass内部的两个分析器是default和search。Default分析器是一个默认的分析器当其他的分析器没有被配置的时候(配置使用一个不同的分析器一般在映射定义当中完成通过引用一个不同的分析器名字),search是用在查询字符串的查找当没有分析器被定义的时候(当执行一个基于查询字符串通过查询编译API的时候需要配置一个不同的分析器)。如果没有任何配置的情况下,compass将会使用Lucene的标准分析器替代default分析器。
以下就是配置这两个分析器的例子。其中一个会替代default分析器,而另一个注册为myAnalyzer(将会稍后被引用,在不同的映射定义当中)
Compass同样支持LuceneAnalyzer类的实现(注意:实现分析器过滤器同样可以达到此目的,稍后讨论)。如果在上述的基础上再实现CompassConfigurable接口,额外的设置(参数)将能够使用配置文件。以下是一个配置的实例,在一个典型的分析器实现当中,能够支持参数threshold的配置。
5.3.2分析仪的过滤器
过滤器为分析流的附加过滤(或者是浓缩)功能提供简单的的支持,由此你不需要繁琐的再去建立你的过滤器了。同时,过滤器,能过被不同的分析仪共享,潜在的拥有不同的分析仪类型。
一个典型的过滤器实现需要实现compass的LuceneAnalyzerTokenFilterProvider类,这是一个单例方法用以创建LuceneTokenFilter。过滤器在注册了一个名字以后,分析仪可以在配置当中引用这个过滤器。接下来这个例子,配置了两个分析仪的过滤器,它们被应用在default分析仪当中。
5.3.3处理同义词
在搜索应用当中对同义词的要求很普遍,compass拥有一个简单的同义词分析过滤器:SynonymAnalyzerTokenFilterProvider。实现SynonymAnalyzerTokenFilterProvider需要配置一个参数,其能返回所有输入值的同义词。如果没有这样的实现提供,用类似的访问公共同义词数据库,或者文件输入结构系统也能简单实现。一下是一个例子显示如何配置实现同义词。
事实上,我们并没有为这种类型,和使用的同义词设置完全合乎标准的类名。这就是compass当中对同义词的简单实现(很自然的,你仍然会使用完全符合类名规范的同义词令牌环过滤器的所提供的工具)
5.4.查询分析器
默认情况下,compass使用其自己的查询分析器,其是基于Lucene的查询分析器。Compass允许配置多个查询分析器(registeredunderalookupname),同时会覆盖默认的compass查询分析器(registeredunderthenamedefault)。定制查询分析器能够被用于扩展默认的查询语言支持,增加分析查询缓存,以及一些其他功能。一个定制的查询分析器必须实现LuceneQueryParser接口。
以下是配置一个定制的查询分析器,使用的是test这个名字:
5.5.索引结构
理解搜索引擎索引的工作原理非常重要,然后我们才能理解事务,优化,以及子索引散列。以下图表显示了搜索引擎索引的结构。
每一个子索引都有一个完全功能的索引结构(其映射到一个单一的Lucene索引)。Lucene索引部分拥有一个“元数据”文件包含索引(叫做“段”)和0到N的段文件。这些段文件可以是单个文件(如果复合设置已经启用)或者是多个文件(如果复合设置没有被启用)。段的功能与索引的功能很接近,其拥有辞去倒排索引数据的功能。(详情请参看相关概念)
索引分割是compass的一个主要功能,其允许灵活的以及可配置的方式去管理复杂的索引以及性能考虑。下面的章节将会更详细的解释这个功能的重要性,尤其实在事务管理当中。
5.6事务
Compass搜索引擎抽象体统事务管理在Lucene的基础上。这个抽象支持一般的通用事务级别:授权读取和序列化,以及比较特殊的批量插入。Compass为普通的事务级别提供两种事务提交方式。
5.6.1锁定
Compass利用Lucene的内部和外部处理锁的机制,创建了其自身的事务锁。但是值得注意的是这种事务锁定是处于“子索引”的级别(子索引是基于索引的),这就意味着脏操作只能锁定他们各自的子索引。所以,越是把关联/可搜索的内容映射到同一个索引(下一章节将会解释子索引散列码是怎么回事),就越多的关联/可搜索的内容将会被锁定当进行脏操作的时候,尽管搜索会越来越快。Lucene使用一种特殊的文件去管理内部和外部处理过程锁,这些也是可以在compass当中配置的。你可以通过compass配置管理事务的超时时间以及轮询间隔。
当有一个脏操作(例如:保存或删除)发生的时候,Compass事务要求锁,这使得“只读”的事务越快越好。下面的配置文件说明了在两个主要的地方配置锁,事务锁超时(默认是10秒)和事务锁轮询时间(compass检查锁是否释放的频率)(默认的是100毫秒)
5.6.2事务的隔离
5.6.2.1授权读取
授权读取的事务隔离级别允许隔离一个事务当中改变的提交,直到另一个事务提交。它仍然允许(load/get/find)操作在帐户发生变化的情况下完成。这就意味着一个删除操作在一个事务当中发生将会被过滤掉,如果一个查询在这个事务当中被执行,其会被在这个删除滞后才会被执行。
当开始一个授权读取的事务的时候,事务锁不会被获得。读操作也不会获得一个事务锁。只有当脏读取发生的时候才会获得一个事务锁。当别名/可搜索的内容的索引涉及到脏操作的时候将获得一个事务锁,例如,子索引,所有映射到这个子索引的别名/可搜索的内容都会被加上锁。在compass当中,每个涉及到一个或多个的保存或创建操作的事务成功提交后,将会为每个索引创建另一个段(与Lucene管理其索引有所不同),以上可以帮助实现快速事务的快速提交,快速更新,以及为两相事务提交做好准备(这也是优化背后的原因)。
授权读取事务支持事务并发提交,当执行几个子索引的时候,事务的提交过程将会在几个不同的子查询中并发。当多个线程发生时可以使用compass的内部执行管理器,当然执行管理器(并发或者工作管理)能够配置。
5.6.2.2序列化
序列化事务级别操作与授权读取事务一样,但是当一个事务开始/结束,所有的子索引都需要一个事务锁。这就很自然的导致事务操作序列化了(似乎是性能的杀手)
一个特别的事务级别,lucene(以前被称之为批量插入)的事务隔离级别与授权读取的事务隔离级别相似,除了其脏操做在一个事务当中对于get/load/find的操作是不可见的。这种事务隔离级别非常适合长时间运行批量脏数据运行同时比授权读取更快。大多数有用的compass模式(例如集成对象关系映射工具)都能与lucene数据隔离级别和好结合。
理解lucene事务隔离级别在提交事务的时候所做得合并操作是十分重要的。Lucene在提交事务的时候有可能会做一些合并动作这取决于合并因素在配置的时候使用compass.engine.mergeFactor。这与授权读取事务隔离级别在事务提交的时候没有和并的操作不同。事务提交的时候的合并操作可能会花上一些时间,所以还有另一个操作就是配置一个更大的合并factor同时让优化器发挥其巨大魔力。(你能为一个优化器配置一个完全不一样的合并因素)
使用lucene事务隔离级别时另一个重要的参数是compass.engin.(默认是16M),它能取代最大的缓冲文本参数和控制事务性数据存储在内存当中数量。较大的数据能够获得更好的性能,越多分配越好。
Lucene事务支持并发事务提交当操作涉及到几个子索引的时候,几个事务提交的时候有可能会并发在几个不同的子索引上。这时候使用compass内部执行管理器来管理多个线程,同时执行管理器(并发或工作管理器)能够配置管理。
Hereishowthetransactionisolationlevelcanbeconfigured:
以下是lucene事务隔离级别的配置方式
最近,一个名叫 Magi 的搜索引擎成了重点关注对象,据称这个搜索引擎和我们常见的搜索引擎很不一样,有一种程序员们钟爱的 X 冷淡风格。于是我们打开 Magi 看了看。确实,这个页面看着就很让人舒爽。