solr全文检索实现原理 全文搜索引擎Solr的部署及基本原理

1.搜索引擎Solr环境搭建示例

Solr服务器使用java5开发,基于Lucene全文检索。 如果要搭建Solr,首先要配置java环境,安装相应的jdk和tomcat。 我这里就不详细说了。

以下是jdk1.7和tomcat1.7环境下搭建的solr4.10.3最新版本。

具体步骤如下:

1.前往官网下载。

2.创建目录/webapps/mysolr/solr

3、解压压缩包solr-4.10.3,在example下的webapps中找到solr.war包,并解压。

4、将解压后的war包(solr文件夹)复制到步骤2中创建的目录:/webapps/mysolr

5、将两个地方的jar包复制到/webapps/mysolr/solr/WEB-INF/lib

(1)example下lib包的所有jar包

(2)示例中lib包下的ext包中的所有jar包

6.将example/resource下的log4j.properties文件复制到/webapps/mysolr/solr/classpath

7.solrhome配置:

首先创建一个solrhome目录:/webapps/mysolr/solrhome,然后将example/solr下的所有文件复制到/webapps/mysolr/solrhome

然后修改配置文件/webapps/mysolr/solr/WEB-INF/web.xml,释放solr/home的注解,配置如下:

<env-entry> 
  <env-entry-name>solr/home</env-entry-name> 
  <env-entry-value>/webapps/mysolr/solrhome</env-entry-value> 
  <env-entry-type>java.lang.String</env-entry-type> 
</env-entry> 

8. 将 /webapps/mysolr/solr 部署到 tomcat 并启动 tomcat。

以上就完成了solr环境的基本搭建。 访问:8080/solr 可以看到如下界面:

Tomcat6下Solr3.6.1环境搭建

基于Tomcat的Solr3.5集群部署

在Linux上使用Nginx对Solr集群进行负载均衡

Linux下Solr的安装和使用

Solr实现低级查询解析(QParser)

Solr 4.0部署实例教程

2.关于solr,schema.xml的配置说明

schema.xml位于solr/conf/目录下,类似于数据表配置文件。

定义添加到索引的数据的数据类型,主要包括类型、字段等默认设置。

1、我们先看type节点,它定义了FieldType子节点,包括name、class、positionIncrementGap等参数。

 1 < schema name = "example" version = "1.2" >
 2 < types >
 3 < fieldType name = "string" class = "solr.StrField" sortMissingLast = "true" omitNorms = "true" />
 4 < fieldType name = "boolean" class = "solr.BoolField" sortMissingLast = "true" omitNorms = "true" />
 5 < fieldtype name = "binary" class = "solr.BinaryField" />
 6 < fieldType name = "int" class = "solr.TrieIntField" precisionStep = "0" omitNorms = "true"
 7 positionIncrementGap = "0" />
 8 < fieldType name = "float" class = "solr.TrieFloatField" precisionStep = "0" omitNorms = "true"
 9 positionIncrementGap = "0" />
10 < fieldType name = "long" class = "solr.TrieLongField" precisionStep = "0" omitNorms = "true"
11 positionIncrementGap = "0" />
12 < fieldType name = "double" class = "solr.TrieDoubleField" precisionStep = "0" omitNorms = "true"
13 positionIncrementGap = "0" />
14 ...
15 </ types >
16 ...
17 </ schema >

必要时,fieldType还需要定义索引和查询该类数据时要使用的分析器,包括分词和过滤,如下:

 1 < fieldType name = "text_ws" class = "solr.TextField" positionIncrementGap = "100" >
 2 < analyzer >
 3 < tokenizer class = "solr.WhitespaceTokenizerFactory" />
 4 </ analyzer >
 5 </ fieldType >
 6 < fieldType name = "text" class = "solr.TextField" positionIncrementGap = "100" >
 7 < analyzer type = "index" >
 8 
12 < tokenizer class = "solr.WhitespaceTokenizerFactory" />
13 
17 
21 < filter class = "solr.StopFilterFactory"
22 ignoreCase = "true"
23 words = "stopwords.txt"
24 enablePositionIncrements = "true"
25 />
26 < filter class = "solr.WordDelimiterFilterFactory" generateWordParts = "1"
27 generateNumberParts = "1" catenateWords = "1" catenateNumbers = "1"
28 catenateAll = "0" splitOnCaseChange = "1" />
29 < filter class = "solr.LowerCaseFilterFactory" />
30 < filter class = "solr.SnowballPorterFilterFactory" language = "English"
31 protected = "protwords.txt" />
32 </ analyzer >
33 < analyzer type = "query" >
34 < tokenizer class = "solr.WhitespaceTokenizerFactory" />
35 < filter class = "solr.SynonymFilterFactory" synonyms = "synonyms.txt" ignoreCase = "true"
36 expand = "true" />
37 < filter class = "solr.StopFilterFactory"
38 ignoreCase = "true"
39 words = "stopwords.txt"
40 enablePositionIncrements = "true"
41 />
42 < filter class = "solr.WordDelimiterFilterFactory" generateWordParts = "1"
43 generateNumberParts = "1" catenateWords = "0" catenateNumbers = "0"
44 catenateAll = "0" splitOnCaseChange = "1" />
45 < filter class = "solr.LowerCaseFilterFactory" />
46 < filter class = "solr.SnowballPorterFilterFactory" language = "English"
47 protected = "protwords.txt" />
48 </ analyzer >
49 </ fieldType >

