sphinx 使用教程-挺简单易懂

时间:2022-04-12 08:34:04

使用打开控制台,必需打开控制台PHP才能连接到sphinx(确保你已经建立好索引源):

d:\coreseek\bin\searchd -c d:\coreseek\bin\sphinx.conf

 

coreseek/api目录下提供了PHP的接口文件 sphinxapi.php,这个文件包含一个SphinxClient的类

在PHP引入这个文件,new一下

01 $sphinx = new SphinxClient();
02  
03 //sphinx的主机名和端口
04  
05 $sphinx->SetServer ( 'loclahost', 9312 );
06  
07 //设置返回结果集为php数组格式
08  
09 $sphinx->SetArrayResult ( true );
10  
11 //匹配结果的偏移量,参数的意义依次为:起始位置,返回结果条数,最大匹配条数
12  
13 $sphinx->SetLimits(0, 20, 1000);
14  
15 //最大搜索时间
16  
17 $sphinx->SetMaxQueryTime(10);
18  
19  
20  
21 //执行简单的搜索,这个搜索将会查询所有字段的信息,要查询指定的字段请继续看下文
22  
23 $index = 'email' //索引源是配置文件中的 index 类,如果有多个索引源可使用,号隔开:'email,diary' 或者使用'*'号代表全部索引源
24  
25 $result = $sphinx->query ('搜索关键字', $index);
26  
27 echo '<pre>';
28  
29 print_r($result);
30  
31 echo '</pre>';

 

$result是一个数组,其中

total是匹配到的数据总数量

matches是匹配的数据,包含id,attrs这些信息

words是搜索关键字的分词

 

你可能奇怪为什么没有邮件的内容这些信息,其实sphinx并不会返回像MySQL那样的数据数组,因为sphinx本来就没有记录完整的数据,只记录被分词后的数据。

具体还要看matches数组,matches中的ID就是指配置文件中sql_query SELECT语句中的第一个字段,我们配置文件中是这样的

sql_query                = SELECT emailid,fromid,toid,subject,content,sendtime,attachement FROM email

所以matches中的ID是指emailid

至于weight是指匹配的权重,一般权重越高被返回的优先度也最高,匹配权重相关内容请参考官方文档

attrs是配置文件中sql_attr_    中的信息,稍后会提到这些属性的用法

 

说了这么多,即使搜索到结果也不是我们想要的email数据,但事实sphinx是不记录真实数据的,所以要获取到真实email数据还要根据matches中的ID去搜索mysql的email表,但总体来说这样一来一回的速度还是远远比mysql的LIKE快得多,前提是几十万数据量以上,否则用sphinx只会更慢。

 

接下来介绍sphinx一些类似mysql条件的用法

01 //emailid的范围
02  
03 $sphinx->SetIdRange($min, $max);
04  
05  
06  
07 //属性过滤,可过滤的属性必需在配置文件中设置sql_attr_    ,之前我们定义了这些
08  
09     sql_attr_uint            = fromid
10  
11     sql_attr_uint            = toid
12  
13     sql_attr_timestamp  = sendtime
14  
15 //如果你想再次修改这些属性,配置完成后记得重新建立索引才能生效
16  
17  
18  
19 //指定一些值
20  
21 $sphinx->SetFilter('fromid', array(1,2));    //fromid的值只能是1或者2
22  
23 //和以上条件相反,可增加第三个参数
24  
25 $sphinx->SetFilter('fromid', array(1,2), false);    //fromid的值不能是1或者2
26  
27 //指定一个值的范围
28  
29 $sphinx->SetFilterRange('toid', 5, 200);    //toid的值在5-200之间
30  
31 //和以上条件相反,可增加第三个参数
32  
33 $sphinx->SetFilterRange('toid', 5, 200, false);    //toid的值在5-200以外
34  
35  
36  
37 //执行搜索
38  
39 $result = $sphinx->query('关键字', '*');

 

 

排序模式

可使用如下模式对搜索结果排序:

SPH_SORT_RELEVANCE 模式, 按相关度降序排列(最好的匹配排在最前面)

SPH_SORT_ATTR_DESC 模式, 按属性降序排列 (属性值越大的越是排在前面)

SPH_SORT_ATTR_ASC 模式, 按属性升序排列(属性值越小的越是排在前面)

SPH_SORT_TIME_SEGMENTS 模式, 先按时间段(最近一小时/天/周/月)降序,再按相关度降序

