海量数据搜索---demo展现百度、谷歌搜索引擎的实现

在咱们日常的生活工做中,百度、谷歌这些搜索网站已经成为了咱们受教解惑的学校,俗话说得好,“有问题找度娘”。那么百度是如何在海量数据中找到本身须要的数据呢?为何它搜索的速度如此之快?咱们都知道是由于百度的搜索引擎,那么搜索引擎究竟是个什么东西呢?可能有的程序员会想到es,可是es并不能表明搜索引擎,它只是其中的一种工具,不过这种工具确实好用,效率很高。html

本文会向你们讲述搜索引擎的基本知识以及中文分词的一些方法、而后会作一个小的demo来尝试数据检索。让你们初步了解搜索引擎的实现。java

1、搜索引擎介绍

1.1 搜索引擎是什么

这里引用百度百科的介绍:git

搜索引擎(Search Engine)是指根据必定的策略、运用特定的计算机程序从互联网上搜集信息,在对信息进行组织和处理后,为用户提供检索服务,将用户检索相关的信息展现给用户的系统。程序员

1.2 搜索引擎分类

搜索引擎包括全文索引、目录索引、元搜索引擎、垂直搜索引擎、集合式搜索引擎、门户搜索引擎与免费连接列表等。github

本文主要介绍全文索引,即百度使用的搜索引擎分类。算法

全文索引数据库

首先是数据库中数据的搜集,搜索引擎的自动信息搜集功能分两种:apache

  • 一种是按期搜索,即每隔一段时间(好比Google通常是28天),搜索引擎主动派出“蜘蛛”程序,对必定IP地址范围内的互联网网站进行检索,一旦发现新的网站,它会自动提取网站的信息和网址加入本身的数据库。
  • 另外一种是提交网站搜索,即网站拥有者主动向搜索引擎提交网址,它在必定时间内(2天到数月不等)定向向你的网站派出“蜘蛛”程序,扫描你的网站并将有关信息存入数据库,以备用户查询。

当用户以关键词查找信息时,搜索引擎会在数据库中进行搜寻,若是找到与用户要求内容相符的网站,便采用特殊的算法——一般根据网页中关键词的匹配程度、出现的位置、频次、连接质量——计算出各网页的相关度及排名等级,而后根据关联度高低,按顺序将这些网页连接返回给用户。这种引擎的特色是搜全率比较高。windows

1.3 搜索引擎能解决什么问题

  • 高效查询数据(运用多种算法查询数据,查询速率是毫秒级别,不管是千万条数据仍是上亿的数据)服务器

  • 比较容易,将普通的数据库切换成搜索引擎比较容易。

  • 大数据量、时效性、高并发等等。

1.4 搜索引擎的应用场景

  • 数据库达到百万数据级别的时候
  • 要求检索时效性、性能要求高,Ms级响应

1.5 Solr

接下来看在日常的互联网中搜索引擎的应用Solr。那么什么是Solr呢?它和es相比有什么优势和不足呢?

咱们先来简单地介绍一下solr:

Solr是一个基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的面向使用的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,而且提供了一个完善的功能管理界面。它支持Xml/Http协议,支持JSONAPI接口。

它具备以下特色:

  • 可扩展性:Solr能够把创建索引和查询处理的运算分布到一个集群内的多台服务器上。

  • 快速部署:Solr是开源软件,安装和配置都很方便,能够根据安装包内的Sample配置直接上手,可分为单机和集群模式。

  • 海量数据:Solr是针对亿级以上的海量数据处理而设计的,能够很好地处理海量数据检索。

  • 优化的搜索功能:Solr搜索速度够快,对于复杂的搜索查询Solr能够作到毫秒级的处理,一般,几十毫秒就能处理完一次复杂查询。

2、分词介绍

接下来,咱们将了解分词是如何实现的。那么,咱们为何要去分词呢,这和搜索引擎有什么关系呢?咱们在搜索框里输入的几个词或者一段话是如何拆成多个关键字的呢?

你们据说过哪些分词器吗?好比lucene自带的中文分词器smartcn,还有最经常使用的IK分词器等等,今天咱们主要讲一下IK分词器。

2.1 IK分词器

IK分词器首先会维护几个词典来记录一些经常使用的词,如主词表:main2012.dic、量词表quantifier.dic、停用词stopword.dic。

