如何在Laravel中使用Scout设置全文搜索

637 阅读5分钟

全文搜索对于允许用户浏览内容丰富的网站至关重要。在这篇文章中, 我将告诉你如何为Laravel应用程序实现全文搜索。事实上, 我们将使用Laravel Scout库, 它使实现全文搜索变得简单而有趣.

Laravel Scout到底是什么?官方文档是这样总结的:

Laravel Scout提供了一个简单的,基于驱动的解决方案,为你的Eloquent模型添加全文搜索。使用模型观察者, Scout将自动保持你的搜索索引与你的Eloquent记录同步.

基本上, Laravel Scout是一个库,只要模型数据有变化,它就会管理对索引的操作。数据被索引的地方取决于你在Scout库中配置的驱动。

目前,Laravel Scout库支持Algolia,一个基于云的搜索引擎API,这也是我们在本文中用来演示全文搜索的实现。

我们将从安装Scout和Algolia服务器库开始,随着我们的进展,我们将通过一个真实世界的例子来演示你如何索引和搜索你的数据。

服务器配置

在这一节中, 我们将安装为了使Scout库与Laravel一起工作所需要的依赖项.安装完成后, 我们需要进行大量的配置,以便Laravel能够检测到Scout库。

让我们继续使用Composer来安装Scout库。

$composer require laravel/scout

就Scout库的安装而言,这就差不多了。现在我们已经安装了Scout库,让我们确保Laravel知道它。

使用Laravel,你可能知道服务提供者的概念,它允许你在你的应用程序中配置服务。因此, 每当你想在你的Laravel应用程序中启用一个新的服务, 你只需要在config/app.php中添加一个相关的服务提供者条目。

如果你还不熟悉Laravel的服务提供者, 我强烈建议你帮自己一个忙, 去看看这篇介绍性的文章, 解释一下Laravel中服务提供者的基本知识.

在我们的例子中, 我们只需要在config/app.php中把ScoutServiceProvider 服务提供者添加到服务提供者列表中, 如下面的代码所示.

...
...
'providers' => [
    /*
     * Laravel Framework Service Providers...
     */
    Illuminate\Auth\AuthServiceProvider::class,
    Illuminate\Broadcasting\BroadcastServiceProvider::class,
    Illuminate\Bus\BusServiceProvider::class,
    Illuminate\Cache\CacheServiceProvider::class,
    Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
    Illuminate\Cookie\CookieServiceProvider::class,
    Illuminate\Database\DatabaseServiceProvider::class,
    Illuminate\Encryption\EncryptionServiceProvider::class,
    Illuminate\Filesystem\FilesystemServiceProvider::class,
    Illuminate\Foundation\Providers\FoundationServiceProvider::class,
    Illuminate\Hashing\HashServiceProvider::class,
    Illuminate\Mail\MailServiceProvider::class,
    Illuminate\Notifications\NotificationServiceProvider::class,
    Illuminate\Pagination\PaginationServiceProvider::class,
    Illuminate\Pipeline\PipelineServiceProvider::class,
    Illuminate\Queue\QueueServiceProvider::class,
    Illuminate\Redis\RedisServiceProvider::class,
    Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
    Illuminate\Session\SessionServiceProvider::class,
    Illuminate\Translation\TranslationServiceProvider::class,
    Illuminate\Validation\ValidationServiceProvider::class,
    Illuminate\View\ViewServiceProvider::class,

    /*
     * Package Service Providers...
     */

    /*
     * Application Service Providers...
     */
    App\Providers\AppServiceProvider::class,
    App\Providers\AuthServiceProvider::class,
    // App\Providers\BroadcastServiceProvider::class,
    App\Providers\EventServiceProvider::class,
    App\Providers\RouteServiceProvider::class,
    Laravel\Scout\ScoutServiceProvider::class,
],
...
...

现在, Laravel已经知道了ScoutServiceProvider 服务提供者.Scout库带有一个配置文件,允许我们设置API凭证。

让我们继续使用以下命令来发布Scout库提供的资产。

$ php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
Copied File [/vendor/laravel/scout/config/scout.php] To [/config/scout.php]
Publishing complete.

正如你所看到的,它已经把vendor/laravel/scout/config/scout.php文件复制到config/scout.php

