参考:http://www.coreseek.com/uploads/pdf/sphinx_doc_zhcn_0.9.pdf
1.匹配模式
有如下可选的匹配模式:
-
- SPH_MATCH_ALL, 匹配所有查询词(默认模式)
- SPH_MATCH_ANY, 匹配查询词中的任意一个
- SPH_MATCH_PHRASE, 将整个查询看作一个词组,要求按顺序完整匹配
- SPH_MATCH_BOOLEAN, 将查询看作一个布尔表达式
- SPH_MATCH_EXTENDED, 将查询看作一个Sphinx内部查询语言的表达式
还有一个特殊的“完整扫描”模式,当如下条件满足时,该模式被自动激活:
1. 查询串是空的(即长度为零)
2. docinfo 存储方式为extern
在完整扫描模式中,全部已索引的文档都被看作是匹配的。这类匹配仍然会被过滤、排序或
分组,但是并不会做任何真正的全文检索。这种模式可以用来统一全文检索和非全文检索的
代码,或者减轻SQL服务器的负担(有些时候Sphinx扫描的速度要优于类似的MySQL查
询)
2. 布尔查询
布尔查询允许使用下列特殊操作符:
显式的与(AND)操作符
hello & world
或(OR)操作符
hello | world
非(NOT)操作符
hello -world
hello !world
分组(grouping)
( hello world )
以下是一个使用了如上全部操作符的例子:
布尔查询示例
( cat -dog ) | ( cat -mouse)
与(AND)操作符为默认操作,所以“hello world”其实就是“hello & world”
或(OR)操作符的优先级高于与操作符,因此“lookingfor cat | dog | mouse”意思是”looking for (
cat | dog | mouse )” 而不是 “(looking for cat) | dog | mouse”
像“-dog”这种查询不能被执行,因为它差不多包括索引所有文档。这既有技术上的原因,
也有性能上的原因。从技术上说,Sphinx并不总是保持一个全部文档ID的列表。性能方面,
当文档集非常大的时候(即10-100M个文档),对这种执行查询可能需要很长的时间。
3. 扩展查询
在扩展查询模式中可以使用如下特殊操作符:
或(OR)操作符
hello | world
非(NOT)操作符
hello -world
hello !world
字段(field)搜索符:
@title hello @body world
词组搜索符
“hello world”
近似搜索符
“hello world”~10
阀值匹配符
“the world is a wonderful place”/3
下例使用了上述大多数操作符:
扩展查询示例
“hello world” @title “example program”~5 @body python -(php|perl)
与(AND)操作为默认操作,因此“hello world”意思是“hello”和“world”必须同时存在文档才
能匹配。
或(OR)操作符的优先级要高于与操作符,因此”looking for cat | dog | mouse” 意思
是”looking for ( cat | dog | mouse )” 而不是”(looking for cat) | dog | mouse”;
近似距离以词为单位,随词数变化而变化,并应用于引号中的全部词。举个例子,”cat dog
mouse”~5 这个查询的意思是必须有一个少于8个词的词串,它要包含全部的三个词,也就
是说”CAT aaa bbb ccc DOG eee fff MOUSE” 这个文档不会匹配这个查询,因为这个词串正好
是8个词。
阀值匹配符引入了一种模糊匹配。它允许至少含有某个阈值数量个匹配词的文档通过。上述
例子(”the world is a wonderful place”/3)会匹配含有指定的六个词中的至少三个的那些文档。
类似如下查询中嵌套的括号
aaa | ( bbb ccc | ( ddd eee ) )
目前还是不允许的,但是这会在今后得以改进。
取否(也就是非(NOT)操作符)只允许用在最外一层且不能在括号(也就是分组)里。这
个特性不会改变,因为支持嵌套的非操作会大大提高词组相关度计算实现的复杂性。
4. 权值计算
采用何种权值计算函数(目前)取决于查询的模式。
There are these major parts which are used in the weighting functions:
权值计算函数进行如下两部分主要部分:
1. 词组评分
2. 统计学评分
词组评分根据文档和查询的最长公共子串(LCS,longest common subsequence)的长度进行。
因此如果文档对查询词组有一个精确匹配(即文档直接包含该词组),那么它的词组评分就
取得了可能的最大值,也就是查询中词的个数。
统计学评分基于经典的BM25函数,该函数仅考虑词频。如果某词在整个数据库中很少见
(即文档集上的低频词)或者在某个特定文档中被经常提及(即特定文档上的高频词),那
么它就得到一个较高的权重。最终的BM25权值是一个0到1之间的浮点数。
在所有模式中,数据字段的词组评分是LCS乘以用户指定的数据字段权值。数据字段权值
是整数,默认为1,且字段的权值必须不小于1。
在SPH_MATCH_BOOLEAN模式中,不做任何权重估计,每一个匹配项的权重都是1。
在SPH_MATCH_ALL和SPH_MATCH_PHRASE模式中,最终的权值是词组评分的加权和。
在SPH_MATCH_ANY模式中,于前面述两模式的基本思想类似,只是每个数据字段的权重
都再加上一个匹配词数目。在那之前,带权的词组相关度被额外乘以一个足够大的数,以便
确保任何一个有较大词组评分的数据字段都会使整个匹配的相关度较高,即使该数据字段的
权重比较低。
在SPH_MATCH_EXTENDED模式中,最终的权值是带权的词组评分和BM25权重的和,再
乘以1000并四舍五入到整数。
这个行为将会被修改,以便使MATCH_ALL和MATCH_ANY这两个模式也能使用BM25算
法。这将使词组评分相同的搜索结果片断得到改进,这在只有一个词的查询中尤其有用。
关键的思想(对于除布尔模式以外的全部模式中)是子词组的匹配越好则评分越高,精确匹
配(匹配整个词组)评分最高。作者的经验是,这种基于词组相似性的评分方法可以提供比
任何单纯的统计模型(比如其他搜索引擎中广泛使用的BM25)明显更高的搜索质量。
5. 排序模式
可使用如下模式对搜索结果排序:
SPH_SORT_RELEVANCE 模式, 按相关度降序排列(最好的匹配排在最前面)
SPH_SORT_ATTR_DESC 模式, 按属性降序排列 (属性值越大的越是排在前面)
SPH_SORT_ATTR_ASC模式, 按属性升序排列(属性值越小的越是排在前面)
SPH_SORT_TIME_SEGMENTS 模式, 先按时间段(最近一小时/天/周/月)降序,再按
相关度降序
SPH_SORT_EXTENDED 模式, 按一种类似SQL的方式将列组合起来,升序或降序排
列。
SPH_SORT_EXPR 模式,按某个算术表达式排序。
SPH_SORT_RELEVANCE忽略任何附加的参数,永远按相关度评分排序。所有其余的模式
都要求额外的排序子句,子句的语法跟具体的模式有关。SPH_SORT_ATTR_ASC,
SPH_SORT_ATTR_DESC以及SPH_SORT_TIME_SEGMENTS这三个模式仅要求一个属性名。
SPH_SORT_RELEVANCE模式等价于在扩展模式中按”@weight DESC, @id ASC”排序,
SPH_SORT_ATTR_ASC 模式等价于”attribute ASC, @weight DESC, @id ASC”,而
SPH_SORT_ATTR_DESC 等价于”attribute DESC, @weight DESC, @id ASC”。
SPH_SORT_TIME_SEGMENTS模式
在SPH_SORT_TIME_SEGMENTS模式中,属性值被分割成“时间段”,然后先按时间段排
序,再按相关度排序。
时间段是根据搜索发生时的当前时间戳计算的,因此结果随时间而变化。所说的时间段有如
下这些值:
最近一小时
最近一天
最近一星期
最近一个月
最近三个月
其他值
时间段的分法固化在搜索程序中了,但如果需要,也可以比较容易地改变(需要修改源码)。
这种模式是为了方便对Blog日志和新闻提要等的搜索而增加的。使用这个模式时,处于更
近时间段的记录会排在前面,但是在同一时间段中的记录又根据相关度排序-这不同于单纯
按时间戳排序而不考虑相关度。
SPH_SORT_EXTENDED 模式
在 SPH_SORT_EXTENDED 模式中,您可以指定一个类似SQL的排序表达式,但涉及的属
性(包括内部属性)不能超过5个,例如:
@relevance DESC, price ASC, @id DESC
只要做了相关设置,不管是内部属性(引擎动态计算出来的那些属性)还是用户定义的属性
就都可以使用。内部属性的名字必须用特殊符号@开头,用户属性按原样使用就行了。在上
面的例子里,@relevance和@id是内部属性,而price是用户定义属性。
已知的内部属性:
@id (match ID)
@weight (match weight)
@rank (match weight)
@relevance (match weight)
@id(匹配的ID)
@weight(匹配权值)
@rank(匹配权值)
@relevance(匹配权值)
@rank和@relevance只是@weight的额外别名。
SPH_SORT_EXPR 模式
表达式排序模式使您可以对匹配项按任何算术表达式排序,表达式中的项可以是属性值,内
部属性(@id和@weight),算术运算符和一些内建的函数。例如:
$cl->SetSortMode ( SPH_SORT_EXPR,
“@weight + ( user_karma + ln(pageviews) )*0.1” );
支持的运算符和函数如下。它们是模仿MySQL设计的。函数接受参数,参数的数目根据具
体函数的不同而不同。
Operators: +, -, *, /, <, > <=, >=, =, <>.
Unary (1-argument) functions: abs(), ceil(), floor(), sin(), cos(), ln(), log2(), log10(), exp(),
sqrt().
Binary (2-argument) functions: min(), max(), pow().
Ternary (3-argument) functions: if().
运算符: +, -, *, /, <, > <=, >=, =, <>.
一元函数(一个参数):abs(), ceil(), floor(), sin(), cos(), ln(), log2(), log10(), exp(),
sqrt().
二元函数(两个参数):min(), max(), pow().
三元函数(三个参数):if().
全部的计算都以单精度32位IEEE754浮点数进行。比较操作符(比如=和<=)在条件为真
时返回1.0,否则返回0.0。例如(a=b)+3在属性“a”与属性“b”相等时返回4,否则返回
3。与MySQL不同,相等性比较符(即=和<>)中引入了一个小的阈值(默认是1e-6)。
如果被比较的两个值的差异在阈值之内,则二者被认为相等。
全部的一元和二元函数的意义都很明确,他们的行为跟在数学中的定义一样。但IF()的行为
需要点详细的解释。它接受3个参数,检查第一个参数是否为0.0,若非零则返回第二个参
数,为零时则返回第三个参数。注意,与比较操作符不同,IF()并不使用阈值!因此在第一
个参数中使用比较结果是安全的,但使用算术运算符则可能产生意料之外的结果。比如,下
面两个调用会产生不同的结果,虽然在逻辑上他们是等价的:
IF ( sqrt(3)*sqrt(3)-3<>0, a, b )
IF ( sqrt(3)*sqrt(3)-3, a, b )
在第一种情况下,由于有阈值,比较操作符<>返回0.0(逻辑假),于是IF()总是返回
‘b’。在第二种情况下,IF()函数亲自在没有阈值的情况下将同样的
sqrt(3)*sqrt(3)-3与零值做比较。但由于浮点数运算的精度问题,该表达式的结果与
0值会有微小的差异,因此该值与零值的相等比较不会通过,上述第二种情况中IF()会返
回‘a’做为结果。
6. 结果分组(聚类)
有时将搜索结果分组(或者说“聚类”)并对每组中的结果计数是很有用的-例如画个漂亮
的图来展示每个月有多少的blog日志,或者把Web搜索结果按站点分组,或者把找到的论
坛帖子按其作者分组。
理论上,这可以分两步实现:首先在Sphinx中做全文检索,再在SQL服务器端对得到的ID
分组。但是现实中在大结果集(10K到10M个匹配)上这样做通常会严重影响性能。
为避免上述问题,Sphinx提供了一种“分组模式”,可以用API调用SetGroupBy()来开启。
在分组时,根据group-by值给匹配项赋以一个分组。这个值用下列内建函数之一根据特定的
属性值计算:
SPH_GROUPBY_DAY,从时间戳中按YYYYMMDD格式抽取年、月、日
SPH_GROUPBY_WEEK,从时间戳中按YYYYNNN格式抽取年份和指定周数(自年
初计起)的第一天
SPH_GROUPBY_MONTH,从时间戳中按YYYYMM格式抽取月份
SPH_GROUPBY_YEAR,从时间戳中按YYYY格式抽取年份
SPH_GROUPBY_ATTR,使用属性值自身进行分组
最终的搜索结果中每组包含一个最佳匹配。分组函数值和每组的匹配数目分别以“虚拟”属
性@group和@count的形式返回。
结果集按group-by排序子句排序,语法与SPH_SORT_EXTENDED 排序子句的语法相似。除
了@id和@weight,分组排序子句还包括:
@group(groupby函数值)
@count(组中的匹配数目)
默认模式是根据groupby函数值降序排列,即按照“@group desc”
排序完成时,结果参数total_found会包含在整个索引上匹配的组的总数目。
注意:分组操作在固定的内存中执行,因此它给出的是近似结果;所以total_found报告的数
目可能比实际给出的个分组数目的和多。@count也可能被低估。要降低不准确性,应提高
max_matches。如果max_matches允许存储找到的全部分组,那结果就是百分之百准确的。
例如,如果按相关度排序,同时用SPH_GROUPBY_DAY函数按属性“published”分组,那
么:
结果中包含每天的匹配结果中最相关的那一个,如果那天有记录匹配的话。
结果中还附加给出天的编号和每天的匹配数目
结果以天的编号降序排列(即最近的日子在前面)
7. 分布式搜索
为提高可伸缩性,Sphnix提供了分布式检索能力。分布式检索可以改善查询延迟问题(即缩
短查询时间)和提高多服务器、多CPU或多核环境下的吞吐率(即每秒可以完成的查询
数)。这对于大量数据(即十亿级的记录数和TB级的文本量)上的搜索应用来说是很关键
的。
其关键思想是将待搜索数据做水平分区(HP,Horizontally partition),然后并行处理。
分区不能自动完成,您需要:
在不同服务器上设置Sphinx程序集(indexer和searchd)的多个实例
让这些实例对数据的不同部分做索引(并检索)
在searchd的一些实例上配置一个特殊的分布式索引
然后对这个索引进行查询
这个特殊索引只包括对其他本地或远程索引的引用,因此不能对它执行重新建立索引的操作,
相反,如果要对这个特殊索引进行重建,要重建的是那些被这个索引被引用到的索引。
当searchd收到一个对分布式索引的查询时,它做如下操作:
1. 连接到远程代理
2. 执行查询
3. (在远程代理执行搜索的同时)对本地索引进行查询
4. 接收来自远程代理的搜索结果
5. 将所有结果合并,删除重复项
6. 将合并后的结果返回给客户端
在应用程序看来,普通索引和分布式索引完全没有区别。
任一个searchd实例可以同时做为主控端(master,对搜索结果做聚合)和从属端(只做本地
搜索)。这有如下几点好处:
1. 集群中的每台机器都可以做为主控端来搜索整个集群,搜索请求可以在主控端之间获
得负载平衡,相当于实现了一种HA(high availability,高可用性),可以应对某个
节点失效的情况。
2. 如果在单台多CPU或多核机器上使用,一个做为代理对本机进行搜索的searchd实例
就可以利用到全部的CPU或者核。
更好的HA支持已在计划之中,到时将允许指定哪些代理之间互相备份、有效性检查、跟踪
运行中的代理、对检索请求进行负载均衡,等等。
8. searchd 日志格式
searchd将全部成功执行的搜索查询都记录在查询日志文件中。以下是一个类似记录文件的
例子:
[Fri Jun 29 21:17:58 2007] 0.004 sec [all/0/rel 35254 (0,20)] [lj] test
[Fri Jun 29 21:20:34 2007] 0.024 sec [all/0/rel 19886 (0,20) @channel_id] [lj]
test
日志格式如下
[query-date] query-time [match-mode/filters-count/sort-mode
total-matches (offset,limit) @groupby-attr] [index-name] query
匹配模式(match-mode)可以是如下值之一:
“all” 代表 SPH_MATCH_ALL 模式;
“any” 代表 SPH_MATCH_ANY 模式;
“phr” 代表 SPH_MATCH_PHRASE 模式;
“bool” 代表 SPH_MATCH_BOOLEAN 模式;
“ext” 代表 SPH_MATCH_EXTENDED 模式.
排序模式(sort-mode)可以取如下值之一:
“rel” 代表 SPH_SORT_RELEVANCE 模式;
“attr-” 代表 SPH_SORT_ATTR_DESC 模式;
“attr+” 代表 SPH_SORT_ATTR_ASC 模式;
“tsegs” 代表 SPH_SORT_TIME_SEGMENTS 模式;
“ext” 代表 SPH_SORT_EXTENDED 模式.
No Responses (yet)
Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.