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

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

一、搜索引擎介绍

1.1 搜索引擎是什么

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

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

1.2 搜索引擎分类

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

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

全文索引

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

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

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

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

  • 高效查询数据(运用多种算法查询数据,查询速率是毫秒级别,无论是千万条数据还是上亿的数据)

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

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

1.4 搜索引擎的应用场景

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

1.5 Solr

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

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

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

它具有如下特点:

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

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

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

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

二、分词介绍

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

大家听说过哪些分词器吗?比如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 -;
}else if(this.begin == other.getBegin()){
//词元长度优先
if(this.length > other.getLength()){
return -;
}else if(this.length == other.getLength()){
return ;
}else {//this.length < other.getLength()
return ;
} }else{//this.begin > other.getBegin()
return ;
}
}

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.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 [] ,   
he []   
i []   
live [] ,,
[]   
Taiyuan []   
tom []

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

3.3 实现

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

3.4 压缩算法

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

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

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

3.5 使用原因

假设要查询单词 “live”,lucene先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结果。词典通常非常小,因而,整个过程的时间是毫秒级的。   

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

四、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":"",
"name":"宝马"
}

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

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

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

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

作者:杨亨

来源:宜信技术学院

海量数据搜索---demo展示百度、谷歌搜索引擎的实现的更多相关文章

  1. 百度谷歌雅虎三大搜索引擎比较和如何配置谷歌访问助手访问Google搜索服务

    引言: 由于近期网上盛传”百度搜索引擎已死“的消息,引发个人对于搜索引擎的思考.百度作为最大的中文搜索引擎,确实有着很大声誉,再加上本地化的优势,正成为国人们的首选,但是作为一名技术开发人员,使用搜索 ...

  2. hexo干货系列:(六)hexo提交搜索引擎(百度+谷歌)

    前言 能看到这里,说明大家都跟我一样,已经把博客搭起来并洋洋洒洒写了几篇博文,正春风得意感觉良好的时候,搭建博客有屎以来最大的危机出现在没有准备的我面前,百度+谷歌都无法搜索到我的博客.装逼还没几天就 ...

  3. ELK之方便的日志收集、搜索、展示工具

    大家在做分部署系统开发的时候是不是经常因为查找日志而头疼,因为各服务器各应用都有自己日志,但比较分散,查找起来也比较麻烦,今天就给大家推荐一整套方便的工具ELK,ELK是Elastic公司开发的一整套 ...

  4. Lucene.net站内搜索—3、最简单搜索引擎代码

    目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...

  5. 百度,谷歌,360,搜狗,神马等蜘蛛IP段

    https://www.imydl.com/wzjs/5971.html 记得3月份的时候明月分享过一篇[站长必备:百度.谷歌.搜狗.360等蜘蛛常见IP地址]的文章,好像一直都受到了众多站长们的关注 ...

  6. lesson5:Condition的原理分析及demo展示

    Condition 将 Object 监视器方法(wait,notify,和notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待 set(wa ...

  7. python根据搜索词下载百度图片

    # coding=utf-8 """根据搜索词下载百度图片""" import re import urllib import os def ...

  8. 百家搜索:在网站中添加Google、百度等搜索引擎

    来源:http://www.ido321.com/1143.html 看到一些网站上添加了各种搜索引擎.如Google.百度.360.有道等,就有点好奇,这个怎么实现?研究了一各个搜索引擎怎么传送关键 ...

  9. 百家搜索:在站点中加入Google、百度等搜索引擎

    来源:http://www.ido321.com/1143.html 看到一些站点上加入了各种搜索引擎. 如Google.百度.360.有道等.就有点好奇.这个怎么实现?研究了一各个搜索引擎怎么传送k ...

随机推荐

  1. 终极版Servlet——我只能提示您路过别错过

    终极版Servlet 前言:这两天看了SSM框架,本来是想往后继续学的,脑门一转又回来了,不能就这么不声不响的走了,看了这么多天的Servlet,再写最后一篇做个告别吧,这篇起名为终极版,是我现在所能 ...

  2. 角度转弧度&根据弧度计算圆周上点的坐标的方法

    角度转弧度: #define AngleToRadian(angle) (M_PI/180.0f)*angle 以正东面为0度起点计算指定角度所对应的圆周上的点的坐标: float radian = ...

  3. Linux虚拟机所装软件说明

    Linux虚拟机所装软件说明 第一台虚拟机192.168.72.201 的 /usr/local/ 目录下放了一下软件: drwxr-xr-x 3 root root 4096 6月 14 19:16 ...

  4. Oracle_InstantClient 及PL/SQL Developer工具的安装

    一.下载 InstantClient 地址: http://www.oracle.com/technology/software/tech/oci/instantclient/index.html i ...

  5. Python基础总结之初步认识---clsaa类(上)。第十四天开始(新手可相互督促)

    最近的类看着很疼,坚持就是胜利~~~ python中的类,什么是类?类是由属性和方法组成的.类中可能有很多属性,以及方法. 我们这样定义一个类: 前面是class关键字 后面school是一个类的名字 ...

  6. 恐怖的Hibernate和JavaFX Table CallBack!

    目录 [隐藏] 1 Hibernate 2 JavaFX Table Hibernate 最近在做 JavaFX 应用,不管再怎么避免数据持久化,但面对几十万的数据量的时候也只能乖乖的去配置持久层框架 ...

  7. Elasticsearch实战 | 必要的时候,还得空间换时间!

    1.应用场景 实时数据流通过kafka后,根据业务需求,一部分直接借助kafka-connector入Elasticsearch不同的索引中. 另外一部分,则需要先做聚类.分类处理,将聚合出的分类结果 ...

  8. Java中的魔法类-Unsafe

    Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别.不安全操作的方法,如直接访问系统内存资源.自主管理内存资源等,这些方法在提升Java运行效率.增强Java语言底层资源操作能 ...

  9. NAS

    NAS, Network Attached Storage, 网络附属存储, 简单来说就是连接在网络上, 可以存储资料的装置.可以用来做私有网盘,同步各种设备的照片.视频.音频和文件. 常见的 NAS ...

  10. 全屏滚动插件pagePiling.js

    全屏滚动效果是最近非常流行的网页设计形式,带给用户良好的视觉和交互体验.pagePiling.js 这款 jQuery 插件可以帮助前端开发人员轻松实现这种效果.支持所有的主流浏览器,包括IE8+,支 ...