接下来,继续在Algolia创建一个账户,因为我们首先需要API凭证。一旦你有了API信息,让我们继续在config/scout.php文件中配置必要的设置,如下面的片段所示。

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Search Engine
    |--------------------------------------------------------------------------
    |
    | This option controls the default search connection that gets used while
    | using Laravel Scout. This connection is used when syncing all models
    | to the search service. You should adjust this based on your needs.
    |
    | Supported: "algolia", "null"
    |
    */

    'driver' => env('SCOUT_DRIVER', 'algolia'),

    /*
    |--------------------------------------------------------------------------
    | Index Prefix
    |--------------------------------------------------------------------------
    |
    | Here you may specify a prefix that will be applied to all search index
    | names used by Scout. This prefix may be useful if you have multiple
    | "tenants" or applications sharing the same search infrastructure.
    |
    */

    'prefix' => env('SCOUT_PREFIX', ''),

    /*
    |--------------------------------------------------------------------------
    | Queue Data Syncing
    |--------------------------------------------------------------------------
    |
    | This option allows you to control if the operations that sync your data
    | with your search engines are queued. When this is set to "true" then
    | all automatic data syncing will get queued for better performance.
    |
    */

    'queue' => env('SCOUT_QUEUE', false),

    /*
    |--------------------------------------------------------------------------
    | Database Transactions
    |--------------------------------------------------------------------------
    |
    | This configuration option determines if your data will only be synced
    | with your search indexes after every open database transaction has
    | been committed, thus preventing any discarded data from syncing.
    |
    */

    'after_commit' => false,

    /*
    |--------------------------------------------------------------------------
    | Chunk Sizes
    |--------------------------------------------------------------------------
    |
    | These options allow you to control the maximum chunk size when you are
    | mass importing data into the search engine. This allows you to fine
    | tune each of these chunk sizes based on the power of the servers.
    |
    */

    'chunk' => [
        'searchable' => 500,
        'unsearchable' => 500,
    ],

    /*
    |--------------------------------------------------------------------------
    | Soft Deletes
    |--------------------------------------------------------------------------
    |
    | This option allows you to control whether to keep soft deleted records in
    | the search indexes. Maintaining soft deleted records can be useful
    | if your application still needs to search for the records later.
    |
    */

    'soft_delete' => false,

    /*
    |--------------------------------------------------------------------------
    | Identify User
    |--------------------------------------------------------------------------
    |
    | This option allows you to control whether to notify the search engine
    | of the user performing the search. This is sometimes useful if the
    | engine supports any analytics based on this application's users.
    |
    | Supported engines: "algolia"
    |
    */

    'identify' => env('SCOUT_IDENTIFY', false),

    /*
    |--------------------------------------------------------------------------
    | Algolia Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your Algolia settings. Algolia is a cloud hosted
    | search engine which works great with Scout out of the box. Just plug
    | in your application ID and admin API key to get started searching.
    |
    */

    'algolia' => [
        'id' => env('ALGOLIA_APP_ID', 'XXXXXX'),
        'secret' => env('ALGOLIA_SECRET', 'XXXXXXXXXXXXXXXXXXXXXXXX'),
    ],

];

注意,我们将SCOUT_DRIVER 的值设置为algolia 驱动。因此,要求你在文件的最后配置Algolia驱动的必要设置。基本上,你只需要设置你从Algolia账户得到的idsecret

正如你所看到的,我们正在从环境变量中获取数值。因此,让我们确保我们在**.env**文件中正确地设置以下变量。

...
...
ALGOLIA_APP_ID=XXXXXX
ALGOLIA_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXX
...
...

最后,我们需要安装Algolia PHP SDK,它将被用来与Algolia使用API进行交互。让我们使用Composer来安装它,如下面的片段所示。

$composer require algolia/algoliasearch-client-php

就这样,我们已经安装了所有必要的依赖项,以便向Algolia服务发布和索引数据。

如何使模型可索引和可搜索

在上一节中,我们做了所有艰苦的工作来设置Scout和Algolia库,以便我们能够使用Algolia搜索服务来索引和搜索数据。

在这一节中,我们将通过一个例子来演示你如何对现有数据进行索引并从Algolia检索搜索结果。我假设你的应用程序中有一个默认的Post 模型。

我们需要做的第一件事是将Laravel\Scout\Searchable 特质添加到Post 模型中。这使得Post 模型可以被搜索到;Laravel会在每次添加、更新或删除帖子记录时将其与Algolia索引同步。

<?php
namespace App;
 
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
 
class Post extends Model
{
    use Searchable;
    
    ...
    ...
}

有了这个,Post 模型就可以搜索了!

接下来, 我们要配置那些应该首先被索引的字段.当然,你不希望在Algolia中对你的模型的所有字段进行索引,以保持它的有效性和轻量级。事实上,更多的时候,你不需要它。

你可以在模型类中添加toSearchableArray 来配置将被索引的字段。

/**
 * Get the indexable data array for the model.
 *
 * @return array
 */
