[关闭]
@a5635268 2015-08-20T20:29:48.000000Z 字数 5902 阅读 1405

【PHP高效搜索专题(2)】sphinx&coreseek在PHP程序中的应用实例

高效搜索 PHP性能优化


PHP可以通过三种途径来调用sphinx

通过php-sphinx扩展来链接

首推此方法

  1. cd coreseek-4.1/csft-4.1/api/libsphinxclient/
  2. ./configure --prefix=/usr/local/libsphinxclient
  3. make && make install
  4. # 处理configure报错
  5. # 编译过程中报了一个config.status: error: cannot find input file: src/Makefile.in这个的错误,然后运行下列指令再次编译就能通过了:
  6. # aclocal
  7. # libtoolize --force
  8. # automake --add-missing
  9. # autoconf
  10. # autoheader
  11. # make clean
  12. # 从新configure编译
  13. # ./configure
  14. # 下载http://pecl.php.net/package/sphinxapi
  15. # 解压进入
  16. /usr/bin/phpize #生成config
  17. ./configure --with-php-config=/usr/bin/php-config --with-sphinx=/usr/local/libsphinxclient
  18. make && make install
  19. #然后得到 Installing shared extensions: /usr/lib/php/modules/ 该目录就是php扩展所在的地方;
  20. vim /etc/php.ini #搜索 extension=,然后再其附近加上sphinx.so
  21. #重启Apache;在phpinfo()中找到sphinx就算成功;

Example1

  1. <?php
  2. $s = new SphinxClient;
  3. $s->setServer("127.0.0.1", 9312);
  4. $s->setMatchMode(SPH_MATCH_PHRASE);
  5. $s->setMaxQueryTime(30);
  6. $res = $s->query("简单",'main'); #[简单]关键字,[main]数据源source
  7. $err = $s->GetLastError();
  8. echo "<pre />";
  9. print_r(array_keys($res['matches'])); #关键字所属的ID集合;
  10. echo "<pre />";
  11. die;
  12. ?>

Example2

