Sphinx的介绍和原理探索

What/Sphinx是什么

定义

Sphinx是一个全文检索引擎。html

特性

  • 索引和性能优异
  • 易于集成SQL和XML数据源,并可以使用SphinxAPI、SphinxQL或者SphinxSE搜索接口
  • 易于经过分布式搜索进行扩展
  • 高速的索引创建(在当代CPU上,峰值性能可达到10 ~ 15MB/秒)
  • 高性能的搜索 (在1.2G文本,100万条文档上进行搜索,支持高达每秒150~250次查询)

 

Why/为何使用Sphinx

遇到的使用场景

遇到一个相似这样的需求:用户能够经过文章标题和文章搜索到一片文章的内容,而文章的标题和文章的内容分别保存在不一样的库,并且是跨机房的。mysql

可选方案

A、直接在数据库实现跨库LIKE查询算法

优势:简单操做sql

缺点:效率较低,会形成较大的网络开销数据库

B、结合Sphinx中文分词搜索引擎数组

优势:效率较高,具备较高的扩展性服务器

缺点:不负责数据存储网络

使用Sphinx搜索引擎对数据作索引,数据一次性加载进来,而后作了因此以后保存在内存。这样用户进行搜索的时候就只须要在Sphinx服务器上检索数据便可。并且,Sphinx没有MySQL的伴随机磁盘I/O的缺陷,性能更佳。数据结构

其余典型使用场景

一、快速、高效、可扩展和核心的全文检索机器学习

  • 数据量大的时候,比MyISAM和InnoDB都要快。
  • 能对多个源表的混合数据建立索引,不限于单个表上的字段。
  • 能未来自多个索引的搜索结果进行整合。
  • 能根据属性上的附加条件对全文搜索进行优化。 

二、高效地使用WHERE子句和LIMIT字句

当在多个WHERE条件作SELECT查询时,索引选择性较差或者根本没有索引支持的字段,性能较差。sphinx能够对关键字作索引。区别是,MySQL中,是内部引擎决定使用索引仍是全扫描,而sphinx是让你本身选择使用哪种访问方法。由于sphinx是把数据保存到RAM中,因此sphinx不会作太多的I/O操做。而mysql有一种叫半随机I/O磁盘读,把记录一行一行地读到排序缓冲区里,而后再进行排序,最后丢弃其中的绝大多数行。因此sphinx使用了更少的内存和磁盘I/O。

三、优化GROUP BY查询

在sphinx中的排序和分组都是用固定的内存,它的效率比相似数据集所有能够放在RAM的MySQL查询要稍微高些。

四、并行地产生结果集

sphinx可让你从相同数据中同时产生几份结果,一样是使用固定量的内存。做为对比,传统SQL方法要么运行两个查询,要么对每一个搜索结果集建立一个临时表。而sphinx用一个multi-query机制来完成这项任务。不是一个接一个地发起查询,而是把几个查询作成一个批处理,而后在一个请求里提交。

五、向上扩展和向外扩展

  • 向上扩展:增长CPU/内核、扩展磁盘I/O
  • 向外扩展:多个机器,即分布式sphinx

六、聚合分片数据

适合用在将数据分布在不一样物理MySQL服务器间的状况。
例子:有一个1TB大小的表,其中有10亿篇文章,经过用户ID分片到10个MySQL服务器上,在单个用户的查询下固然很快,若是须要实现一个归档分页功能,展现某个用户的全部朋友发表的文章。那么就要同事访问多台MySQL服务器了。这样会很慢。而sphinx只须要建立几个实例,在每一个表里映射出常常访问的文章属性,而后就能够进行分页查询了,总共就三行代码的配置。

 

介绍了Sphinx的工做原理,关于如何安装的文章在网上有不少,笔者就再也不复述了,如今继续讲解Sphinx的配置文件,让Sphinx工做起来。

How/如何使用Sphinx

Sphinx工做流程图

 

流程图解释

Database:数据源,是Sphinx作索引的数据来源。由于Sphinx是无关存储引擎、数据库的,因此数据源能够是MySQL、PostgreSQL、XML等数据。

Indexer:索引程序,从数据源中获取数据,并将数据生成全文索引。能够根据需求,按期运行Indexer达到定时更新索引的需求。

Searchd:Searchd直接与客户端程序进行对话,并使用Indexer程序构建好的索引来快速地处理搜索查询。

APP:客户端程序。接收来自用户输入的搜索字符串,发送查询给Searchd程序并显示返回结果。

Sphinx的工做原理

Sphinx的整个工做流程就是Indexer程序到数据库里面提取数据,对数据进行分词,而后根据生成的分词生成单个或多个索引,并将它们传递给searchd程序。而后客户端能够经过API调用进行搜索。

介绍了Sphinx工做原理以及Sphinx的配置以后,继续介绍在Sphinx中,负责作索引的程序Indexer是如何作索引的。

