首页 > web > php

sphinx分词精准搜索

admin2019--06-21共有549人围观
简介在Sphinx源码API中,有好几种语言的API调用.其中有一个是sphinxapi.php。 不过以下的测试使用的是Sphinx的PHP扩展.具体安装见本文开头的Sphinx安装部分。 测试用的搜索类sphinxsearch.php:注意修改连接信息改成自己的。(不会整理语言,直接码代码)
        $user = 'root';
        $this->passwd = 'root';
        $this->port = '9306';
        $this->sport = '9312';
        $defaults = array(
            'query_mode' => SPH_MATCH_EXTENDED2,
            'sort_mode' => SPH_SORT_EXTENDED,
            'ranking_mode' => SPH_RANK_PROXIMITY_BM25,
            'field_weights' => array(),
            'max_matches' => 1000,
            'snippet_enabled' => true,
            'snippet_fields' => array(),
        );
        $this->options = array_merge($defaults, $options);
        $this->client = new \SphinxClient();
        $this->client->setServer($this->host, $this->sport);
        $this->client->setMatchMode($this->options['query_mode']);
        if ($this->options['field_weights'] !== array()) {
            $this->client->setFieldWeights($this->options['field_weights']);
        }
        $this->getDBConnection();
    }
 
    /**
     * Query
     *
     * @param string  $keywords
     * @param integer $offset
     * @param integer $limit
     * @param string  $index
     * @return array
     **/
    public function query($keywords, $offset = 0, $limit = 10, $index = '*') {
        $this->keywords = $keywords;
        $max_matches = $limit > $this->options['max_matches'] ? $limit : $this->options['max_matches'];
        $this->client->setLimits($offset, $limit, $max_matches);
        $query_results = $this->client->query($keywords, $index);
 
        if ($query_results === false) {
            $this->log('error:' . $this->client->getLastError());
        }
 
        $res = [];
        if ( empty($query_results['matches']) ) {
            return $res;
        }
        $res['total'] = $query_results['total'];
        $res['total_found'] = $query_results['total_found'];
        $res['time'] = $query_results['time'];
        $list=[];
        foreach($query_results['matches'] as $key=>$detail){
            $data=$detail['attrs'];
            $data['id']=$key;
            $data['weight']=$detail['weight'];
            $list[]=$data;
        }
        $res['data'] = $list;
        return $res;
    }
 
    /**
     * custom sorting
     *
     * @param string $sortBy
     * @param int $mode
     * @return bool
     **/
    public function setSortBy($sortBy = '', $mode = 0) {
        if ($sortBy) {
            $mode = $mode ?: $this->options['sort_mode'];
            $this->client->setSortMode($mode, $sortBy);
        } else {
            $this->client->setSortMode(SPH_SORT_RELEVANCE);
        }
    }
 
    /**
     * Chinese words segmentation
     *
     **/
    public function wordSplit($keywords) {
        $so = new pscws('utf-8');
        $so->set_dict();
        $so->set_rule();
        $so->set_ignore(true);
        $so->set_multi(false);
        $so->set_duality(false);
        $so->send_text($keywords);
        $words = [];
        $kws = [];
        $results =  $so->get_result();
        foreach ($results as $res) {
            $kws[]=$res['word'];
            $words[] = '(' . $res['word'] . ')';
        }
//        $words[] = '(' . $keywords . ')';
        $re['str']=join('|', $words);
        $re['arr']=$kws;
        return $re;
    }
 
    /**
     * get current sphinx client
     *
     * @return resource
     **/
    public function getClient() {
        return $this->client;
    }
    /**
     * log error
     **/
    public function log($msg) {
        // log errors here
        //echo $msg;
    }
    /**
     * magic methods
     **/
    public function __call($method, $args) {
        $rc = new \ReflectionClass('SphinxClient');
        if ( !$rc->hasMethod($method) ) {
            throw new Exception('invalid method :' . $method);
        }
        return call_user_func_array(array($this->client, $method), $args);
    }
 
}

下面控制器用法:

$s = new sphinxsearch([
    'snippet_fields' => ['post_title', 'post_alias','stars','directors','post_excerpt'],
    'field_weights' => ['post_title' => 50, 'post_alias' => 40,'stars'=>30,'directors'=>20,'post_excerpt'=>10],
]);
$s->setSortMode(SPH_SORT_EXTENDED, '@weight desc');
$words = $s->wordSplit($keyword);
$start=($page-1)*$lows;
$res = $s->query($words['str'], $start, $lows, 'moviesearch');
if(!empty($res['data'])){
    foreach($res['data'] as &$detail){
        $detail['more']=json_decode($detail['more'],JSON_UNESCAPED_UNICODE);
        $detail['stars']=json_decode($detail['stars'],JSON_UNESCAPED_UNICODE);
        if(!empty($detail['stars'])){
            $detail['stars']=implode(' ',$detail['stars']);
        }
        $detail['directors']=json_decode($detail['directors'],JSON_UNESCAPED_UNICODE);
        if(!empty($detail['directors'])){
            $detail['directors']=implode(' ',$detail['directors']);
        }
    }
    $list=$res['data'];
    $config['path'] = $this->request->baseUrl();
    $pa=new Bootstrap($list,$lows,$page,$res['total'],false,$config);
    $pa->appends($param);
    $pages=$pa->render();
    $this->assign('kws',join(',',$words['arr']));
}

snippet_fields搜索的字段,field_weights搜到得分权重。

下面分词效果:


那么会把同时存在分词的记录权排在前列

之后就是一元分词效果了。


文章评论

评论列表(0)

发表评论 取消回复

微信公众账号

微信扫一扫加关注