他山之石-sphinx全文检索之PHP使用教程
2015-12-23 21:57
573 查看
数据表:
CREATETABLEemail(
emailidmediumint(8)unsignedNOTNULLauto_incrementCOMMENT'邮件id',
fromidint(10)unsignedNOTNULLdefault'0'COMMENT'发送人ID',
toidint(10)unsignedNOTNULLdefault'0'COMMENT'收件人ID',
contenttextunsignedNOTNULLCOMMENT'邮件内容',
subjectvarchar(100)unsignedNOTNULLCOMMENT'邮件标题',
sendtimeint(10)NOTNULLCOMMENT'发送时间',
attachmentvarchar(100)NOTNULLCOMMENT'附件ID,以逗号分割',PRIMARYKEY(emailid),
)ENGINE=MyISAM';使用打开控制台,必需打开控制台PHP才能连接到sphinx(确保你已经建立好索引源):
d:\coreseek\bin\searchd-cd:\coreseek\bin\sphinx.conf
coreseek/api目录下提供了PHP的接口文件sphinxapi.php,这个文件包含一个SphinxClient的类
在PHP引入这个文件,new一下
$sphinx=newSphinxClient();
//sphinx的主机名和端口
$sphinx->SetServer('loclahost',9312);
//设置返回结果集为php数组格式
$sphinx->SetArrayResult(true);
//匹配结果的偏移量,参数的意义依次为:起始位置,返回结果条数,最大匹配条数
$sphinx->SetLimits(0,20,1000);
//最大搜索时间
$sphinx->SetMaxQueryTime(10);
//执行简单的搜索,这个搜索将会查询所有字段的信息,要查询指定的字段请继续看下文
$index='email'//索引源是配置文件中的index类,如果有多个索引源可使用,号隔开:'email,diary'或者使用'*'号代表全部索引源
$result=$sphinx->query('搜索关键字',$index);
echo'';
print_r($result);
echo'';
$result是一个数组,其中
total是匹配到的数据总数量
matches是匹配的数据,包含id,attrs这些信息
words是搜索关键字的分词
你可能奇怪为什么没有邮件的内容这些信息,其实sphinx并不会返回像mysql那样的数据数组,因为sphinx本来就没有记录完整的数据,只记录被分词后的数据。
具体还要看matches数组,matches中的ID就是指配置文件中sql_querySELECT语句中的第一个字段,我们配置文件中是这样的
sql_query=SELECTemailid,fromid,toid,subject,content,sendtime,attachementFROMemail
所以matches中的ID是指emailid
至于weight是指匹配的权重,一般权重越高被返回的优先度也最高,匹配权重相关内容请参考官方文档
attrs是配置文件中sql_attr_中的信息,稍后会提到这些属性的用法
说了这么多,即使搜索到结果也不是我们想要的email数据,但事实sphinx是不记录真实数据的,所以要获取到真实email数据还要根据matches中的ID去搜索mysql的email表,但总体来说这样一来一回的速度还是远远比mysql的LIKE快得多,前提是几十万数据量以上,否则用sphinx只会更慢。
接下来介绍sphinx一些类似mysql条件的用法
//emailid的范围
$sphinx->SetIdRange($min,$max);
//属性过滤,可过滤的属性必需在配置文件中设置sql_attr_,之前我们定义了这些
sql_attr_uint=fromid
sql_attr_uint=toid
sql_attr_timestamp=sendtime
//如果你想再次修改这些属性,配置完成后记得重新建立索引才能生效
//指定一些值
$sphinx->SetFilter('fromid',array(1,2));//fromid的值只能是1或者2
//和以上条件相反,可增加第三个参数
$sphinx->SetFilter('fromid',array(1,2),false);//fromid的值不能是1或者2
//指定一个值的范围
$sphinx->SetFilterRange('toid',5,200);//toid的值在5-200之间
//和以上条件相反,可增加第三个参数
$sphinx->SetFilterRange('toid',5,200,false);//toid的值在5-200以外
//执行搜索
$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模式,按某个算术表达式排序
//使用属性排序
//以fromid倒序排序,注意当再次使用SetSortMode会覆盖上一个排序
$sphinx->SetSortMode("SPH_SORT_ATTR_DESC",'fromid');
//如果要使用多个字段排序可使用SPH_SORT_EXTENDED模式
//@id是sphinx内置关键字,这里指emailid,至于为什么是emailid,自己思考一下
$sphinx->SetSortMode("SPH_SORT_ATTR_DESC",'fromidASC,toidDESC,@idDESC');
//执行搜索
$result=$sphinx->query('关键字','*');
//更多请查看官方文档排序模式的说明
匹配模式
有如下可选的匹配模式:
SPH_MATCH_ALL,匹配所有查询词(默认模式);
SPH_MATCH_ANY,匹配查询词中的任意一个;
SPH_MATCH_PHRASE,将整个查询看作一个词组,要求按顺序完整匹配;
SPH_MATCH_BOOLEAN,将查询看作一个布尔表达式
SPH_MATCH_EXTENDED,将查询看作一个CoreSeek/Sphinx内部查询语言的表达式.从版本Coreseek3/Sphinx0.9.9开始,这个选项被选项SPH_MATCH_EXTENDED2代替,它提供了更多功能和更佳的性能。保留这个选项是为了与遗留的旧代码兼容——这样即使Sphinx及其组件包括API升级的时候,旧的应用程序代码还能够继续工作。
SPH_MATCH_EXTENDED2,使用第二版的“扩展匹配模式”对查询进行匹配.
SPH_MATCH_FULLSCAN,强制使用下文所述的“完整扫描”模式来对查询进行匹配。注意,在此模式下,所有的查询词都被忽略,尽管过滤器、过滤器范围以及分组仍然起作用,但任何文本匹配都不会发生.
我们要关注的主要是SPH_MATCH_EXTENDED2扩展匹配模式,扩展匹配模式允许使用一些像mysql的条件语句
//设置扩展匹配模式
$sphinx->SetMatchMode("SPH_MATCH_EXTENDED2");
//查询中使用条件语句,字段用@开头,搜索内容包含测试,toid等于1的邮件:
$result=$sphinx->query('@content(测试)&@toid=1','*');
//用括号和&(与)、|、(或者)、-(非,即!=)设置更复杂的条件
$result=$sphinx->query('(@content(测试)&@subject=呃)|(@fromid-(100))','*');
//更多语法请查看官方文档匹配模式的说明
扩展匹配模式中值得一提的是搜索的字段,如果该字段被设置属性,那么扩展匹配搜索的字段默认是不包含这些属性的,只能用SetFilter()或者SetFilterRange()之类
之前我们设置了fromid、toid、sendtime为属性,但又想在扩展匹配模式中又想用作条件该怎么办?
只要在sql_query语句中再选择多一次该字段就可以了
sql_query=SELECTemailid,fromid,fromid,toid,toid,subject,content,sendtime,sendtime,attachementFROMemail
//设置完成记得重新建立索引
更多条件技巧
只是一些技巧,但不建议使用的部署环境中,至于为什么,请看文章结尾
<、<=、>、>=
默认sphinx没有这些比较符。
假如我想邮件的发送时间大于某一日期怎么办?用SetFilterRange()方法模拟一下
//大于等于某一时间截$time
$sphinx->SetFilterRange('sendtime',$time,10000000000)//时间截最大是10个9,再加1是不可超越了。。
//大于某一时间截$time
$sphinx->SetFilterRange('sendtime',$time+1,10000000000)
//小于等于某一时间截$time
$sphinx->SetFilterRange('sendtime',-1,$time)//时间截最小是0,所以应该减1
//大于某一时间截$time
$sphinx->SetFilterRange('sendtime',-1,$time-1)
ISNOTNULL
怎样搜索为空的字段,比如我要搜索附件为空的邮件,有人可能会想@attachment('')不就可以了吗?其实这是搜索两个单引号。。。sphinx搜索的字符串不用加引号的
目前sphinx是没有提供这样的功能,其实可以在mysql语句上作手脚:
sql_query=SELECTemailid,fromid,toidsubject,content,sendtime,attachement!=''asattachisnotnullFROMemail//这里返回了一个新字段attachisnotnull,当attachisnotnull为1的时候附件就不为空了
//设置完成记得重新建立索引
FIND_IN_SET()
搜索包含某一附件的邮件,mysql习惯用FIND_IN_SET这么简单一句就搞定了,在sphinx中必需在配置里设置属性sql_attr_multi多值属性(MVA):
sql_attr_multi=attachment#attachment可以是逗号分隔的附件ID,或者是空格、分号等sphinx都能识别
//设置完成记得重新建立索引
然后PHP中可以使用SetFilter()
//搜索包含附件ID为1或2邮件,mysql语法是这样FIND_IN_SET(`attachment`,'1,2')
$sphinx->SetFilter('attachment',array(1,2))
//可以使用SetFilterRange,搜索包含附件ID在50-100范围的邮件
$sphinx->SetFilterRange('attachment',50,100)
总结
如果你想一个免费、好用、极速的全文搜索引擎,sphinx无疑是最好的选择,但是不要忘记sphinx的目的:全文检索。不要去想那些乱七八糟条件。你想要把sphinx搜索变得像mysql那样灵活,可完全单独用在一些复杂的多条件搜索,像某些邮件的高级搜索,那么我建议你还是多花点时间在PHP或者mysql代码的优化上,因为那样可能会让你的搜索变得更慢。
最好的方法是以最简单的方法搜索到内容,将ID交还mysql数据库搜索。
原文:[code]http://www.php100.com/html/php/lei/2013/0916/6188.html
d:\coreseek\bin\searchd-cd:\coreseek\bin\sphinx.conf
coreseek/api目录下提供了PHP的接口文件sphinxapi.php,这个文件包含一个SphinxClient的类
在PHP引入这个文件,new一下
$result是一个数组,其中
total是匹配到的数据总数量
matches是匹配的数据,包含id,attrs这些信息
words是搜索关键字的分词
你可能奇怪为什么没有邮件的内容这些信息,其实sphinx并不会返回像mysql那样的数据数组,因为sphinx本来就没有记录完整的数据,只记录被分词后的数据。
具体还要看matches数组,matches中的ID就是指配置文件中sql_querySELECT语句中的第一个字段,我们配置文件中是这样的
sql_query=SELECTemailid,fromid,toid,subject,content,sendtime,attachementFROMemail
所以matches中的ID是指emailid
至于weight是指匹配的权重,一般权重越高被返回的优先度也最高,匹配权重相关内容请参考官方文档
attrs是配置文件中sql_attr_中的信息,稍后会提到这些属性的用法
说了这么多,即使搜索到结果也不是我们想要的email数据,但事实sphinx是不记录真实数据的,所以要获取到真实email数据还要根据matches中的ID去搜索mysql的email表,但总体来说这样一来一回的速度还是远远比mysql的LIKE快得多,前提是几十万数据量以上,否则用sphinx只会更慢。
接下来介绍sphinx一些类似mysql条件的用法
排序模式
可使用如下模式对搜索结果排序:
SPH_SORT_RELEVANCE模式,按相关度降序排列(最好的匹配排在最前面)
SPH_SORT_ATTR_DESC模式,按属性降序排列(属性值越大的越是排在前面)
SPH_SORT_ATTR_ASC模式,按属性升序排列(属性值越小的越是排在前面)
SPH_SORT_TIME_SEGMENTS模式,先按时间段(最近一小时/天/周/月)降序,再按相关度降序
SPH_SORT_EXTENDED模式,按一种类似SQL的方式将列组合起来,升序或降序排列。
SPH_SORT_EXPR模式,按某个算术表达式排序
//更多请查看官方文档排序模式的说明
匹配模式
有如下可选的匹配模式:
SPH_MATCH_ALL,匹配所有查询词(默认模式);
SPH_MATCH_ANY,匹配查询词中的任意一个;
SPH_MATCH_PHRASE,将整个查询看作一个词组,要求按顺序完整匹配;
SPH_MATCH_BOOLEAN,将查询看作一个布尔表达式
SPH_MATCH_EXTENDED,将查询看作一个CoreSeek/Sphinx内部查询语言的表达式.从版本Coreseek3/Sphinx0.9.9开始,这个选项被选项SPH_MATCH_EXTENDED2代替,它提供了更多功能和更佳的性能。保留这个选项是为了与遗留的旧代码兼容——这样即使Sphinx及其组件包括API升级的时候,旧的应用程序代码还能够继续工作。
SPH_MATCH_EXTENDED2,使用第二版的“扩展匹配模式”对查询进行匹配.
SPH_MATCH_FULLSCAN,强制使用下文所述的“完整扫描”模式来对查询进行匹配。注意,在此模式下,所有的查询词都被忽略,尽管过滤器、过滤器范围以及分组仍然起作用,但任何文本匹配都不会发生.
我们要关注的主要是SPH_MATCH_EXTENDED2扩展匹配模式,扩展匹配模式允许使用一些像mysql的条件语句
扩展匹配模式中值得一提的是搜索的字段,如果该字段被设置属性,那么扩展匹配搜索的字段默认是不包含这些属性的,只能用SetFilter()或者SetFilterRange()之类
之前我们设置了fromid、toid、sendtime为属性,但又想在扩展匹配模式中又想用作条件该怎么办?
只要在sql_query语句中再选择多一次该字段就可以了
sql_query=SELECTemailid,fromid,fromid,toid,toid,subject,content,sendtime,sendtime,attachementFROMemail
//设置完成记得重新建立索引
更多条件技巧
只是一些技巧,但不建议使用的部署环境中,至于为什么,请看文章结尾
<、<=、>、>=
默认sphinx没有这些比较符。
假如我想邮件的发送时间大于某一日期怎么办?用SetFilterRange()方法模拟一下
ISNOTNULL
怎样搜索为空的字段,比如我要搜索附件为空的邮件,有人可能会想@attachment('')不就可以了吗?其实这是搜索两个单引号。。。sphinx搜索的字符串不用加引号的
目前sphinx是没有提供这样的功能,其实可以在mysql语句上作手脚:
sql_query=SELECTemailid,fromid,toidsubject,content,sendtime,attachement!=''asattachisnotnullFROMemail//这里返回了一个新字段attachisnotnull,当attachisnotnull为1的时候附件就不为空了
//设置完成记得重新建立索引
FIND_IN_SET()
搜索包含某一附件的邮件,mysql习惯用FIND_IN_SET这么简单一句就搞定了,在sphinx中必需在配置里设置属性sql_attr_multi多值属性(MVA):
sql_attr_multi=attachment#attachment可以是逗号分隔的附件ID,或者是空格、分号等sphinx都能识别
总结
如果你想一个免费、好用、极速的全文搜索引擎,sphinx无疑是最好的选择,但是不要忘记sphinx的目的:全文检索。不要去想那些乱七八糟条件。你想要把sphinx搜索变得像mysql那样灵活,可完全单独用在一些复杂的多条件搜索,像某些邮件的高级搜索,那么我建议你还是多花点时间在PHP或者mysql代码的优化上,因为那样可能会让你的搜索变得更慢。
最好的方法是以最简单的方法搜索到内容,将ID交还mysql数据库搜索。
相关文章推荐
- thinkphp中使用ajax实现无刷新分页
- php json 格式控制
- php rewrite模式
- PHP、JS间json数据的处理
- NTP方式保证以时间戳同步可靠性
- PHP中逻辑运算符and/or与||/&&的一个坑
- PHP单元测试利器:PHPUNIT初探
- php学习笔记---字符串操作
- PHP学习练手(五)
- 关于php编译安装configure 的一些参数详解
- php中工厂方法的两个特殊例子
- 给php开启mysql扩展
- phpStudy报错
- php【基础学习三】json
- php【基础学习二】File
- php【基础练习一】DB
- php解密java的DES加密
- ZendGuardLoader安装
- 【PHP】数组foreach引发的小问题
- iOS 推送证书上传(JAVA/PHP)