SPH_SORT_EXTENDED 模式, 按一种类似SQL的方式将列组合起来,升序或降序排列。

SPH_SORT_EXPR 模式,按某个算术表达式排序

01 //使用属性排序
02  
03 //以fromid倒序排序,注意当再次使用SetSortMode会覆盖上一个排序
04  
05 $sphinx->SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid');
06  
07 //如果要使用多个字段排序可使用SPH_SORT_EXTENDED模式
08  
09 //@id是sphinx内置关键字,这里指emailid,至于为什么是emailid,自己思考一下
10  
11 $sphinx->SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid ASC, toid DESC, @id DESC');
12  
13 //执行搜索
14  
15 $result = $sphinx->query('关键字', '*');
16  
17 //更多请查看官方文档排序模式的说明

 

 

匹配模式

有如下可选的匹配模式:

SPH_MATCH_ALL, 匹配所有查询词(默认模式);

SPH_MATCH_ANY, 匹配查询词中的任意一个;

SPH_MATCH_PHRASE, 将整个查询看作一个词组,要求按顺序完整匹配;

SPH_MATCH_BOOLEAN, 将查询看作一个布尔表达式 

SPH_MATCH_EXTENDED, 将查询看作一个CoreSeek/Sphinx内部查询语言的表达式 . 从版本Coreseek 3/Sphinx 0.9.9开始, 这个选项被选项SPH_MATCH_EXTENDED2代替,它提供了更多功能和更佳的性能。保留这个选项是为了与遗留的旧代码兼容——这样即使Sphinx及其组件包括API升级的时候,旧的应用程序代码还能够继续工作。

SPH_MATCH_EXTENDED2, 使用第二版的“扩展匹配模式”对查询进行匹配.

SPH_MATCH_FULLSCAN, 强制使用下文所述的“完整扫描”模式来对查询进行匹配。注意,在此模式下,所有的查询词都被忽略,尽管过滤器、过滤器范围以及分组仍然起作用,但任何文本匹配都不会发生.

我们要关注的主要是SPH_MATCH_EXTENDED2扩展匹配模式,扩展匹配模式允许使用一些像mysql的条件语句

01 //设置扩展匹配模式
02  
03 $sphinx->SetMatchMode ( "SPH_MATCH_EXTENDED2" );
04  
05 //查询中使用条件语句,字段用@开头,搜索内容包含测试,toid等于1的邮件:
06  
07 $result = $sphinx->query('@content (测试) & @toid =1', '*');
08  
09 //用括号和&(与)、|、(或者)、-(非,即!=)设置更复杂的条件
10  
11 $result = $sphinx->query('(@content (测试) & @subject =呃) | (@fromid -(100))', '*');
12  
13 //更多语法请查看官方文档匹配模式的说明

 

扩展匹配模式中值得一提的是搜索的字段,如果该字段被设置属性,那么扩展匹配搜索的字段默认是不包含这些属性的,只能用SetFilter()或者SetFilterRange()之类

之前我们设置了fromid、toid、sendtime为属性,但又想在扩展匹配模式中又想用作条件该怎么办?

只要在sql_query语句中再选择多一次该字段就可以了

sql_query                = SELECT emailid,fromid,fromid,toid,toid,subject,content,sendtime,sendtime,attachement FROM email

//设置完成记得重新建立索引

 

 

更多条件技巧

只是一些技巧,但不建议使用的部署环境中,至于为什么,请看文章结尾

 

<、<=、>、>=

默认sphinx没有这些比较符。

假如我想邮件的发送时间大于某一日期怎么办?用SetFilterRange()方法模拟一下

 

01 //大于等于某一时间截$time
02  
03 $sphinx->SetFilterRange('sendtime', $time, 10000000000) //时间截最大是10个9,再加1是不可超越了。。
04  
05  
06  
07 //大于某一时间截$time
08  
09 $sphinx->SetFilterRange('sendtime', $time+1, 10000000000)
10  
11 //小于等于某一时间截$time
12  
13 $sphinx->SetFilterRange('sendtime', -1, $time)    //时间截最小是0,所以应该减1
14  
15 //大于某一时间截$time
16  
17 $sphinx->SetFilterRange('sendtime', -1, $time - 1)

 

IS NOT NULL

怎样搜索为空的字段,比如我要搜索附件为空的邮件,有人可能会想 @attachment ('')不就可以了吗?其实这是搜索两个单引号。。。sphinx搜索的字符串不用加引号的