注意,下文中被注释掉的部分仅仅作为参考;

  1. <?php
  2. header("Content-type: text/html; charset=utf-8");
  3. $s = new SphinxClient();
  4. $s->setServer("127.0.0.1", 9312);
  5. $s->setMatchMode(SPH_MATCH_ANY);
  6. /*
  7. SPH_MATCH_ALL, 匹配所有查询词(默认模式);
  8. SPH_MATCH_ANY, 匹配查询词中的任意一个;
  9. SPH_MATCH_PHRASE, 将整个查询看作一个词组,要求按顺序完整匹配;
  10. SPH_MATCH_BOOLEAN, 将查询看作一个布尔表达式
  11. SPH_MATCH_EXTENDED, 将查询看作一个CoreSeek/Sphinx内部查询语言的表达式 . 从版本Coreseek 3/Sphinx 0.9.9开始, 这个选项被选项SPH_MATCH_EXTENDED2代替,它提供了更多功能和更佳的性能。保留这个选项是为了与遗留的旧代码兼容——这样即使Sphinx及其组件包括API升级的时候,旧的应用程序代码还能够继续工作。
  12. SPH_MATCH_EXTENDED2, 使用第二版的“扩展匹配模式”对查询进行匹配.
  13. SPH_MATCH_FULLSCAN, 强制使用下文所述的“完整扫描”模式来对查询进行匹配。注意,在此模式下,所有的查询词都被忽略,尽管过滤器、过滤器范围以及分组仍然起作用,但任何文本匹配都不会发生.
  14. 我们要关注的主要是SPH_MATCH_EXTENDED2扩展匹配模式,扩展匹配模式允许使用一些像mysql的条件语句
  15. //设置扩展匹配模式
  16. $sphinx->SetMatchMode ( "SPH_MATCH_EXTENDED2" );
  17. //查询中使用条件语句,字段用@开头,搜索内容包含测试,toid等于1的邮件:
  18. $result = $sphinx->query('@content (测试) & @toid =1', '*');
  19. //用括号和&(与)、|、(或者)、-(非,即!=)设置更复杂的条件
  20. $result = $sphinx->query('(@content (测试) & @subject =呃) | (@fromid -(100))', '*');
  21. //更多语法请查看官方文档匹配模式的说明
  22. */
  23. $s->setMaxQueryTime(10);//设置最大搜索时间
  24. $s->SetArrayResult(true);//设为true,那Matches的key就是一个从0开始的数组索引,设为false,那key就是数据的id值;
  25. $s->SetSelect ( "*" ); //设置返回信息的内容,等同于SQL
  26. // $s->SetRankingMode(SPH_RANK_BM25);//设置评分模式,SPH_RANK_BM25可能使包含多个词的查询的结果质量下降。
  27. //$s->SetSortMode(SPH_SORT_EXTENDED);
  28. //$s->SetSortMode(SPH_SORT_EXTENDED,"from_id asc,id desc"); //设置匹配项的排序模式, SPH_SORT_EXTENDED按一种类似SQL的方式将列组合起来,升序或降序排列。
  29. /*
  30. SPH_SORT_RELEVANCE 模式, 按相关度降序排列(最好的匹配排在最前面)
  31. SPH_SORT_ATTR_DESC 模式, 按属性降序排列 (属性值越大的越是排在前面)
  32. SPH_SORT_ATTR_ASC 模式, 按属性升序排列(属性值越小的越是排在前面)
  33. SPH_SORT_TIME_SEGMENTS 模式, 先按时间段(最近一小时/天/周/月)降序,再按相关度降序
  34. SPH_SORT_EXTENDED 模式, 按一种类似SQL的方式将列组合起来,升序或降序排列。
  35. SPH_SORT_EXPR 模式,按某个算术表达式排序
  36. */
  37. // $s -> SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid'); //以fromid倒序排序,注意当再次使用SetSortMode会覆盖上一个排序
  38. // $sphinx->SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid ASC, toid DESC, @id DESC'); //如果要使用多个字段排序可使用SPH_SORT_EXTENDED模式,@id是sphinx内置关键字,这里指emailid,至于为什么是emailid,自己思考一下
  39. // $weights = array ('company_name' => 20);
  40. // $s->SetFieldWeights($weights);//设置字段权重
  41. $s->SetLimits ( 0, 10, 1000);//SetLimits (偏移量,匹配项数目,查询的结果集数默认1000,阀值达到后停止),匹配结果的偏移量,参数的意义依次为:起始位置,返回结果条数,最大匹配条数
  42. //属性过滤,可过滤的属性必需在配置文件中设置sql_attr_ ,之前我们定义了这些
  43. // sql_attr_uint = 'fromid';
  44. // sql_attr_uint = 'toid';
  45. // sql_attr_timestamp = 'sendtime';
  46. //如果你想再次修改这些属性,配置完成后记得重新建立索引才能生效
  47. //指定一些值
  48. // $sphinx->SetFilter('fromid', array(1,2)); //fromid的值只能是1或者2
  49. //和以上条件相反,可增加第三个参数
  50. // $sphinx->SetFilter('fromid', array(1,2), false); //fromid的值不能是1或者2
  51. //指定一个值的范围
  52. // $sphinx->SetFilterRange('toid', 5, 200); //toid的值在5-200之间
  53. //和以上条件相反,可增加第三个参数
  54. // $sphinx->SetFilterRange('toid', 5, 200, false); //toid的值在5-200以外
  55. //$s->SetFilter ( $attribute, $values, $exclude=false ); //设置属性过滤
  56. //$s->SetGroupBy ( $attribute, $func, $groupsort="@group desc" );//设置分组的属性
  57. $keyword = '小杨生煎';
  58. $index = 'main'; //索引源是配置文件中的 index 类,如果有多个索引源可使用,号隔开:'email,diary' 或者使用'*'号代表全部索引源
  59. $res = $s->query($keyword,$index);
  60. echo "<pre />";
  61. print_r($res);
  62. echo "<pre />";
  63. die;
  64. $ids = implode(',',array_keys($res['matches']));
  65. $conn=@mysql_connect('localhost','root','')||die('数据库链接失败!');
  66. mysql_select_db('test');
  67. mysql_query('set names utf8');
  68. $sql = "select user_comment_id,user_recommend from data where user_comment_id in ({$ids})";
  69. $result = mysql_query($sql);
  70. $row = array();
  71. $i = 0;
  72. $opts = array(
  73. 'before_match' => "<font style='color:red;font-weight:bold;text-decoration:underline'>",
  74. 'after_match' => "</font>",
  75. "limit" => 100, //摘要最多包含的符号数,默认256
  76. "around" => 3, //每个关键词左右选取的词的数目,默认为5
  77. );
  78. while($f=mysql_fetch_assoc($result)){
  79. $f = $s->BuildExcerpts ($f, 'main', $keyword, $opts);//执行高亮,这里索引名字千万不能用*
  80. $row[$i]= $f;
  81. $i++;
  82. }
  83. echo "<pre />";
  84. print_r($row);
  85. echo "<pre />";
  86. die;
  87. ?>

