Solr基本概念

搜索基本构成

搜索的基本定义,可以表述为以下4个步骤:

1) 构建索引:
Indexing,对文件、网站、数据库的记录进行处理以便可以进行搜索,被索引的文件称为文档。
构建索引之前,需要对文档的内容、结构、类型深入了解,这对于构建索引很有必要,对内容不理解,很难构建出优秀的搜索引擎。索引是使得文档可搜索的过程,一般是将文档各部分内容切分成词条(token),词条经过词干还原、不区分大小写等方式进行规范化后成为词项(term)。这个规范化的过程可以是简单的去掉停用词、大小写处理、词干还原,也可以是复杂的同义词扩展。从文档中构建出词项的过程,在Lucence以及更高层的Solr和ElasticSearch中,通过分析器Analyser来完成。

从文档中抽取出来的词项,通常存储在成为倒排索引的数据结构中,以便搜索引擎可以快速查找到。下图是一个简单的倒排索引示例:

Solr基本概念_第1张图片

左边的单词就是上面说的词项,每个索引种存储出现该词项的文档ID。例如life这个词出现在文档1,2,3中。除了简单地保存词项在哪个问答中出现以外,往往还会保存词项在文档中的重要程度、在文档中的位置等信息。这使得搜索引擎从简单的布尔模型(是否出现在文档中)进化到基于相关度的排序模型,这是很大的进步。

2)用户输入:
用户通过某种形式输入表达其信息需求,这个需求一般都是不完整的。
用户的输入可以是像Google那样很简洁的一个输入框,也可以提供更高级的选项,例如限制结果的时间范围,来源网站等信息。或者提供一套查询语法供高级的用户使用,主流的搜索引擎的支持这类复杂查询。

用户的输入提交到搜索引擎之后,采取与索引过程类似的手段到输入进行处理,例如去掉停用词,根据输入进行同义词扩展等。在具体的实现中,用户的输入最后都形式化为Query对象,例如Lucence提供了各种类型的Query,例如布尔类型、前缀查询等。

3)排名:
搜索引擎根据查询和索引种文档的匹配度(相关度)进行排名。
用户输入与被索引的文档之间的相关度计算,用于对文档进行排名。Google的PageRank非常出名,该算法根据文档被引用(外链)的次数对文档进行排序。向量空间模型(vector space model,VSM)也是很典型的一种模型。

这种模型将文档中出现的词条作为维度,以向量的形式来表示整个文档。例如整个文档库中有100W的词项,那么文档将被表示为100W维的向量。对于特定的一个文档,如果词汇在文档中出现,则对应维度取值为1,否则为0。最终的向量表示是一个很稀疏的高维矩阵。下图是一个简单的例子:

Solr基本概念_第2张图片

在这种模型下,用户的输入也被建模为一个文档向量,通过计算文档向量之间的相似度,来决定其排名。文档的相似度通过向量的夹角大小来表示,在数学上通过计算cosine值来得到。下图是一个二维的示意图,q代表用户输入的查询,d1和d2表示两个文档。

Solr基本概念_第3张图片

在Salton等人提出的经典向量空间模型中,词项在文档中的权重由文档本身的参数(局部)和整个文档集的参数(全局)来决定,就是大家熟知的TF-IDF。词项频率(Term frequency)表示该词汇在文档中出现的次数。文档频率(document frequency)表示这个词汇出现在整个文档集中的文档个数,逆文档频率则取反。也就是说,一个词汇在文档中出现的次数越多,某种程度上约重要。在全局上,如果一个词汇很少在文档中出现,那么它很有表征意义,也就是很重要。相反,像the,a之类的词汇,几乎在每个文档中都出现,因此其重要性要大打折扣。其数学表达如下:

image_1apsv41e6q06p5s4uk166ei351g.png-4.3kB

左边是词频,右边的分子是文档总数,分母是包含词项t的文档数量,log对量级做约束。Lucence的模型中,也用到了TD-IDF。

4)结果展示:
将排序结果按业务需求展示给用户,同时提供必要的交互。
结果的展示则跟业务关系比较紧密,例如手机App上的展示,需要根据产品及业务需求来确定。而Google的结果页面中,则包含了文档结果,直接的信息框或者直接的问题答案等。下面的截图是一些搜索结果:

Solr基本概念_第4张图片

Solr基本概念_第5张图片

Solr基本概念_第6张图片