sphinx使用配置文件从数据库读出数据以后,就将数据传递给Indexer程序,而后Indexer就会逐条读取记录,根据分词算法对每条记录创建索引,分词算法能够是一元分词/mmseg分词。下面先介绍Indexer作索引时使用的数据结构和算法。

 

数据源配置

先来看一份数据源的配置文件示例:

复制代码
 1 source test
 2  {
 3      type                    = mysql
 4  
 5      sql_host                = 127.0.0.1
 6      sql_user                = root
 7      sql_pass                = root
 8      sql_db                  = test
 9      sql_port                = 3306    # optional, default is 3306
10  
11      sql_query_pre           = SET NAMES utf8
12      sql_query            = SELECT id, name, add_time FROM tbl_test
13  
14      sql_attr_timestamp      = add_time
15  
16    sql_query_info_pre      = SET NAMES utf8
17      sql_query_info          = SELECT * FROM tbl_test WHERE id=$id
18  }
复制代码

 

其中

source后面跟着的是数据源的名字,后面作索引的时候会用到;

type:数据源类型,能够为MySQL,PostreSQL,Oracle等等;

sql_host、sql_user、sql_pass、sql_db、sql_port是链接数据库的认证信息;

sql_query_pre:定义查询时的编码

sql_query:数据源配置核心语句,sphinx使用此语句从数据库中拉取数据;

sql_attr_*:索引属性,附加在每一个文档上的额外的信息(值),能够在搜索的时候用于过滤和排序。设置了属性以后,在调用Sphinx搜索API时,Sphinx会返回已设置了的属性;

sql_query_info_pre:设置查询编码,若是在命令行下调试出现问号乱码时,能够设置此项;

sql_query_info:设置命令行下返回的信息。

索引配置

复制代码
 1 index test_index
 2 {
 3     source                    = test
 4     path                      = /usr/local/coreseek/var/data/test
5 docinfo = extern 6 charset_dictpath = /usr/local/mmseg3/etc/ 7 charset_type = zh_cn.utf-8 8 ngram_len = 1 9 ngram_chars = U+3000..U+2FA1F 10 }
复制代码

其中

index后面跟的test_index是索引名称

source:数据源名称;

path:索引文件基本名,indexer程序会将这个路径做为前缀生成出索引文件名。例如,属性集会存在/usr/local/sphinx/data/test1.spa中,等等。

docinfo:索引文档属性值存储模式;

charset_dictpath:中文分词时启用词典文件的目录,该目录下必需要有uni.lib词典文件存在;

charset_type:数据编码类型;

ngram_len:分词长度;

ngram_chars:要进行一元字符切分模式承认的有效字符集。

中文分词核心配置

一元分词

1 charset_type = utf8
2 
3 ngram_len = 1
4 
5 ngram_chars = U+3000..U+2FA1F

mmseg分词

1 charset_type = utf8
2 
3 charset_dictpath = /usr/local/mmseg3/etc/
4 
5 ngram_len = 0

运行示例

数据库数据

 

使用indexer程序作索引

 

查询

能够看到,配置文件中的add_time被返回了,如上图的1所示。而sql_query_info返回的信息如上图的2所示。

 

Sphinx的配置不是很灵活,此处根据工做流程给出各部分的配置,更多的高级配置能够在使用时查阅文档。

倒排索引

倒排索引是一种数据结构,用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最经常使用的数据结构。

倒排索引(Inverted Index):倒排索引是实现“单词-文档矩阵”的一种具体存储形式,经过倒排索引,能够根据单词快速获取包含这个单词的文档列表。

传统的索引是:索引ID->文档内容,而倒排索引是:文档内容(分词)->索引ID。能够类比正向代理和反向代理的区别来理解。正向代理把内部请求代理到外部,反向代理把外部请求代理到内部。因此应该理解为转置索引比较合适。

倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。

单词词典是倒排索引中很是重要的组成部分,它用来维护文档集合中出现过的全部单词的相关信息,同时用来记载某个单词对应的倒排列表在倒排文件中的位置信息。在支持搜索时,根据用户的查询词,去单词词典里查询,就可以得到相应的倒排列表,并以此做为后续排序的基础。

对于一个规模很大的文档集合来讲,可能包含几十万甚至上百万的不一样单词,可否快速定位某个单词直接影响搜索时的响应速度,因此须要高效的数据结构来对单词词典进行构建和查找,经常使用的数据结构包括哈希加链表结构和树形词典结构。