Dictionary为字典管理类中,分别加载了这个词典到内存结构中。具体的字典代码,位于org.wltea.analyzer.dic.DictSegment。 这个类实现了一个分词器的一个核心数据结构,即Tire Tree。

Tire Tree(字典树)是一种结构至关简单的树型结构,用于构建词典,经过前缀字符逐一比较对方式,快速查找词,因此有时也称为前缀树。具体的例子以下。

举例

好比:我是北京海淀区中关村的中国人民。

咱们设置的词典是:北京、海淀区、中关村、中国、中国人民,那么根据词典组成的字典树如图所示:

而后咱们根据这个字典树来对这段话进行词语切分。IK分词器中,基本能够分为两种模式:一种是smart模式、一种是非smart模式,能够在代码中初始化的时候去配置。

咱们其实不用解释这两种模式的字面含义,直接打印两种模式的结果就能够看出来:

  • 原句:我是北京海淀区中关村的中国人民

  • smart模式:北京、海淀区、中关村、中国人民

  • 非smart模式:北京、海淀区、中关村、中国、中国人民

显而易见,非smart模式是将可以分出来的词所有输出;smart模式是根据内在的方法输出一个合理的分词结果,这就涉及到了歧义判断。

举例

举个更有表明性的例子:张三说的确实在理。

根据正向匹配可能的词元链:

  • L1:{张三,张,三}
  • L2:{说}
  • L3:{的确,的,确实,确,实在,实,在理,在,理}

首来看一下最基本的一些元素结构类:

public class Lexeme implements Comparable{  
    ……  
   
    //词元的起始位移  
    private int offset;  
    //词元的相对起始位置  
    private int begin;  
    //词元的长度  
    private int length;  
    //词元文本  
    private String lexemeText;  
    //词元类型  
    private int lexemeType;  
     ……  
}

这里的Lexeme(词元),能够理解为是一个词语或单词。其中的begin,是指其在输入文本中的位置。注意,它是实现Comparable的,起始位置靠前的优先,长度较长的优先,这能够用来决定一个词在一条分词结果的词元链中的位置,能够用于获得上面例子中分词结果中的各个词的顺序。  

/* 
* 词元在排序集合中的比较算法
* @see java.lang.Comparable#compareTo(java.lang.Object) 
*/  
public int compareTo(Lexeme other) {  
//起始位置优先  
    if(this.begin < other.getBegin()){  
        return -1;  
    }else if(this.begin == other.getBegin()){  
     //词元长度优先  
     if(this.length > other.getLength()){  
         return -1;  
     }else if(this.length == other.getLength()){  
         return 0;  
     }else {//this.length < other.getLength()  
         return 1;  
     }  
        
    }else{//this.begin > other.getBegin()  
     return 1;  
    }  
}

smart模式歧义消除算法:  

  • 词元位置权重比较(词元长度积),含义是选取长的词元位置在后的集合
  • L31:{的,确实,在理}1*1+2*2+3*2=11
  • L32:{的确,实,在理} 1*2+2*1+3*2=10
  • L33:{的确,实在,理} 1*2+2*2+3*1=9
  • 最后的分词结果:张三,说,的,确实,在理

分词就介绍这么多,你们能够去读一下IK分词器的源码,深刻地了解一下,源码地址:https://github.com/quentinxxz/Search/tree/master/IKAnalyzer2012FF_hf1_source/

3、倒排索引算法

3.1 介绍

咱们能够把倒排索引算法想象成查字典时的目录同样,咱们知道须要查的字的目录后,就会很快地查找到。若是用专业的语言解释的话就是:

倒排索引源于实际应用中须要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具备该属性值的各记录的地址。因为不是由记录来肯定属性值,而是由属性值来肯定记录的位置,于是称为倒排索引(inverted index)。带有倒排索引的文件咱们称为倒排索引文件,简称倒排文件(inverted file)。

倒排文件(倒排索引),索引对象是文档或者文档集合中的单词等,用来存储这些单词在一个文档或者一组文档中的存储位置,是对文档或者文档集合的一种最经常使用的索引机制。

搜索引擎的关键步骤就是创建倒排索引,倒排索引通常表示为一个关键词,而后是它的频度(出现的次数),位置(出如今哪一篇文章或网页中,及有关的日期,做者等信息),它至关于为互联网上几千亿页网页作了一个索引,比如一本书的目录、标签通常。读者想看哪个主题相关的章节,直接根据目录便可找到相关的页面。没必要再从书的第一页到最后一页,一页一页地查找。

