phpwind搜索二次开发教程

       作为论坛的重要组成部份,搜索的重要性日益突显出来了,那么在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中使用的搜索技术分为三种:mysqlsphinx、云搜索

      

实现方式

大数据量下效率

安装要求

实时性

mysql

sphinx

需额外安装和配置软件

新版本已经实现实时,高

云搜索

需向云搜索提交申请

      

代码改进建议:

1、代码冗余度太高。例如:search/search/base.search.php最后那一堆function get***Dao(),这部份代码基本上是相似的,是否违反编程中的“DRY(Don’t repeat Yourself)”的原则,而且L::loadDB 已经实现单例模式了,这边没办法重复实现一次吧?

建议:使用简单工厂模式改写这部份代码。

……

二次开发说明:

普通情况下是使用mysql进行搜索的,要使用sphinx进行搜索,必须在后台开启sphinx,并安装和配置好sphinx

在进行搜索的二次开发时,要同时处理mysqlsphinx的开发,以防用户在关闭sphinx后,该部份的搜索功能无法使用。

Search_Base这个类中,还包含了一些基础服务,例如权限的检查、搜索结果缓存机制。

search.jpg

    /**

     * 检查用户搜索权限

     * @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;

    }

                                  

mysqllike查询大家都很熟悉了,我就不说了,我就说下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();

这样就可以得到分类信息的搜索结果了。

相关资源:

http://www.sphinxsearch.com

Expert PHP and MySQL.pdf