一、总论
Lucene是一个高效的、基于Java的全文检索库。
所以在了解Lucene之前要了解一下全文检索的概念。
在存入数据库中的数据我们分为两类:结构化数据和非结构化数据。
· 结构化数据 :指有具体的格式或者有限长度的数据,如数据库,元数据等。
· 非结构化数据 :指不定长或无固定格式的数据,如邮件,word文档等。
还有的是第三种数据格式:半结构化数据、如xml,html等,当根据需求可按结构化数据来处理、也可以抽出纯文本按非结构数据来处理。
对非结构化数据的叫法又叫全文数据。
按照对数据的分类,搜索也有两种:
对结构化数据搜索:如对数据库的搜索,用sql语句。再如对数据源的搜索,如利用windows搜索对文件名、类型、修改时间进行搜索等等。
对非结构化数据的搜索:如利用windows的搜索也可以搜索文件内容,linux下的grep命令、再如Google或者百度对大量数据的搜索。
对非机构化数据也即对全文数据的搜索主要有两种方法:
1.顺序扫描法:从字面上理解就是把要搜索的所有数据全部进行比较,找到需要的内容。
特点:算法简单,流程简单。
缺点:对于大量数据操作时效率极低。
2.全文检索:通过对非结构化数据的部分信息进行提取,然后进行组织,使其获得一定的结构,然后对此有一定结构的数据进行搜索,从而达到搜索速度的提高。而从非结构化数据提取的信息我们就叫做索引。
理解全文检索:比如字典,字典的拼音就是索引,我们可以通过索引查找相应的汉字,从而不需要对字典的所有汉字进行一个一个的查找。
那么建立索引就对非结构化查询来说至关重要。
二:初识索引
Lucene检索过程
图中过程分为两部分:一部分是收集数据另一部分是提供搜索服务。
但是它们都会用到一个东西Index索引库。
过程一:收集数据建立索引库
将现实中的结构化数据和非结构化数据进行提取信息,创建索引的过程。
那么索引如何创建呢?
首先我们要知道索引是什么,才能创建索引。
索引使我们解决顺序扫描效率慢的一个解决方法,因为顺序扫描需要对文件依次进行检索,从第一个到最后一个,那么我们有什么办法让它去找有该内容的文件呢?所以索引是我们标记该文件存储内容的一个东西。
我们现在要检索一个文件夹内的文件包含指定字符串,即已知字符串求文件,这个是比较复杂的,我们不知道哪个文件包含此字符串,需要检索所有的文件。那么反过来我们要找该文件包含哪些字符串,即已知文件求字符串,就简单些,因为我们知道指定的文件,扫描该文件即可找到所有字符串。
那么我们就将索引建立为字符串到文件的映射,就可以大大提高检索效率。由于从字符串到文件的映射是文件到字符串的反向过程,于是保存这种信息的索引被称为反向索引。
反向索引的保存信息一般如下:
假如我的文档集合里面有100篇文档,为了方便表示,我们为文档做编号,从1-100,得到下面的结构。
左边保存的是一系列字符串,称为词典。
每个字符串都是指向包含此字符串的文档链表,此文档链表称为倒排表。
有了索引,便使保存的信息和要索引的信息一致,可以大大加快索引的速度。
过程二:获取查询信息对索引库进行检索
比如说,我们要寻找既包含字符串“Lucene”又包含字符串“solr”的文档,我们只需要以下几步:
1.取出包含字符串“Lucene”的文档链表。
2.取出包含字符串“solr”的文档链表。
3.通过合并链表,找出既包含“Lucene”又包含“solr”的文件。
这就是全文检索的过程。
索引有一个好处就是创建索引只需要一次,重复检索不需要每次创建。
三:创建索引
第一步:需要索引的文档(Document)。
文件一:Students should be allowed to go out with their friends,but not allowed to drink beer.
文件二:My friend Jerry went to school to see his students but found them drunk which is not allowed .
第二步:将原文档传给分词组件(Tokenizer);
分词组件:
1.将文档分成一个一个单独的单词。
2.去除标点符号。
3.去除停词(Stop word)。
所谓的停词就是一种语言中最普通的一些单词,由于没有特别的意义,因而大多数情况下不能作为搜索的关键字,因而创建索引时会被去掉,而减小索引的大小。(this,a,the等)
对于每一种语言都有一个停词集合。
经历过分词(Tokenizer)后得到的结果称为词元(Token)。
在我们的例子中,便得到以下词元: “Students”,“allowed”,“go”,“their”,“friends”,“allowed”,“drink”,“beer”,“My”,“friend”,“Jerry”,“went”,“school”,“see”,“his”,“students”,“found”,“them”,“drunk”,“allowed”。
第三步:将得到的词元传给语言处理组件(Linguistic Processor)。
语言处理组件主要是对词元做一些同语言相关的处理。
1.变为小写。
2.将单词缩减为词根。如“cars”到“car”等。这种过程称为:stemming。
3.将单词缩减为词根形式。如“drove”到“drive”等。这种操作被称为:lemmatization。
两者从方式和算法上是不同的。stemming多为替换删减,而lemmatization则需要依赖单独的词典。
语言处理组件得到的结果称为词(Term)。
在我们的例子中,经过语言处理,得到的词(Term)如下:
“student”,“allow”,“go”,“their”,“friend”,“allow”,“drink”,“beer”,“my”,“friend”,“jerry”,“go”,“school”,“see”,“his”,“student”,“find”,“them”,“drink”,“allow”。
第四步:将得到的词(Term)传给索引组件。
1.利用得到的词创建一个字典。
2.对字典进行排序
3.合并相同的词成为文档倒排链表。
在表中,有 几个定义:
Document Frequency 即文档频次,表示总共有多少文件包含此词(Term)。
Frequency即词频率,表示此文件中包含了几个此词(Term)。
到此索引创建成功。
四、检索索引
接下来就是用户输入查询条件进行对索引的检索了,然后将文件返回给用户。
比如使用Google进行数据检索时,通常我们能的到几亿份文件,那么如何才能得到我们想要的数据呢?
这时一个词就可以解决:相关性。
相关性越高的文件对我们来说越重要,那么如何判断相关性就是把数据检出的关键。
检出数据的步骤:
第一步:用户输入查询语句。
查询语句一般都是有格式的,比如sql语句。
而查询语句也是有一定的规则。比如AND,OR,NOT等。
举个例子,用户输入语句:Lucene AND solr NOT hadoop。
就是说用户想要查询一个包含Lucene和solr但是不包含hadoop的文件。
第二步:对查询语句进行词法分析,语句分析,及语言处理。
1.词法分析主要是用来识别关键字和单词。
2.语法分析主要是分局查询语句的语法规则来形成一颗语法树。
通过树形结构排除不包含的信息。
3.语言处理跟索引建立的过程基本一样。
第三步:搜索索引,得到符合语法树的文档。
此步骤有分几小步:
-
首先,在反向索引表中,分别找出包含lucene,learn,hadoop的文档链表。
-
其次,对包含lucene,learn的链表进行合并操作,得到既包含lucene又包含learn的文档链表。
-
然后,将此链表与hadoop的文档链表进行差操作,去除包含hadoop的文档,从而得到既包含lucene又包含learn而且不包含hadoop的文档链表。
-
此文档链表就是我们要找的文档。
第四步:根据得到的文档和查询语句的相关性,对结果进行排序。
虽然在上一步,我们得到了想要的文档,然而对于查询结果应该按照与查询语句的相关性进行排序,越相关者越靠前。
如何计算文档和查询语句的相关性呢?
这个我就不会了。。。你们看看原作者写的吧!
http://mp.weixin.qq.com/s/3z8qZeg_sTVw2_6hLkUdUw
请关注Java团长,从他那里学到了很多,这篇文章手打的基本都看会了。