2、我们看一下fields节点中定义的具体字段(类似于数据库字段),它包含以下属性:

 1 < fields >
 2 < field name = "id" type = "integer" indexed = "true" stored = "true" required = "true" />
 3 < field name = "name" type = "text" indexed = "true" stored = "true" />
 4 < field name = "summary" type = "text" indexed = "true" stored = "true" />
 5 < field name = "author" type = "string" indexed = "true" stored = "true" />
 6 < field name = "date" type = "date" indexed = "false" stored = "true" />
 7 < field name = "content" type = "text" indexed = "true" stored = "false" />
 8 < field name = "keywords" type = "keyword_text" indexed = "true" stored = "false" multiValued = "true" />
 9 
10 < field name = "all" type = "text" indexed = "true" stored = "false" multiValued = "true" />
11 </ fields >

3、建议创建复制字段,将所有全文字段复制到一个字段中,以便统一检索:

以下是复印设置:

1 < copyField source = "name" dest = "all" />
2 < copyField source = "summary" dest = "all" />

4.动态字段,没有具体名称的字段,使用dynamicField字段

例如:name为*_i,其类型定义为int,那么在使用该字段时,任务结果带有_i的字段都被认为符合该定义。 如name_i、school_i

1 < dynamicField name = "*_i" type = "int" indexed = "true" stored = "true" />
2 < dynamicField name = "*_s" type = "string" indexed = "true" stored = "true" />
3 < dynamicField name = "*_l" type = "long" indexed = "true" stored = "true" />
4 < dynamicField name = "*_t" type = "text" indexed = "true" stored = "true" />
5 < dynamicField name = "*_b" type = "boolean" indexed = "true" stored = "true" />
6 < dynamicField name = "*_f" type = "float" indexed = "true" stored = "true" />
7 < dynamicField name = "*_d" type = "double" indexed = "true" stored = "true" />
8 < dynamicField name = "*_dt" type = "date" indexed = "true" stored = "true" />

schema.xml 文档注释中的信息:

1、为了提高性能,可以采取以下措施:

2. <模式名称=“示例”版本=“1.2”>

3. 字段类型

1 < fieldType name =" string " class =" solr.StrField " sortMissingLast =" true " omitNorms =" true " />

可选属性:

StrField 类型不会被解析,而是逐字索引/存储。

StrField 和 TextField 都有一个可选属性“compressThreshold”,它确保压缩到不小于一个大小(单位:char)

1  < fieldType name =" text " class =" solr.TextField " positionIncrementGap =" 100 " >

solr.TextField 允许用户通过分析器自定义索引和查询,分析器包括分词器和多个过滤器。

name:字段类型名称

类:java类名

索引:默认 true。 指示应搜索和排序此数据。 如果数据未建立索引,stored 应该为 true。

已存储:默认 true。 表示该字段适合包含在搜索结果中。 如果不存储数据,indexed 应该为 true。

sortMissingLast:表示没有指定字段数据的文档排在有指定字段数据的文档后面。

sortMissingFirst:表示将指定字段中没有数据的文档排在指定字段中有数据的文档之前。

omitNorms:当字段长度不影响分数并且索引期间不执行boost时,将其设置为true。 一般文本字段未设置为 true。

termVectors:如果该字段用于更多类似的内容并突出显示功能,则应设置为 true。

压缩:该字段被压缩。 这可能会导致索引和搜索速度变慢,但会减少存储空间。 只有StrField和TextField可以压缩,通常适用于长度超过200个字符的字段。

multiValued:当字段有多个值时,可以设置为true。

positionIncrementGap:和多值

一起使用,设置多个值之间的虚拟空白量

1  < tokenizer class =" solr.WhitespaceTokenizerFactory " />

空间分词,精确匹配。

1  < filter class =" solr.WordDelimiterFilterFactory " generateWordParts =" 1 " generateNumberParts =" 1 " catenateWords =" 1 " catenateNumbers =" 1 " catenateAll =" 0 " splitOnCaseChange =" 1 " />

分段和匹配时,请考虑“-”连字符、字母数字边界和非字母数字字符,以便“wifi”或“wi fi”可以匹配“Wi-Fi”。

