TNTSearch 轻量级全文索引 + 中文分词

TNTSearch 轻量级全文索引+中文分词

选用 TNTSearch 的原因:轻,方便移植,不需要额外安装服务,能减少后期维护的工作量。搜索的效果也还不错,可以满足大多数项目场景,如果对性能和精准度要求较高,还是使用 Elasticsearch 吧。因TNTSearch使用的逗号空格分词,所以我们还需要一个中文分词的服务。
这里我选用的是 fukuball/jieba-php 选它的原因也是轻量,也不需要过多的依赖,部署方便。

TNTSearch 集成教程
https://laravel-china.org/articles/3702/full-text-indexing-engine-implemented-in-tntsearch-php
教程讲的很清楚,也没有什么坑,根据教程一步步来就可以了。这里就不在重复了。

下面主要说说 TNTSearch 怎么集成 fukuball/jieba-php 中文分词。

安装 fukuball/jieba-php

composer composer require fukuball/jieba-php:dev-master

注:fukuball/jieba-php 分词对内存有要求,如果内存过小,分词的时候可能会报错。

开始集成

  1. 修改配置 app/config/scout.php 增加 jieba 的配置项

    'tntsearch' => [
        ...
    
        'tokenizer' => [
            ...
            'jieba' => [
                'dict' => 'small',
            ],
    
           ....
        ],
        ...
    ],
  2. 新建一个 Tokenizer
    app/Handlers/TokenizerHandler.php

    <?php
    namespace App\Handlers;
    use Fukuball\Jieba\Jieba;
    use Fukuball\Jieba\Finalseg;
    use TeamTNT\TNTSearch\Support\TokenizerInterface;
    class TokenizerHandler implements TokenizerInterface
    {
    public function __construct(array $options = [])
    {
        Jieba::init($options);
        Finalseg::init($options);
    }
    
    public function tokenize($text, $stopwords = [])
    {
        return is_numeric($text) ? [] : $this->getTokens($text, $stopwords);
    }
    
    public function getTokens($text, $stopwords = [])
    {
        $split = Jieba::cutForSearch($text);
        return $split;
    }
    }
  3. 新建服务提供者,用来取代 laravel-scout-tntsearch-driver 默认的服务提供者
    app/Providers/ScoutServiceProvider.php

    <?php
    namespace App\Providers;
    use TeamTNT\TNTSearch\TNTSearch;
    use Laravel\Scout\EngineManager;
    use TeamTNT\Scout\Console\ImportCommand;
    use TeamTNT\Scout\Engines\TNTSearchEngine;
    use TeamTNT\Scout\TNTSearchScoutServiceProvider;
    use App\Handlers\TokenizerHandler;
    class ScoutServiceProvider extends TNTSearchScoutServiceProvider
    {
    public function boot()
    {
        $this->app[EngineManager::class]->extend('tntsearch', function ($app) {
            $tnt = new TNTSearch();
            $driver = config('database.default');
            $config = config('scout.tntsearch') + config("database.connections.{$driver}");
            $tnt->loadConfig($config);
            # 注入中文分词服务
            $tnt->setTokenizer(new TokenizerHandler(config('scout.tntsearch.tokenizer.jieba')));
            $tnt->setDatabaseHandle(app('db')->connection()->getPdo());
            $this->setFuzziness($tnt);
            $this->setAsYouType($tnt);
            return new TNTSearchEngine($tnt);
        });
        if ($this->app->runningInConsole()) {
            $this->commands([
                ImportCommand::class,
            ]);
        }
    }
    }
  4. 注册服务提供者,将 TNTSearchScoutServiceProvider 取消注册
    app/config/app.php
    ...
    'providers' => [
        ...
        SocialiteProviders\Manager\ServiceProvider::class,
        # TeamTNT\Scout\TNTSearchScoutServiceProvider::class,
        ...
    ]
    ...

至此集成完毕,可以去测试一下效果。
当然也可以根据 laravel-scout-tntsearch-driver 源码修改,然后打包成一个自己包,只是这样以后就失去了原包的升级服务。可以自行取舍,没有对错,适合就好。

如果有问题可以一起探讨一下。
我开源的 laraCMS 已集成了 TNTSearch ,如果有兴趣可以去github查看源码,也可以去在线体验

Github: https://github.com/wanglelecc/laracms
预览:https://www.56br.com/