全文搜索对于允许用户浏览内容丰富的网站至关重要。在这篇文章中, 我将告诉你如何为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账户得到的id 和secret 。
正如你所看到的,我们正在从环境变量中获取数值。因此,让我们确保我们在**.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库支持Algolia 和MeiliSearch 驱动。此外,你也可以使用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库实现全文搜索。在这个过程中, 我们经历了必要的安装和一个真实世界的例子来证明它。