迅搜(xunsearch) 多值属性的处理

我之前使用Yii2框架做了一个电影网站dy360.net,网站的搜索是通过MySQL的like实现,搜索的条件很多,担心以后数据越来越多,会拖垮网站的速度,于是想通过搜索引擎来解决! 开始准备使用sphinx,研究发现不太好使。后发现迅搜(xunsearch),文档比较清楚,上手比较简单,并且有Yii2的composer包,于是决定使用迅搜。
使用的过程中遇到这样一个问题:一部电影有多个演员,出品国家或地区,其实就是文档的多值属性的新建、搜索的问题。我研究了一下,最终结局方案如下:

#项目的配置文件

project.name = yddy
project.default_charset = utf-8
server.index = 8383
server.search = 8384

[id]
type = id
phrase = yes

[summary]
type = body
cutlen=900

[year]
type = numeric
phrase = yes
index = self
 
[actors_text]
type = string
index = self
tokenizer = split(/)

[category_id]
type = string
index = self
tokenizer = split(,)


[country_id]
type = string
index = self
tokenizer = split(,)
phrase = yes

其实就是使用迅搜的tokenizer分词器,文档上具体的语法如下:

tokenizer 分词器

默认为 default 采用内置的功能强大的 scws 分词,适合绝大多数字符串字段。也可以指定自定义分词器, 格式为 name 或 name(arg) 两种形式,其中 name 是分词器名称,arg 则是传递给分词器构造函数的参数。 自定义分词器需要在 lib/ 目录下编写名为 XSTokenizerName 的分词类并实现接口 XSTokenizer, 内置支持的分词器有以下几种:

full 表示本字段的值整体作为一个检索词,像各种 ID 都适合这种情况
none 表示本字段没有任何词汇用于索引
split([ ]) 表示根据参数分割内容,默认参数为空格,若参数以 / 开头并以 / 结尾则 内部调用 preg_split(arg, ..) 来分割取词,以支持正则或其它特殊字符分割
xlen([2]) 表示根据指定参数长度分段取词,如 ABCDEF => AB + CD + EF
xstep([2]) 表示根据指定参数步长逐段取词,如 ABCDEF => AB + ABCD + ABCDEF
scws([3]) 表示采用指定参数为复合等级的 scws 分词,(若无特殊复合需求,无需指定)
tokenizer = default

然后,根据不同情况使用不同的分割参数,譬如,有的使用'/',有的使用','。
最后,搜索代码如下:

public static function search($params){
        $db = Yii::$app->xunsearch->getDatabase('yddy');
        $xs = $db->xs;

        $search = $xs->getSearch();

        $keywords = $params['word'];
        if(empty($keywords)){
            $keywords ='';
        }
        $search = $search->setQuery($keywords);

        if($category=$params['category']){
            $search->addQueryTerm('category_id',$category);
        }
        if($country=$params['country']){
            $search->addQueryTerm('country_id',$country);
        }

        if( (empty($params['other']) ) && ($year = intval($params['year'])) && is_numeric($params['year'])){
            $search->addQueryTerm('year',$year);

        }elseif(($params['other'] == 'ago') && ($year = intval($params['year'])) ){
            //$search->addRange('year',1900,1978);
            $search->addRange('year',1900,$year);
        }

        if( $rating=intval($params['rating'])){
            $search->addQueryTerm('rate', $rating);
        }

        $search->addQueryTerm('subtype',$params['subtype']);
        //$search->addQueryTerm('status',1);
        //echo $search->getQuery();
        return $search;

    }

相关文章

此处评论已关闭