1 < filter class =" solr.SynonymFilterFactory " synonyms =" synonyms.txt " ignoreCase =" true " expand =" true " />

同义词

1  < filter class =" solr.StopFilterFactory " ignoreCase =" true " words =" stopwords.txt " enablePositionIncrements =" true " />

删除停用词后在短语之间添加空格

stopword:在索引过程(索引和搜索)过程中被忽略的单词,例如 is this 等常见单词。 维护在conf/stopwords.txt中。

4. 领域

1 < field name =" id " type =" string " indexed =" true " stored =" true " required =" true " />

< 字段名称 ="text" 类型 ="text" 索引 ="true" 存储 ="false" multiValued ="true" />

全包(有点夸张)的字段,包括所有可搜索的文本字段,通过copyField实现。

<copyField source =“cat”dest =“text”/>

<copyField source =“名称”dest =“文本”/>

<copyField source =“manu”dest =“text”/>

<copyField source =“features”dest =“text”/>

<copyField source =“includes”dest =“text”/>

添加索引时,将复制字段(如cat)中的所有数据复制到文本字段中。

影响:

<dynamicField name =“*_i”类型=“int”索引=“true”存储=“true”/>

如果字段名称不匹配,将使用动态字段来尝试匹配各种定义的模式。

1  < dynamicField name =" * " type =" ignored " multiValued=" true " />

如果通过上面的匹配没有找到,可以定义这个,然后定义一个类型来将其处理为String。 (一般不会发生)

但如果没有定义的话,如果没有找到匹配就会报错。

5.其他一些标签

1 < uniqueKey > id </ uniqueKey >

文档的唯一标识符。 该字段必须填写(除非该字段被标记为required=“false”),否则Solr在构建索引时会报错。

< defaultSearchField > text </ defaultSearchField >

如果搜索参数中未指定特定字段,则这是默认域。

1 < solrQueryParser defaultOperator =" OR " />

配置搜索参数短语之间的逻辑,可以是“AND|OR”。

Tomcat6下Solr3.6.1环境搭建

基于Tomcat的Solr3.5集群部署

在Linux上使用Nginx对Solr集群进行负载均衡

Linux下Solr的安装和使用

Solr实现低级查询解析(QParser)

Solr 4.0部署实例教程

3.全文搜索引擎Solr系列—全文搜索基本原理

我们都用过新华字典。 如果让你翻到第38页,找到“cheat”的位置,这个时候你会怎么查看呢? 毫无疑问,你的眼睛会从38页的第一个字开始从头到尾扫描,直到找到“作弊”这个词。 这种搜索方法称为顺序扫描。 对于少量数据,顺序扫描就足够了。 但当你妈妈让你找出“陷阱”这个欺骗性的词在哪一页时,如果你从第一页的第一个词开始逐个扫描,那你就真的被骗了。 这时候就需要用到索引了。 索引记录了“坑”这个词在哪一页。 你只需要在索引中找到“坑”字solr全文检索实现原理,然后找到对应的页码,答案就出来了。 因为在索引中搜索“坑”这个词是非常快的,因为你知道它的部首,所以你可以快速定位到这个词。

那么新华字典的目录(索引表)是如何编制的呢? 首先,对于《新华字典》这本书来说,除去目录之后,这本书只是一堆非结构化的数据集。 但聪明的人类善于思考和总结,会发现每个单词对应一个页码。 比如“坑”这个词在第38页,“爸爸”这个词在第90页。所以他们提取了这些信息,并将其构建成结构化数据。 类似于数据库中的表结构:

word    page_no
---------------
坑        38
爹        90
...       ...

这样就形成了一个完整的目录(索引库),查找时非常方便。 全文检索的原理类似,可以归结为两个过程:1.创建索引(Indexing)2.搜索索引(Search)。 那么索引是如何创建的呢? 索引中存储了什么? 搜索时如何找到索引? 带着这一系列问题继续阅读。

指数

Solr/Lucene 使用反向索引。 所谓反向索引就是从关键词到文档的映射过程。 保存这种映射信息的索引称为反向索引。

字段字符串列表和文档编号链表共同构成一个字典。 现在如果我们要搜索“lucene”,索引会直接告诉我们包含“lucene”的文档有:2,3,10,35,92,而不必在整个文档库中一一搜索。 如果要搜索同时包含“lucene”和“solr”的文档,那么将它们相交即可得到对应的两个倒排列表:3、10、35、92。

索引创建

假设有两个原始文档如下:

文件1:允许学生与朋友外出,但不允许喝啤酒。

文件2:我的朋友杰瑞去学校看望他的学生,却发现他们喝醉了,这是不允许的。

创建过程大致分为以下几个步骤:

1:将原始文档交给分词组件(Tokenizer)

分词组件(Tokenizer)会做以下事情(这个过程称为:Tokenize),处理的结果就是词汇单元(Token)