倒排索引基础知识

  • 文档(Document):通常搜索引擎的处理对象是互联网网页,而文档这个概念要更宽泛些,表明以文本形式存在的存储对象,相比网页来讲,涵盖更多种形式,好比Word,PDF,html,XML等不一样格式的文件均可以称之为文档。再好比一封邮件,一条短信,一条微博也能够称之为文档。在本书后续内容,不少状况下会使用文档来表征文本信息。
  • 文档集合(Document Collection):由若干文档构成的集合称之为文档集合。好比海量的互联网网页或者说大量的电子邮件都是文档集合的具体例子。
  • 文档编号(Document ID):在搜索引擎内部,会将文档集合内每一个文档赋予一个惟一的内部编号,以此编号来做为这个文档的惟一标识,这样方便内部处理,每一个文档的内部编号即称之为“文档编号”,后文有时会用DocID来便捷地表明文档编号。
  • 单词编号(Word ID):与文档编号相似,搜索引擎内部以惟一的编号来表征某个单词,单词编号能够做为某个单词的惟一表征。

 Indexer程序就是根据配置好地分词算法,将获取到的记录进行分词,而后用倒排索引作数据结构保存起来。

 分词算法

一元分词

一元分词的核心配置

1 charsey_type = zh_cn.utf8
2 ngram_len = 1
3 ugram_chars = U+4E00..U+9FBF

ngram_len是分词的长度。

ngram_chars标识要进行一元分词切分模式的字符集。

 

原生的Sphinx支持的分词算法是一元分词,这种分词算法是对记录的每一个词切割后作索引,这种索引的优势就是覆盖率高,保证每一个记录都能被搜索到。缺点就是会生成很大的索引文件,更新索引时会消耗不少的资源。因此,若是不是特殊需求,并且数据不是特别少的时候,都不建议使用一元分词。

国人在sphinx的基础上开发了支持中文分词的Coreseek。Coreseek与Sphinx惟一的不一样就是Coreseek还支持mmseg分词算法作中文分词。

mmseg分词

mmseg分词算法是基于统计模型的,因此算法的规则也是来自对语料库的分析和数学概括,由于中文字符没有明确的分界,会致使大量的字符分界歧义,并且,中文里面,词和短语也很难界定,所以,算法除了要作统计和数学概括以外,还要作歧义的解决。

在mmseg分词中,有一个叫chunk的概念。

chunk,是一句话的分词方式。包括一个词条数组和四个规则。

如:研究生命,有“研究/生命”和“研究生/命”两种分词方式,这就是两个chunk。

一个chunk有四个属性:长度、平均长度(长度/分词数)、方差、单字自由度(各单词条词频的对数之和)。

作好分词以后,会获得多种分词方式,这时候就要使用一些过滤规则来完成歧义的解决,以获得最终的分词方式。

歧义解决规则:

一、最大匹配

匹配最大长度的词。如“国际化”,有“国际/化”、“国际化”两种分词方式,选择后者。

二、最大平均词长度

匹配平均词最大的chunk。如“南京市长江大桥”,有“南京市/长江大桥”、“南京/市长/江大桥”三种分词方式,前者平均词长度是7/2=3.5,后者是7/3=2.3,故选择前者的分词方式。

三、最大方差

去方差最大的chunk。如“研究生命科学”,有“研究生/命/科学”、“研究/生命/科学“两种分词方式,而它们的词长都同样是2。因此须要继续过滤,前者方差是0.82,后者方差是0。因此选择第一种分词方式。

四、最大单字自由度

选择单个字出现最高频率的chunk。好比”主要是由于“,有”主要/是/由于“,”主/要是/由于“两种分词方式,它们的词长、方差都同样,而”是“的词频较高,因此选择第一种分词方式。

若是通过上述四个规则的过滤,剩下的chunk仍然大于一,那这个算法也无能为力了,只能本身写扩展完成。

 

最后的最后

固然,有人会说数据库的索引也能够作到sphinx索引,只是数据结构不同而已,可是,最大的不一样是sphinx就像一张没有任何关系查询支持的单表数据库。并且,索引主要用在搜索功能的实现而不是主要的数据来源。所以,你的数据库也许是符合第三范式的,但索引会彻底被非规范化并且主要包含须要被搜索的数据。
另一点,大部分数据库都会遭遇一个内部碎片的问题,它们须要在一个大请求里遭遇太多的半随机I/O任务。那就是说,考虑一个在数据库的索引中,查询指向索引,索引指向数据,若是数据由于碎片问题被分开在不一样的磁盘中,那么这次查询将占用很长的时间。

 

总结

经过一个项目的实践,发现sphinx的使用要点主要在配置文件上,若是懂得配置了,那么基本用法很容易掌握。若是要深刻研究,好比研究其工做原理,那就得查阅更多的资料。高级特性尚未用到,往后用到再作分享。最后,若是还想扩展sphinx,定制更强大的功能,能够直接阅读源代码,而后编写扩展。使用sphinx也有弊端,若是须要保证高质量的搜索,那么就要常常手动维护词库。若是不能保持常常更新词库,那么能够考虑百度搜索之类的插件。若是能够加入机器学习的话,那么会更好。

转:

http://www.cnblogs.com/h-hq/p/5408933.html

相关文章
相关标签/搜索