作为论坛的重要组成部份,搜索的重要性日益突显出来了,那么在phpwind系统如何对搜索部份进行二次开发呢?
知识点:
sphinx相关配置及其接口使用、mysql 查询、缓存的使用
目录结构:
我们首先来介绍下phpwind的搜索相关目录结构:
/
searcher.php (入口文件)
search.php (旧版入口文件,兼容性考虑,直接进行跳转)
lib/search 搜索相关的控制及业务逻辑目录
searcherseo.class.php 搜索seo设置
searchseo.class.php 旧版搜索seo设置,已废弃
searcher.class.php 搜索公共服务层
extendsearcher.class.php 用户自定义的搜索服务层
db/ 数据库搜索相关的类
keywordstatisticdatabasedb.class.php 搜索关键词及搜索次数统计
schcachedb.class.php 搜索缓存类
search/ 论坛搜索的实现类
base.search.php 搜索公共基类
mysql.search.php 搜索的mysql实现类
sphinx.search.php 搜索的sphinx实现类
extend/ 搜索扩展类
extendabstract.class.php 扩展抽象类
extendconfigs.php 扩展配置类
userdefine/ 用户自定义的搜索应用
cmssearcher.extend.php 文章系统内容搜索类
hotwordssearcher.class.php 热门关键词处理类
keywordstatistic.class.php 关键词统计类(文件缓存)
keywordstatisticdatabase.class.php关键词统计类(数据库)
realtimesearcher.class.php 准实时搜索类
weibosearcher.extend.php 微博搜索类
template/wind
search.htm 旧版搜索页面
searcher.htm 搜索页面
searcher_advanced.htm 高级搜索页面
searcher_cms.htm 文章搜索结果显示页面
searcher_defaultresult.htm 搜索默认结果页
searcher_diary.htm 日志搜索结果显示页面
searcher_forum.htm 版块相关搜索结果显示页面
searcher_group.htm 群组搜索结果显示页面
searcher_user.htm 会员搜索结果显示页面
searcher_headbar.htm 搜索头部登录及个人信息导航页面
searcher_header.htm 搜索header头文件页面
searcher_none.htm 搜索结果为空的默认显示页面
searcher_result.htm 搜索结果的框架结构页面,在这里根据搜索类型,包含具体的搜索结果页面
searcher_searchinput.htm 搜索表单页面
searcher_thread.htm 帖子搜索后续管理页面
searcher_threadleftside.htm 搜索结果左侧页面
searcher_footer.htm 搜索底部模板
简介:
phpwind中使用的搜索技术分为三种:mysql和sphinx、云搜索
实现方式 |
大数据量下效率 |
安装要求 |
实时性 |
mysql |
低 |
无 |
高 |
sphinx |
高 |
需额外安装和配置软件 |
新版本已经实现实时,高 |
云搜索 |
高 |
需向云搜索提交申请 |
高 |
代码改进建议:
1、代码冗余度太高。例如:search/search/base.search.php最后那一堆function get***Dao(),这部份代码基本上是相似的,是否违反编程中的“DRY(Don’t repeat Yourself)”的原则,而且L::loadDB 已经实现单例模式了,这边没办法重复实现一次吧?
建议:使用简单工厂模式改写这部份代码。
……
二次开发说明:
普通情况下是使用mysql进行搜索的,要使用sphinx进行搜索,必须在后台开启sphinx,并安装好和配置好sphinx。
在进行搜索的二次开发时,要同时处理mysql和sphinx的开发,以防用户在关闭sphinx后,该部份的搜索功能无法使用。
在Search_Base这个类中,还包含了一些基础服务,例如权限的检查、搜索结果缓存机制。
/**
* 检查用户搜索权限
* @return unknown_type
*/
function _checkUserLevel() {
$userService = $this->_getUserService ();
if (!$this->_userGroup ['searchtime']) {
return true;
}
$memberInfo
= $userService->get
( $this->_userId, false, false, true );
$memberInfo
['lasttime'] = $memberInfo ? $memberInfo ['lasttime'] : 0;
if ($this->_timestamp - $memberInfo ['lasttime'] < $this->_userGroup ['searchtime']) {
return false;
}
$userService->update ( $this->_userId, array (), array (), array ('lasttime' => $this->_timestamp ) );
return true;
}
/**
* 检查用户搜索间隔时间
* @return unknown_type
*/
function _checkWaitSegment() {
if (! $this->_waitSegment)
return true;
if (file_exists ( D_P . 'data/bbscache/schwait_cache.php' )) {
if ($this->_timestamp - pwFilemtime ( D_P . 'data/bbscache/schwait_cache.php' ) > $this->_waitSegment) {
P_unlink(D_P.'data/bbscache/schwait_cache.php');
} else {
return false;
}
}
return true;
}
mysql的like查询大家都很熟悉了,我就不说了,我就说下sphinx的二次开发。
总体流程:
1、先从搜索页面上接收到搜索的系列参数,然后传递给搜索相关的服务类,然后获取到相关内容的编号集合
2、从mysql中根据编号集合去获取相关内容的详细内容。
3、最后将搜索结果进行关键词等处理,然后输出到搜索结果页面。
例如要在sphinx上进行分类信息的搜索,要在lib\search\search\sphinx.search.php文件中进行如下处理:
/********************************************************************/
// 分类信息Sphinx定制
function searchFenlei($keywords,$fid,$page=1,$perpage=20,$modelid,$expand=array()){
if(!($result = $this->_searchFenlei($keywords,$fid,$page,$perpage,$modelid,$expand))){
return array(false,false);
}
return array($result[0],$result[1]);
}
function _searchFenlei($keywords,$forumIds,$page=1,$perpage=20,$modelid,$expand=array()){
global $timestamp;
$ifrecycle
= 0;
//list($keywords,$users,$starttime,$endtime)
= $this->_checkThreadConditions($keywords,$userNames,$starttime,$endtime);
$starttime
= 0;
$endtime
= $timestamp;
if(!$modelid) return false;
$keywords = trim($keywords);
//if(!$keywords || ($userNames
&& !$users )) return false;
$configs
= $this->_getSphinxConfigs($this->_server_thread);
list($host,$port) = ($configs) ? $configs : $this->_getSphinxConfig();
$filter
= $filterRange = array();
//if($users){
// $filter[]
= array('attribute' => 'authorid','values' => array_keys($users),'exclude' => false);
//}
if($forumIds){
$forumIds = (is_array($forumIds)) ? $forumIds :
array($forumIds);
$filter[] = array('attribute' => 'fid','values' => $forumIds,'exclude' => false);
}
if($this->_sphinxFilterIds){
$filter[] = array('attribute' => 'fid','values' => $this->_sphinxFilterIds,'exclude' => true);
}
//$filterRange[] = array('attribute' => 'postdate','min'
=> $starttime,'max' => $endtime,'exclude'
=> false);
$filterRange[]
= array('attribute' => 'fid','min' => 1,'max' => 99999999,'exclude' => false);
// 分类信息过滤
$filter[]
= array('attribute' => 'ifrecycle','values' => array($ifrecycle),'exclude' => false);
foreach($expand['filter'] as $k=>$v) {
if($k==1) {
foreach($v as $kk=>$vv) {
$filter[] = array('attribute' => $kk,'values' => array($vv),'exclude' => false);
}
} elseif($k==2) {
foreach($v as $kk=>$vv) {
if($vv[0]<0 || $vv[1]<0) continue;
$filterRange[]
= array('attribute' => $kk,'min' => $vv[0],'max' => $vv[1],'exclude' => false);
}
}
}
$page = $page>1 ? $page : 1;
$offset = intval(($page - 1) * $perpage);
$this->_setDefaultSphinx();
$this->_sphinxHost
= $host;
$this->_sphinxPort
= $port;
$this->_sphinxMode
= $this->_getSphinxMode($this->_sphinxMethod);
$this->_sphinxFilter =
$filter;
$this->_sphinxFilterRange = $filterRange;
$this->_sphinxOffset =
$offset;
$this->_sphinxLimit
= $perpage;
$this->_sphinxKeywords = $keywords;
//$this->_sphinxSortBy = ($sortby && in_array($sortby,array('topped','postdate','lastpost'))) ? $sortby : '';
$this->_sphinxIndex
= 'topicvalue'.$modelid.'index';
$result = $this->_sphinxAssemble('topped DESC, lastpost DESC');
if ( $result === false ) return false;
return $this->_buildSphinxResult($result,'id');
}
/********************************************************************/
上面为实现类,然后还要在搜索接口lib\search\searcher.class.php上加上分类信息的搜索接口:
/**
* 分类信息Sphinx定制
* @param mixed $keywords 关键词
* @param int $fid 版块编号
* @param int $page 当前页码
* @param int $perpage
每页的页码数
* @param int $modelid
分类编号
* @param array $expand 过滤的参数
* @return array 返回结果
*/
function searchFenlei($keywords,$fid,$page=1,$perpage=20,$modelid,$expand=array()){
if(count($keywords)==1){
$keywords
= $keywords[0];
}
if($modelid>0){
return $this->_service->searchFenlei($keywords,$fid,$page,$perpage,$modelid,$expand);}else{
return array();
}
}
然后只要在要调用搜索分类的地方,加上:
$searcherService = L::loadclass ( 'searcher', 'search' );
$result = $searcherService->searchFenlei();
这样就可以得到分类信息的搜索结果了。
相关资源:
Expert PHP and MySQL.pdf