将文档划分为单个单词、删除标点符号并删除停用词。

2:将词汇单元(Token)传递给语言处理组件(Linguistic Processor)

语言处理组件(语言处理器)主要对获得的token进行一些语言相关的处理。 对于英语来说,语言处理组件(Linguistic Processor)一般会做以下事情:

更改为小写(Lowercase)。 将单词还原为其词根形式,例如将“cars”还原为“car”等。此操作称为词干提取。 将单词转换为词根形式,如“drove”转换为“drive”等。这种操作称为:词形还原。

语言处理器(linguisticprocessor)得到的结果称为术语。 本例中,经过语言处理后得到的术语如下:

"student","allow","go","their","friend","allow","drink","beer","my","friend","jerry","go","school","see","his","student","find","them","drink","allow"。

经过语言处理后,搜索驱动器时也可以搜索到驱动器。 词干提取和词形还原之间的异同:

三:将得到的词(Term)传递给索引组件(Indexer)

使用获得的单词(Term)创建字典

Term    Document ID
student     1
allow       1
go          1
their       1
friend      1
allow       1
drink       1
beer        1
my          2
friend      2
jerry       2
go          2
school      2
see         2
his         2
student     2
find        2
them        2
drink       2
allow       2

按字母顺序对字典进行排序:

Term    Document ID
allow       1
allow       1
allow       2
beer        1
drink       1
drink       2
find        2
friend      1
friend      2
go          1
go          2
his         2
jerry       2
my          2
school      2
see         2
student     1
student     2
their       1
them        2

将相同的单词(Term)合并到一个文档发布列表(Posting List)中

对于单词(Term)“允许”,包含该单词(Term)的文档一共有两个,并且该单词(Term)后面一共有两个文档链表。 第一个代表第一个包含“allow”的文档。 即1号文件。在该文件中,“允许”出现了两次。 第二个代表第二个包含“allow”的文档,即2号文档。在该文档中,“allow”出现了一次。

至此solr全文检索实现原理,索引创建完成。 当搜索“drive”时,还可以搜索“driven”、“drove”和“driven”。 因为在索引中,“drive”、“drove”、“driven”都会经过语言处理,变成“drive”。 搜索时,如果输入“驾驶”,输入的查询语句也会经过分词组件和语言处理组件。 处理步骤是查询“drive”,以便可以搜索到所需的文档。

搜索步骤

当搜索“microsoft job”时,用户的目的是在 Microsoft 寻找工作。 如果搜索结果是:“微软在软件行业做得很好……”,这与用户的期望相差太远。 如何进行合理有效的搜索,找到用户最想要的结果? 搜索主要分为以下几个步骤:

1:对查询内容进行词法分析、语法分析、语言处理

词法分析:区分查询内容中的单词和关键字,例如:english和janpan,“and”是关键字,“english”和“janpan”是普通单词。根据查询语法的语法规则形成一棵树

语言处理与创建索引时相同。 例如:倾斜–>倾斜,驱动–>驱动

2:搜索索引,得到符合语法树的文档集合

三:根据查询语句与文档的相关性对结果进行排序

我们将查询语句视为一个文档,并对文档之间的相关性(relevance)进行评分。 分数越高,文档的相关性越高,排名也越高。 当然,你也可以人为地影响评分。 例如,百度搜索不一定完全按照相关性排名。

如何判断文档之间的相关性? 一份文档由多个(或一个)单词(Term)组成,例如:“solr”、“toturial”。 不同的词可能有不同的重要性。 例如,solr比toturial更重要。 如果toturial在一个文档中出现了10次,但是solr只出现了一次,而另一个文档solr出现了4次,toturial出现了一次,那么后者很可能就是我们想要的搜索结果。 这就引出了术语权重的概念。

权重代表了该词在文档中的重要性。 越重要的词,权重越高,因此在计算文档相关性时影响力越大。 通过词之间的权重获得文档相关性的过程称为向量空间模型算法。

影响文档中单词重要性的主要方面有两个:

空间矢量模型

文档中单词的权重被视为向量

Document = {term1, term2, …… ,term N}
Document Vector = {weight1, weight2, …… ,weight N}

将您要查询的语句视为一个简单的文档,也由向量表示:

Query = {term1, term 2, …… , term N}
Query Vector = {weight1, weight2, …… , weight N}

将搜索到的文档向量和查询向量放到一个N维空间中,每个单词代表一个维度:

角度越小,越相似,相关性越大。

Tomcat6下Solr3.6.1环境搭建

基于Tomcat的Solr3.5集群部署

在Linux上使用Nginx对Solr集群进行负载均衡

Linux下Solr的安装和使用

Solr实现低级查询解析(QParser)

Solr 4.0部署实例教程

© 版权声明
THE END
喜欢就支持一下吧
点赞47赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容