public function toSearchableArray()
{
  $array = $this->toArray();
     
  return array('id' => $array['id'],'name' => $array['name']);
}

现在,我们已经准备好将现有的Post 记录导入Algolia并进行索引。事实上,Scout库通过提供下面的artisan命令使之变得简单。

$php artisan scout:import "App\Post"

这应该可以一次性导入Post 模型的所有记录!它们一被导入就会被编入索引,所以我们已经准备好查询记录了。继续探索Algolia仪表盘以查看导入的记录和其他工具。

它是如何整体工作的

在本节中,我们将创建一个例子,演示如何执行与Algolia索引实时同步的搜索和CRUD操作。

继续创建app/Http/Controllers/SearchController.php文件,内容如下。

<?php
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Post;
 
class SearchController extends Controller
{
    public function query()
    {
        // queries to Algolia search index and returns matched records as Eloquent Models
        $posts = Post::search('title')->get();
         
        // do the usual stuff here
        foreach ($posts as $post) {
          // ...
        }
    }
 
    public function add()
    {
        // this post should be indexed at Algolia right away!
        $post = new Post;
        $post->setAttribute('name', 'Another Post');
        $post->setAttribute('user_id', '1');
        $post->save();
    }
     
    public function delete()
    {
        // this post should be removed from the index at Algolia right away!
        $post = Post::find(1);
        $post->delete();
    }
}

当然,我们也需要添加相关的路由。

Route::get('search/query', 'SearchController@query');
Route::get('search/add', 'SearchController@add');
Route::get('search/delete', 'SearchController@delete');

让我们通过query 方法来看看如何在Algolia中进行搜索。

public function query()
{
    // queries to Algolia search index and returns matched records as Eloquent Models
    $posts = Post::search('title')->get();
     
    // do the usual stuff here
    foreach ($posts as $post) {
        // ...
    }
}

回顾一下,我们通过添加Searchable 特质使Post 模型可以搜索。因此,Post 模型可以使用search 方法来从Algolia索引中检索记录。在上面的例子中,我们试图获取与title 关键字相匹配的记录。

接下来是add 方法,它模仿了添加新帖子记录的工作流程。

public function add()
{
    // this post should be indexed at Algolia right away!
    $post = new Post;
    $post->setAttribute('name', 'Another Post');
    $post->setAttribute('user_id', '1');
    $post->save();
}

上面的代码没有什么花哨的,它只是使用Post 模型创建一个新的帖子记录。但是Post 模型实现了Searchable 特质, 所以Laravel这次做了一些额外的工作,在Algolia中对新创建的记录进行索引。所以你可以看到, 索引是实时完成的。

最后, 有一个delete 方法.我们也来看看它。

public function delete()
{
    // this post should be removed from the index at Algolia right away!
    $post = Post::find(1);
    $post->delete();
}

正如你所期望的那样,该记录一旦从数据库中删除,就会立即从Algolia索引中删除。

基本上,如果你想让现有的模型可以被搜索到,你这边不需要额外的努力。一切都由Scout库使用模型观察员来处理。

如何制作一个自定义搜索引擎/驱动程序

默认情况下,Scout库支持AlgoliaMeiliSearch 驱动。此外,你也可以使用database 驱动程序来做一个轻量级的数据库。另一方面,如果你想实现你自己的自定义引擎,Scout允许你实现这个目的。你只需要编写你的自定义引擎并在Scout上注册即可

你的自定义引擎类可能看起来像这样。

<?php

namespace App\Engines;

use Laravel\Scout\Builder;
use Laravel\Scout\Engines\Engine;

class CustomScoutEngine extends Engine {
    public function update($models) {}
    public function delete($models) {}
    public function search(Builder $builder) {}
    public function paginate(Builder $builder, $perPage, $page) {}
    public function mapIds($results) {}
    public function map(Builder $builder, $results, $model) {}
    public function getTotalCount($results) {}
    public function flush($model) {}
}

当然,你需要按照你的要求实现抽象的方法。

一旦你实现了你的自定义引擎类,你只需要注册它。你可以在服务提供者的boot 方法的帮助下做到这一点,如下面的片段所示。

use App\Engines\CustomScoutEngine;
use Laravel\Scout\EngineManager;
 
/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    resolve(EngineManager::class)->extend('custom_scout_engine', function () {
        return new CustomScoutEngine;
    });
}

最后,在你的自定义引擎被注册后,你可以在config/scout.php文件中使用它。

'driver' => 'custom_scout_engine',

总结

今天, 我们讨论了如何在Laravel中使用Laravel Scout库实现全文搜索。在这个过程中, 我们经历了必要的安装和一个真实世界的例子来证明它。