目前sphinx是没有提供这样的功能,其实可以在mysql语句上作手脚:

sql_query                = SELECT emailid,fromid,toidsubject,content,sendtime,attachement != '' as attach is not null FROM email //这里返回了一个新字段attachisnotnull,当attachisnotnull为1的时候附件就不为空了

//设置完成记得重新建立索引

 

FIND_IN_SET()

搜索包含某一附件的邮件,mysql习惯用FIND_IN_SET这么简单一句就搞定了,在sphinx中必需在配置里设置属性sql_attr_multi 多值属性(MVA):

sql_attr_multi    = attachment    #attachment可以是逗号分隔的附件ID,或者是空格、分号等sphinx都能识别

//设置完成记得重新建立索引

 

然后PHP中可以使用SetFilter()

1 //搜索包含附件ID为1或2邮件,mysql语法是这样FIND_IN_SET(`attachment`, '1,2')
2  
3 $sphinx->SetFilter('attachment', array(1,2))
4  
5 //可以使用SetFilterRange,搜索包含附件ID在50-100范围的邮件
6  
7 $sphinx->SetFilterRange('attachment', 50, 100)

 

 

总结

如果你想一个免费、好用、极速的全文搜索引擎,sphinx无疑是最好的选择,但是不要忘记sphinx的目的:全文检索。不要去想那些乱七八糟条件。你想要把sphinx搜索变得像mysql那样灵活,可完全单独用在一些复杂的多条件搜索,像某些邮件的高级搜索,那么我建议你还是多花点时间在PHP或者mysql代码的优化上,因为那样可能会让你的搜索变得更慢。

最好的方法是以最简单的方法搜索到内容,将ID交还mysql数据库搜索。


大家都知道sphinx自带的一些匹配模式。主要有

setMatchMode: SPH_MATCH_ALL匹配所有查询词(默认模式) SPH_MATCH_ANY匹配查询词中的任意一个 SPH_MATCH_PHRASE将整个查询看作一个词组,要求按顺序完整匹配 SPH_MATCH_BOOLEAN将查询看作一个布尔表达式 SPH_MATCH_EXTENDED将查询看作一个Sphinx内部查询语言的表达式 SPH_MATCH_FULLSCAN使用完全扫描,忽略查询词汇 SPH_MATCH_EXTENDED2类似 SPH_MATCH_EXTENDED ,并支持评分和权重.
通常我们想搜索到尽可能多的一句话中的内容,使用的是SPH_MATCH_ANY,但使用它之后,任何关键词中的字都可能做为一个单独的词进行搜索。这样语义不合适。而且这种匹配模式对词频也很有权重,个人感觉得出来的搜索结果不是很准确。 今天介绍的是SPH_MATCH_EXTENDED2,使用过的朋友可能觉得它也要搜索的关键词同时存在才会被搜索出来。是因为SPHINX默认不是通过空格分词的。而是通过""来分。比如两个关键词:我们 他是。如果单这样写 $sphinx->query('我们 他是',index);使用any模式会折成 我 们 他 是  。似乎是一元分词法。而使用extended2则要搜索的字段同时存在这2个词才可以被搜索到。如果写成   $sphinx->query('"我们"|"他是"',index);那么他就会分成我们和他是2个词。而且同时存在的权重高。比较符合搜索规范。
php中sphinx的使用进行了详细的分析介绍,需要的朋友参考下

<?php
//参数筛选

//筛选cat_id=2
$cl->SetFilter("cat_id",array(2));
//仅在id为1、3、7的子论坛中搜索
$cl->SetFilter("forum_id",array(1,3,7));

//范围筛选
//筛选发布时间为今天,参数为int时间戳
$cl->SetFilterRange("starttime",123,124);
//筛选价格
$cl->SetFilterRange("price",10.0,99.9);

// 分组
//按照item_id分组,并且按照order desc排序
$cl->SetGroupBy("item_id",SPH_GROUP_ATTR,"order desc");

//排序模式
//按照price desc排序
$cl->SetSortMode(SPH_SORT_ATTR_DESC,"price");
 注意:会被SetGroupBy中的排序覆盖

