好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

sphinx全文检索之PHP使用教程

这是半年前没有对外写的文章,现在拿出来分享下。可能会有一些不正确或不严谨的地方,某些语言可能比较轻浮,请见谅。 以上一篇的email数据表为例: 数据结构:

view source

 

print ?

01. CREATE   TABLE   email (

02. emailid mediumint(8) unsigned  NOT   NULL   auto_increment COMMENT  '邮件id' ,

03.  

04. fromid  int (10) unsigned  NOT   NULL   default   '0'   COMMENT  '发送人ID' ,

05.  

06. toid  int (10) unsigned  NOT   NULL   default   '0'   COMMENT  '收件人ID' ,

07. content text unsigned  NOT   NULL   COMMENT  '邮件内容' ,

08. subject  varchar (100) unsigned  NOT   NULL   COMMENT  '邮件标题' ,

09.  

10. sendtime  int (10)  NOT   NULL   COMMENT  '发送时间' ,

11.  

12. attachment  varchar (100)  NOT   NULL   COMMENT  '附件ID,以逗号分割' ,  PRIMARY   KEY   (emailid),

13. ) ENGINE=MyISAM';

使用打开控制台,必需打开控制台PHP才能连接到sphinx(确保你已经建立好索引源): d:\coreseek\bin\searchd -c d:\coreseek\bin\sphinx.conf coreseek/api目录下提供了PHP的接口文件 sphinxapi.php,这个文件包含一个SphinxClient的类 在PHP引入这个文件,new一下

view source

 

print ?

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   '

'; print_r($result); echo ' '; $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条件的用法

view source

 

print ?

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 模式,按某个算术表达式排序

view source

 

print ?

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( '关键字' ,  '*' );

//更多请查看官方文档排序模式的说明 匹配模式 有如下可选的匹配模式: 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的条件语句

view source

 

print ?

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()方法模拟一下

view source

 

print ?

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都能识别

view source

 

print ?

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

02.  

03.  

04.  

05. 然后PHP中可以使用SetFilter()

06.  

07. //搜索包含附件ID为1或2邮件,mysql语法是这样FIND_IN_SET(`attachment`, '1,2')

08.  

09. $sphinx ->SetFilter( 'attachment' ,  array (1,2))

10.  

11. //可以使用SetFilterRange,搜索包含附件ID在50-100范围的邮件

12.  

13. $sphinx ->SetFilterRange( 'attachment' , 50, 100)

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

查看更多关于sphinx全文检索之PHP使用教程的详细内容...

  阅读:35次