放牧代码和思想
专注自然语言处理、机器学习算法

WordPress中文分词与智能搜索

目录

问题

WordPress的搜索功能非常简陋,如果用户搜索“日语综合教程+第六册”,WordPress会机械地构造一个wp_posts.post_title LIKE '%日语综合教程+第六册%'的SQL查询送到数据库里,结果十有八九找不到任何文章。因为我的文章里并没有直接出现这种句子,我一般给“日语综合教程”加了书名号,并且“第六册”前面一般有空格。

解决思路

解决思路是对用户的查询字串进行分词,然后用空格隔开,最后送到数据库里查询。

中文分词

以前我一直抱怨PHP平台并没有一款出色的分词套件,不过现在SAE提供了一款:http://apidoc.sinaapp.com/sae/SaeSegment.html 

调用方法

/**
 * 分词
 * @param $s 原始句子
 * @return string 用空格隔开的分词结果
 * @author hankcs
 */
function sae_seg($s)
{
    $seg = new SaeSegment();
    $ret = $seg->segment($s);//$s是原始查询串
    if ($ret)
    {
        $phrase = '';
        foreach ($ret as $word)
        {
            $phrase .= $word['word'] . ' ';
        }
        $phrase = substr($phrase, 0, strlen($phrase) - 1);
    }
    return $phrase;
}

这样就可以将“日语综合教程+第六册”拆分为“日语 综合 教程 第六册”。

整合WordPress

目前有多种整合方式:

通过filter实现

function rebuild_search_query($request_vars)
{
    if (!empty($request_vars['s']))
    {
        $request_vars['s'] = sae_seg($request_vars['s']);
    }
    return $request_vars;
}

add_filter('request', 'rebuild_search_query');

这种方式在最大限度上优化了用户体验,但是每个页面都会触发rebuild_search_query,在效率上稍微有点浪费。毕竟不是每个页面都是搜索,也不是每个人都要搜索,更何况大部分搜索都有结果。

通过主题search.php实现

由此,我的想法是,当没有搜索结果的时候,就将搜索语句分词,通过js重定向,发起一次新的搜索:

if(!isset($_GET['seg']))
{
    $ret = sae_seg($request_vars['s']);
    if ($ret)
    {
        ?>
        <script type="text/javascript">
            <!--
            location.replace("<?php echo get_option('siteurl') . '/?s=' . $phrase .'&seg=done'; ?>");
            -->
        </script>
    <?php
    }
}

这样最大限度保证了效率,用户会看到屏幕闪烁了一下才出结果。

效果

就算你用再奇怪的句子,也能搜索到结果:

知识共享许可协议 知识共享署名-非商业性使用-相同方式共享码农场 » WordPress中文分词与智能搜索

分享到:更多 ()

评论 2

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    那搜索的不还是like %aa bb cc dd ee ff%

    cevin2年前 (2015-04-06)回复

我的开源项目

HanLP自然语言处理包基于DoubleArrayTrie的Aho Corasick自动机