// 匹配查询词中的任意一个
$cl->SetMatchMode ( SPH_MATCH_ANY );
SPH_MATCH_ALL, 匹配所有查询词(默认模式);
SPH_MATCH_ANY, 匹配查询词中的任意一个;
SPH_MATCH_PHRASE, 将整个查询看作一个词组,要求按顺序完整匹配;
SPH_MATCH_BOOLEAN, 将查询看作一个布尔表达式 (参见 第 5.2 节 “布尔查询语法”);
SPH_MATCH_EXTENDED, 将查询看作一个CoreSeek/Sphinx内部查询语言的表达式 (参见 第 5.3 节 “扩展查询语法”). 从版本Coreseek 3/Sphinx 0.9.9开始, 这个选项被选项SPH_MATCH_EXTENDED2代替,它提供了更多功能和更佳的性能。保留这个选项是为了与遗留的旧代码兼容——这样即使 Sphinx及其组件包括API升级的时候,旧的应用程序代码还能够继续工作。
SPH_MATCH_EXTENDED2, 使用第二版的“扩展匹配模式”对查询进行匹配.
SPH_MATCH_FULLSCAN, 强制使用下文所述的“完整扫描”模式来对查询进行匹配。注意,在此模式下,所有的查询词都被忽略,尽管过滤器、过滤器范围以及分组仍然起作用,但任何文本匹配都不会发生.

//从0开始查询,查询30条,返回结果最多为1000
$cl->setLimits(0,30,1000);

// 从名称为index的sphinx索引查询“电影票”
$cl->Query("电影票","index");

// 从名称为index的sphinx索引查询“电影票”
$sp->SetGroupBy('item_id',SPH_GROUP_ATTR,'s_order desc');
$sp->SetFilter('city_id','1');
$sp->SetFilter('cat_id',array(1));
$sp->SetLimit(0,10,1000);
$sp->AddQuery('电影票','index');
$sp->ResetFilters();//重置筛选条件
$sp->ResetGroupBy();//重置分组

$sp->SetGroupBy('item_id', SPH_GROUPBY_ATTR, 's_order desc');
$sp->setFilter('city_id', '2');
$sp->setFilter('cat_id', array(2));
$sp->setLimits(0, 20, 1000);
$sp->AddQuery('温泉', 'index');
$sp->ResetFilters();// 重置筛选条件
$sp->ResetGroupBy();//重置分组
$results = $sp->RunQuries();
批量查询(或多查询)使searchd能够进行可能的内部优化,并且无论在任何情况下都会减少网络连接和进程创建方面的开销。相对于单独的查询,批量查询不会引入任何额外的开销。因此当您的Web页运行几个不同的查询时,一定要考虑使用批量查询。
例如,多次运行同一个全文查询,但使用不同的排序或分组设置,这会使searchd仅运行一次开销昂贵的全文检索和相关度计算,然后在此基础上产生多个分组结果。
有时您不仅需要简单地显示搜索结果,而且要显示一些与类别相关的计数信息,例如按制造商分组后的产品数目,此时批量查询会节约大量的开销。 若无批量查询,您会必须将这些本质上几乎相同的查询运行多次并取回相同的匹配项,最后产生不同的结果集。若使用批量查询,您只须将这些查询简单地组成一个 批量查询,Sphinx会在内部优化掉这些冗余的全文搜索。
AddQuery()在内部存储全部当前设置状态以及查询,您也可在后续的AddQuery()调用中改变设置。早先加入的查询不会被影响,实际上没有任何办法可以改变它们。

用上述代码,第一个查询会在“documents”索引上查询“hello world”并将结果按相关度排序,第二个查询会在“products”索引上查询“ipod”并将结果按价格排序,第三个查询在“books”索引上搜 索“harry potter”,结果仍按价格排序。注意,第二个SetSortMode()调用并不会影响第一个查询(因为它已经被添加了),但后面的两个查询都会受影 响。
此外,在AddQuery()之前设置的任何过滤,都会被后续查询继续使用。因此,如果在第一个查询前使用SetFilter(),则通过 AddQuery()执行的第二个查询(以及随后的批量查询)都会应用同样的过滤,除非你先调用ResetFilters()来清除过滤规则。同时,你还 可以随时加入新的过滤规则
AddQuery()并不修改当前状态。也就是说,已有的全部排序、过滤和分组设置都不会因这个调用而发生改变,因此后续的查询很容易地复用现有设置。
AddQuery()返回RunQueries()结果返回的数组中的一个下标。它是一个从0开始的递增整数,即,第一次调用返回0,第二次返回1,以此类推。这个方便的特性使你在需要这些下标的时候不用手工记录它们。
?>