3.2 Lucene倒排索引原理

Lucerne是一个开放源代码的高性能的基于java的全文检索引擎工具包,不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或者以此为基础创建起完整的全文检索引擎。

假设有两篇文章1和2:

文章1的内容为: Jack lives in BeiJing,I live in BeiJing too.    文章2的内容为: He lived in Taiyuan.

1)取得关键词 

首先咱们要用咱们以前讲的方式分词,而后因为英文的缘由,咱们须要将in、on、of这些没用实际意义的词过滤掉,而后将第三人称单数加s或者过去式加ed这些词还原回去,如lived变回live,lives变回live,而后把不须要的标点符号也去掉。通过上面的处理以后,剩下的关键字为:

文章1的全部关键词为:[Jack] [live] [BeiJing] [i] [live] [BeiJing]    

文章2的全部关键词为:[he] [live] [Taiyuan]

2)创建倒排索引

关键词            文章号[出现频率]              出现位置   
BeiJing             1[2]                      3,6   
he                  2[1]                      1   
i                   1[1]                      4   
live                1[2]                      2,5, 
                    2[1]                      2   
Taiyuan             2[1]                      3   
tom                 1[1]                      1

  以上就是lucene索引结构中最核心的部分。咱们注意到关键字是按字符顺序排列的(lucene没有使用B树结构),所以lucene能够用二元搜索算法快速定位关键词。  

3.3 实现

实现时,lucene将上面三列分别做为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不只保存有每一个关键词,还保留了指向频率文件和位置文件的指针,经过指针能够找到该关键字的频率信息和位置信息。  

3.4 压缩算法

为了减少索引文件的大小,Lucene对索引还使用了压缩技术。

首先,对词典文件中的关键词进行了压缩,关键词压缩为<前缀长度,后缀>,例如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>。

其次大量用到的是对数字的压缩,数字只保存与上一个值的差值(这样能够减少数字的长度,进而减小保存该数字须要的字节数)。例如当前文章号是16389(不压缩要用3个字节保存),上一文章号是16382,压缩后保存7(只用一个字节)。

3.5 使用缘由

假设要查询单词 “live”,lucene先对词典二元查找、找到该词,经过指向频率文件的指针读出全部文章号,而后返回结果。词典一般很是小,于是,整个过程的时间是毫秒级的。   

而用普通的顺序匹配算法,不建索引,而是对全部文章的内容进行字符串匹配,这个过程将会至关缓慢,当文章数目很大时,时间每每是没法忍受的。

4、solr基本配置以及使用

咱们在windows系统中安装solr。

下载地址 http://lucene.apache.org/solr/downloads.html

解压后:

cmd 进入solr的bin目录,使用命令 solr start(为了更方便,能够配置solr的环境变量,配好后能够直接在cmd中使用solr命名)

看到这个界面,说明solr服务启动成功,端口号为 8983,访问 http://localhost:8983,会自动跳转到http://localhost:8983/solr/#/

在这个页面会显示 solr的基本信息,lucene信息,Java信息等

而后咱们介绍一个solr的指令: solr -h 能够看到solr的基本信息

配置solr

配置核心core

solr create -c mycore -d baisc_configs:-c参数指定定义的核心名称,-d参数指定配置目录

执行该命令后,会多出一个test目录。

访问Solr Admin页面:http://localhost:8983/,查看core,多了一个 test

在\solr-6.3.0\server\solr\test目录下有conf和data目录,分别对应配置和数据。

给core添加数据

打开目录:\solr-6.3.0\server\solr\test\conf,添加一个字段:

<field name="name" type="string" indexed="false" stored="true" required="true" multiValued="false" />

而后重启solr: solr restart -p 8983

到Solr Admin页面,选择core-test-document,在Document(s)中填写数据:

{
"id":"1",
"name":"宝马"
}

点击submit,返回Status: success,则表明添加数据成功。

多加几条后,点击Query,查询数据:

查询界面的 q,表明 查询条件,如输入:name:"宝马",再次执行查询

也能够直接get方式访问url:http://localhost:8983/solr/test/select?q=name:宝马

做者:杨亨

来源:宜信技术学院

相关文章
相关标签/搜索