我们在学习Sphinx 的过程中,Sphinx的配置是必不可少的,这里就给大家讲解一下Sphinx的配置。
先来看一份数据源的配置文件示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
source test { type = mysql
sql_host = 127.0.0.1 sql_user = root sql_pass = root sql_db = test sql_port = 3306 # optional, default is 3306
sql_query_pre = SET NAMES utf8 sql_query = SELECT id, name, add_time FROM tbl_test
sql_attr_timestamp = add_time
sql_query_info_pre = SET NAMES utf8 sql_query_info = SELECT * FROM tbl_test WHERE id=$id } |
其中
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 2 3 4 5 6 7 8 9 10 |
index test_index { source = test path = /usr/local/coreseek/var/data/test docinfo = extern charset_dictpath = /usr/local/mmseg3/etc/ charset_type = zh_cn.utf-8 ngram_len = 1 ngram_chars = U+3000..U+2FA1F } |
其中
index后面跟的test_index是索引名称
source:数据源名称;
path:索引文件基本名,indexer程序会将这个路径作为前缀生成出索引文件名。例如,属性集会存在/usr/local/sphinx/data/test1.spa中,等等。
docinfo:索引文档属性值存储模式;
charset_dictpath:中文分词时启用词典文件的目录,该目录下必须要有uni.lib词典文件存在;
charset_type:数据编码类型;
ngram_len:分词长度;
ngram_chars:要进行一元字符切分模式认可的有效字符集。
1 2 3 |
charset_type = utf8 ngram_len = 1 ngram_chars = U+3000..U+2FA1F |
1 2 3 |
charset_type = utf8 charset_dictpath = /usr/local/mmseg3/etc/ ngram_len = 0 |
可以看到,配置文件中的add_time被返回了,如上图的1所示。而sql_query_info返回的信息如上图的2所示。
Sphinx的配置不是很灵活,此处根据工作流程给出各部分的配置,更多的高级配置可以在使用时查阅文档。
介绍了Sphinx的配置之后,继续介绍在Sphinx中,负责做索引的程序Indexer是如何做索引的。
sphinx使用配置文件从数据库读出数据之后,就将数据传递给Indexer程序,然后Indexer就会逐条读取记录,根据分词算法对每条记录建立索引,分词算法可以是一元分词/mmseg分词。下面先介绍Indexer做索引时使用的数据结构和算法。
倒排索引是一种数据结构,用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。
倒排索引(Inverted Index):倒排索引是实现“单词-文档矩阵”的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。
传统的索引是:索引ID->文档内容,而倒排索引是:文档内容(分词)->索引ID。可以类比正向代理和反向代理的区别来理解。正向代理把内部请求代理到外部,反向代理把外部请求代理到内部。所以应该理解为转置索引比较合适。
倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。
单词词典是倒排索引中非常重要的组成部分,它用来维护文档集合中出现过的所有单词的相关信息,同时用来记载某个单词对应的倒排列表在倒排文件中的位置信息。在支持搜索时,根据用户的查询词,去单词词典里查询,就能够获得相应的倒排列表,并以此作为后续排序的基础。
对于一个规模很大的文档集合来说,可能包含几十万甚至上百万的不同单词,能否快速定位某个单词直接影响搜索时的响应速度,所以需要高效的数据结构来对单词词典进行构建和查找,常用的数据结构包括哈希加链表结构和树形词典结构。
· 文档(Document):一般搜索引擎的处理对象是互联网网页,而文档这个概念要更宽泛些,代表以文本形式存在的存储对象,相比网页来说,涵盖更多种形式,比如Word,PDF,html,XML等不同格式的文件都可以称之为文档。再比如一封邮件,一条短信,一条微博也可以称之为文档。在本书后续内容,很多情况下会使用文档来表征文本信息。
· 文档集合(Document Collection):由若干文档构成的集合称之为文档集合。比如海量的互联网网页或者说大量的电子邮件都是文档集合的具体例子。
· 文档编号(Document ID):在搜索引擎内部,会将文档集合内每个文档赋予一个唯一的内部编号,以此编号来作为这个文档的唯一标识,这样方便内部处理,每个文档的内部编号即称之为“文档编号”,后文有时会用DocID来便捷地代表文档编号。
· 单词编号(Word ID):与文档编号类似,搜索引擎内部以唯一的编号来表征某个单词,单词编号可以作为某个单词的唯一表征。
Indexer程序就是根据配置好地分词算法,将获取到的记录进行分词,然后用倒排索引做数据结构保存起来。
一元分词的核心配置
1 2 3 4 |
charsey_type = zh_cn.utf8 ngram_len = 1 ugram_chars = U+4E00..U+9FBF ngram_len是分词的长度。 |
ngram_chars标识要进行一元分词切分模式的字符集。
原生的Sphinx支持的分词算法是一元分词,这种分词算法是对记录的每个词切割后做索引,这种索引的优点就是覆盖率高,保证每个记录都能被搜索到。缺点就是会生成很大的索引文件,更新索引时会消耗很多的资源。所以,如果不是特殊需求,而且数据不是特别少的时候,都不建议使用一元分词。
国人在sphinx的基础上开发了支持中文分词的Coreseek。Coreseek与Sphinx唯一的不同就是Coreseek还支持mmseg分词算法做中文分词。
mmseg分词算法是基于统计模型的,所以算法的规则也是来自对语料库的分析和数学归纳,因为中文字符没有明确的分界,会导致大量的字符分界歧义,而且,中文里面,词和短语也很难界定,因此,算法除了要做统计和数学归纳之外,还要做歧义的解决。
在mmseg分词中,有一个叫chunk的概念。
chunk,是一句话的分词方式。包括一个词条数组和四个规则。
如:研究生命,有“研究/生命”和“研究生/命”两种分词方式,这就是两个chunk。
一个chunk有四个属性:长度、平均长度(长度/分词数)、方差、单字自由度(各单词条词频的对数之和)。
做好分词之后,会得到多种分词方式,这时候就要使用一些过滤规则来完成歧义的解决,以得到最终的分词方式。
歧义解决规则:
1、最大匹配 匹配最大长度的词。如“国际化”,有“国际/化”、“国际化”两种分词方式,选择后者。
2、最大平均词长度 匹配平均词最大的chunk。如“南京市长江大桥”,有“南京市/长江大桥”、“南京/市长/江大桥”三种分词方式,前者平均词长度是7/2=3.5,后者是7/3=2.3,故选择前者的分词方式。
3、最大方差 去方差最大的chunk。如“研究生命科学”,有“研究生/命/科学”、“研究/生命/科学“两种分词方式,而它们的词长都一样是2。所以需要继续过滤,前者方差是0.82,后者方差是0。所以选择第一种分词方式。
4、最大单字自由度 选择单个字出现最高频率的chunk。比如”主要是因为“,有”主要/是/因为“,”主/要是/因为“两种分词方式,它们的词长、方差都一样,而”是“的词频较高,所以选择第一种分词方式。
如果经过上述四个规则的过滤,剩下的chunk仍然大于一,那这个算法也无能为力了,只能自己写扩展完成。
原文来自:伯乐在线