标题如何展示,链接、重复结果的处理,也是搜索引擎重要的组成部分。在Solr中,结果可以以JSON,XML等形式返回,具体通过ResponseWriter来控制,前端产品根据业务决定如何将数据展示给用户。

Solr概念

Apache Solr是一个基于Lucence的开源搜索解决方案,被广泛应用到企业级应用中。它基于HTTP来完成索引的构建和搜索,各语言可以方便的与Solr进行交互,同时提供了多面浏览、高亮显示、缓存等非常优秀的机制。Solr Cloud使得对可用性和性能要求极高的应用可以基于Solr来构建。Solr提供了很方便的管理界面,启动Solr实例之后,可以在8983端口访问到如下界面:

Solr基本概念_第7张图片

Solr中,文档使用Document来抽象,每个Document包含一个或者多个Field。在构建索引之前,需要先确定文档有哪些Field,各个Field是什么类型,Filed是否加入索引,是否存储等属性。这些属性通过Solr Schema来定义,这有点类似于关系型数据库中表的定义。Schema使用XML来定义,每个索引(Core/Collection)都包含一个schema.xml文件来定义Schema。

Field的类型可以使用Solr内置的类型,也可以自己定义并声明Field类型,一个日期类型的Field类型声明如下:

<fieldType name="date" class="solr.DateField" sortMissingLast="true" omitNorms="true"/>

注意这是Field类型声明,而不是Field声明。

如果某个Field指定需要被索引,则Solr通过底层的Lucence Analyzer将相应的文档数据转化成索引。Analyzer由一个可选的CharFilter、一个必须的Tokenizer及零个或多个TokenFilter构成。CharFilter用于保留正常的位置偏移的同时,去掉不需要的内容信息,例如HTML的标签。Tokenizer对相应的文档内容进行分词,然后通过过滤器对切分之后的词进行规范化等处理。例如Solr内置的WhitespaceTokenizer通过空白来分词,StopFilter则从Token中移除停用词。下面的例子展示的是text字段类型的定义

<fieldType name="text" class="solr.TextField" positionIncrementGap="100">
    <analyzer type="index">
     <tokenizer class="solr.WhitespaceTokenizerFactory"/>

     <filter class="solr.WordDelimiterFilterFactory"/>
     <filter class="..." />
   analyzer>
 fieldType>

analyzer的type参数表名该类型值应用到索引过程,而不应用到搜索过程。有了字段类型声明之后,就可以声明Field了:

<field name="date" type="date" indexed="true" stored="true" multiValue="true"/>
<field name="title" type="text" indexed="true" stored="true"

Solr的schema定义中,除了Field类型声明、Field声明外,还包括其他的一些定义。例如可以使用来copy一个Filed到另一个Field中,比如原来一个Field区分大小写,我们使用copyField复制一份这个Field,同时不区分大小写。用于配置文档的唯一主键。

定义一个Solr索引,除了Schema以外,其他配置在solrconfig.xml中定义。例如Lucence版本,索引数据存放目录,类路径(如存放自定义插件的目录)。

Solr索引构建

Solr提供了很多种方式对数据进行索引,例如从XML或者JSON中构建索引,SCV也支持,或者通过SQL命令从数据库或者RSS源中读取数据。数据导入(索引)通过Data Importer Handler来实现。

索引的构建可以直接通过HTTP发送给Solr服务器,也可以通过类似SolrJ等客户端库来交互,这些客户端底层也只是封装了对Solr的Http调用。同时,Solr内置了功能强大的Tika,在创建索引的时候从原始数据中提取相应的内容来构建索引。

Solr对请求的处理使用RequestHandler实现,更新、新增等操作都通过对应的Handler来完成。Handler一半在solrconfig.xml中配置,也就是它的作用范围时一个索引(core/collection)。ExtractingRequestHandler用于从文档中提取内容构建索引,其配置如下:

<requestHandler name="/update/extract"
class="org.apache.solr.handler.extraction.ExtractingRequestHandler">
  <lst name="defaults">
    <str name="fmap.Last-Modified">last_modifiedstr>
    <str name="fmap.Page-Count">pageCountstr>
    <str name="fmap.Author">creatorstr>
    <str name="fmap.Creation-Date">createdstr>
    <str name="fmap.Last-Save-Date">last_modifiedstr>
    <str name="fmap.Word-Count">last_modifiedstr>
    <str name="fmap.Application-Name">generatorstr>
    <str name="fmap.Content-Type">mimeTypestr>

    <bool name="uprefix">ignored_bool>
  lst>
requestHandler>

你可能感兴趣的:(搜索)