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

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

  • 通过Sphinx官方提供的API接口(接口有Python,Java,Php三种版本)
  • 通过安装SphinxSE,然后创建一个中介sphinxSE类型的表,再通过PHP执行,采用sphinxSE必须要求为mySQL安装sphinxSE Engine驱动行特定的SQL语句实现
  • 使用libsphinxclient+php的sphinx扩展 代替 sphinxapi (等同于第一种方案)

通过php-sphinx扩展来链接

首推此方法

cd coreseek-4.1/csft-4.1/api/libsphinxclient/
./configure --prefix=/usr/local/libsphinxclient
make && make install

# 处理configure报错  
# 编译过程中报了一个config.status: error: cannot find input file: src/Makefile.in这个的错误,然后运行下列指令再次编译就能通过了: 
# aclocal  
# libtoolize --force  
# automake --add-missing  
# autoconf  
# autoheader  
# make clean  
  
# 从新configure编译  
# ./configure  

# 下载http://pecl.php.net/package/sphinxapi
# 解压进入
/usr/bin/phpize #生成config
./configure --with-php-config=/usr/bin/php-config --with-sphinx=/usr/local/libsphinxclient
make && make install

#然后得到 Installing shared extensions:     /usr/lib/php/modules/ 该目录就是php扩展所在的地方;
vim /etc/php.ini #搜索 extension=,然后再其附近加上sphinx.so
#重启Apache;在phpinfo()中找到sphinx就算成功;

Example1

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

Example2

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

<?php 
header("Content-type: text/html; charset=utf-8");  
$s = new SphinxClient();  
$s->setServer("127.0.0.1", 9312);  
  
$s->setMatchMode(SPH_MATCH_ANY);
/*
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的条件语句

//设置扩展匹配模式

$sphinx->SetMatchMode ( "SPH_MATCH_EXTENDED2" );

//查询中使用条件语句,字段用@开头,搜索内容包含测试,toid等于1的邮件:

$result = $sphinx->query('@content (测试) & @toid =1', '*');

//用括号和&(与)、|、(或者)、-(非,即!=)设置更复杂的条件

$result = $sphinx->query('(@content (测试) & @subject =呃) | (@fromid -(100))', '*');

//更多语法请查看官方文档匹配模式的说明
 */


$s->setMaxQueryTime(10);//设置最大搜索时间  

$s->SetArrayResult(true);//设为true,那Matches的key就是一个从0开始的数组索引,设为false,那key就是数据的id值;

$s->SetSelect ( "*" ); //设置返回信息的内容,等同于SQL 

// $s->SetRankingMode(SPH_RANK_BM25);//设置评分模式,SPH_RANK_BM25可能使包含多个词的查询的结果质量下降。

//$s->SetSortMode(SPH_SORT_EXTENDED);
//$s->SetSortMode(SPH_SORT_EXTENDED,"from_id asc,id desc");      //设置匹配项的排序模式, SPH_SORT_EXTENDED按一种类似SQL的方式将列组合起来,升序或降序排列。  
/*
 SPH_SORT_RELEVANCE 模式, 按相关度降序排列(最好的匹配排在最前面)

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

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

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

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

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

// $s -> SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid'); //以fromid倒序排序,注意当再次使用SetSortMode会覆盖上一个排序

// $sphinx->SetSortMode ( "SPH_SORT_ATTR_DESC", 'fromid ASC, toid DESC, @id DESC'); //如果要使用多个字段排序可使用SPH_SORT_EXTENDED模式,@id是sphinx内置关键字,这里指emailid,至于为什么是emailid,自己思考一下

// $weights = array ('company_name' => 20);  
// $s->SetFieldWeights($weights);//设置字段权重  

$s->SetLimits ( 0, 10, 1000);//SetLimits (偏移量,匹配项数目,查询的结果集数默认1000,阀值达到后停止),匹配结果的偏移量,参数的意义依次为:起始位置,返回结果条数,最大匹配条数 

//属性过滤,可过滤的属性必需在配置文件中设置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以外



//$s->SetFilter ( $attribute, $values, $exclude=false ); //设置属性过滤  
//$s->SetGroupBy ( $attribute, $func, $groupsort="@group desc" );//设置分组的属性  


$keyword = '小杨生煎';
$index = 'main'; //索引源是配置文件中的 index 类,如果有多个索引源可使用,号隔开:'email,diary' 或者使用'*'号代表全部索引源
$res = $s->query($keyword,$index);

echo "<pre />";
print_r($res);
echo "<pre />";
die;

$ids = implode(',',array_keys($res['matches'])); 
$conn=@mysql_connect('localhost','root','')||die('数据库链接失败!');
mysql_select_db('test');
mysql_query('set names utf8');
$sql = "select user_comment_id,user_recommend from data where user_comment_id in ({$ids})";
$result = mysql_query($sql);
$row = array();
$i = 0;
$opts = array(
  'before_match' => "<font style='color:red;font-weight:bold;text-decoration:underline'>",
  'after_match' => "</font>",
  "limit"            => 100,  //摘要最多包含的符号数,默认256
  "around"        => 3,       //每个关键词左右选取的词的数目,默认为5
  );
while($f=mysql_fetch_assoc($result)){
   $f = $s->BuildExcerpts ($f, 'main', $keyword, $opts);//执行高亮,这里索引名字千万不能用*  
   $row[$i]= $f; 
   $i++;
}

echo "<pre />";
print_r($row);  
echo "<pre />";
die;
?>

通过官方提供的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的适用于:

  • 使将MySQL FTS 应用程序移植到Sphinx
  • 使没有Sphinx API的那些语言也可以使用Sphinx
  • 当需要在MySQL端对Sphinx结果集做额外处理(例如对原始文档表做JOIN,MySQL端的额外过滤等等)时提供优化。

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

创建一张表t1

CREATE TABLE t1
(
    id          INTEGER UNSIGNED NOT NULL,
    weight      INTEGER NOT NULL,
    query       VARCHAR(3072) NOT NULL,
    group_id    INTEGER,
    INDEX(query)
) 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 = '研究生创业';

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

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

原文地址:https://www.cnblogs.com/nixi8/p/4746189.html