Lucene全文检索基本原理

    一、总论

    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.语言处理跟索引建立的过程基本一样。

                

        第三步:搜索索引,得到符合语法树的文档。

         此步骤有分几小步:

  1. 首先,在反向索引表中,分别找出包含lucene,learn,hadoop的文档链表。

  2. 其次,对包含lucene,learn的链表进行合并操作,得到既包含lucene又包含learn的文档链表。

  3. 然后,将此链表与hadoop的文档链表进行差操作,去除包含hadoop的文档,从而得到既包含lucene又包含learn而且不包含hadoop的文档链表。

  4. 此文档链表就是我们要找的文档。

         第四步:根据得到的文档和查询语句的相关性,对结果进行排序。

         虽然在上一步,我们得到了想要的文档,然而对于查询结果应该按照与查询语句的相关性进行排序,越相关者越靠前。

         如何计算文档和查询语句的相关性呢?

         这个我就不会了。。。你们看看原作者写的吧!

         http://mp.weixin.qq.com/s/3z8qZeg_sTVw2_6hLkUdUw

         请关注Java团长,从他那里学到了很多,这篇文章手打的基本都看会了。

 

posted @ 2018-04-10 15:53  没有bug的土豆  阅读(1430)  评论(0编辑  收藏  举报