通过官方提供的sphinxapi.php来链接

直接进解压后的包里面找到sphinxapi.php,然后引入到文件中,其它操作都同上.虽然Coreseek官方教程中建议php使用直接include一个php文件进行操作,事实上php有独立的sphinx模块可以直接操作coreseek(coreseek就是sphinx!)已经进入了php的官方函数库,而且效率的提升不是一点点!但php模块依赖于libsphinxclient包。见上文;

SphinxSE

SphinxSE是一个可以编译进MySQL 5.x版本的MySQL存储引擎,它利用了该版本MySQL的插件式体系结构。尽管被称作“存储引擎”,SphinxSE自身其实并不存储任何数据。它其实是一个允许MySQL服务器与searchd交互并获取搜索结果的嵌入式客户端。所有的索引和搜索都发生在MySQL之外。

SphinxSE的适用于:

要通过SphinxSE搜索,需要建立特殊的ENGINE=SPHINX的“搜索表”,然后使用SELECT语句从中检索,把全文查询放在WHERE子句中。

创建一张表t1

  1. CREATE TABLE t1
  2. (
  3. id INTEGER UNSIGNED NOT NULL,
  4. weight INTEGER NOT NULL,
  5. query VARCHAR(3072) NOT NULL,
  6. group_id INTEGER,
  7. INDEX(query)
  8. ) ENGINE=SPHINX CONNECTION="sphinx://localhost:9312/test1";

搜索表前三列的类型必须是INTEGER,INTEGER和VARCHAR,这三列分别对应文档ID,匹配权值和搜索查询。查询列必须被索引,其他列必须无索引。列的名字会被忽略,所以可以任意命名,参数CONNECTION来指定用这个表搜索时的默认搜索主机、端口号和索引,语法格式:CONNECTION="sphinx://HOST:PORT/INDEXNAME"。
执行SQL语句 select d.id,d.title,d.content from t1 join documents as d on t1.id = d.id and t1.query = '研究生创业';

  1. +----+--------------------+-----------------------+
  2. | id | title | content |
  3. +----+--------------------+-----------------------+
  4. | 5 | 研究生的故事 | 研究生自主创业 |
  5. +----+--------------------+-----------------------+
  6. 1 row in set (0.04 sec)

结果返回了我们想要的数据,可见利用SphinxSE可以仅仅在SQL语句上做很小的改动即可很方便的实现全文检索!
但是效率比起直接用官方的sphinx扩展模块来要远远不足。。。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注