使用 Laravel Scout 启用全文搜索

已发表: 2023-05-08

Laravel 框架已成为开发人员构建 Web 服务的首选资源。

作为开源工具,Laravel 提供了大量开箱即用的功能,使开发人员能够构建健壮且功能强大的应用程序。

它的产品之一是 Laravel Scout,这是一个用于管理应用程序搜索索引的库。 它的灵活性使开发人员可以微调配置并从 Algolia、Meilisearch、MySQL 或 Postgres 驱动程序中进行选择以存储索引。

在这里,我们将深入探索这个工具,教你如何通过驱动程序为 Laravel 应用程序添加全文搜索支持。 您将对一个演示 Laravel 应用程序建模,用于存储模型火车的名称,然后使用 Laravel Scout 向该应用程序添加搜索。

先决条件

要继续,您应该:

  • 安装在您计算机上的 PHP 编译器。 本教程使用 PHP 8.1 版。
  • 安装在您计算机上的 Docker 引擎或 Docker Desktop
  • 一个 Algolia 云帐户,您可以免费创建
想让您的应用更加人性化吗? 尝试添加全文搜索支持! 这是 Laravel Scout 的使用方法️ 点击发推

如何在 Laravel 项目中安装 Scout

要使用 Scout,您必须首先创建一个 Laravel 应用程序,您打算在其中添加搜索功能。 Laravel-Scout Bash 脚本包含在 Docker 容器中生成 Laravel 应用程序的命令。 使用 Docker 意味着您不需要安装额外的支持软件,例如 MySQL 数据库。

Laravel-scout 脚本使用 Bash 脚本语言,因此您必须在 Linux 环境中执行它。 如果您运行的是 Windows,请确保配置适用于 Linux 的 Windows 子系统 (WSL)。

如果使用 WSL,请在终端中执行以下命令以设置首选 Linux 发行版。

 wsl -s ubuntu

接下来,导航到计算机上您要放置项目的位置。 Laravel-Scout 脚本会在这里生成一个项目目录。 在下面的示例中,Laravel-Scout 脚本将在桌面目录中创建一个目录。

 cd /desktop

运行以下命令以执行 Laravel-Scout 脚本。 它将使用必要的样板代码搭建一个 Dockerized 应用程序。

 curl -s https://laravel.build/laravel-scout-app | bash

执行后,使用cd laravel-scout-app更改目录。 然后,在项目文件夹中运行sail-up命令,为您的应用程序启动 Docker 容器。

注意:在许多 Linux 发行版上,您可能需要使用sudo命令运行以下命令以启动提升的权限。

 ./vendor/bin/sail up

您可能会遇到错误:

错误指出端口已分配
指出端口已分配的错误。

要解决此问题,请使用APP_PORT变量在sail up命令中指定一个端口:

 APP_PORT=3001 ./vendor/bin/sail up

接下来,执行以下命令以在 PHP 服务器上通过 Artisan 运行应用程序。

 php artisan serve
使用 Artisan 服务 Laravel 应用程序
使用 Artisan 服务 Laravel 应用程序

在 Web 浏览器中,导航到位于 http://127.0.0.1:8000 的正在运行的应用程序。 应用程序将在默认路由处显示 Laravel 欢迎页面。

Laravel 应用程序的欢迎页面
Laravel 应用程序的欢迎页面

如何将 Laravel Scout 添加到应用程序

在您的终端中,输入命令以启用 Composer PHP 包管理器将 Laravel Scout 添加到项目中。

 composer require laravel/scout

接下来,使用 vendor:publish 命令发布 Scout 配置文件。 该命令会将scout.php配置文件发布到应用程序的配置目录。

 php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"

现在,修改样板.env文件以包含SCOUT_QUEUE布尔值。

SCOUT_QUEUE值将允许 Scout 对操作进行排队,从而提供更好的响应时间。 没有它,像 Meil​​isearch 这样的 Scout 驱动程序将不会立即反映新记录。

 SCOUT_QUEUE=true

此外,修改.env文件中的DB_HOST变量以指向您的本地主机,以便在 Docker 容器中使用 MySQL 数据库。

 DB_HOST=127.0.0.1

如何标记模型和配置索引

默认情况下,Scout 不启用可搜索数据模型。 您必须使用Laravel\Scout\Searchable特征将模型显式标记为可搜索。

您将从为演示Train应用程序创建数据模型并将其标记为可搜索开始。

如何创建模型

对于Train应用程序,您需要存储每个可用火车的占位符名称。

执行下面的 Artisan 命令以生成迁移并将其命名为create_trains_table

 php artisan make:migration create_trains_table
进行名为 create_trains_table 的迁移
进行名为 create_trains_table 的迁移

迁移将在一个文件中生成,该文件的名称结合了指定的名称和当前时间戳。

打开位于database/migrations/目录中的迁移文件。

要添加标题列,请在第 17 行的id()列之后添加以下代码。该代码将添加一个标题列。

 $table->string('title');

要应用迁移,请执行以下命令。

 php artisan migrate
应用 Artisan 迁移
应用 Artisan 迁移

运行数据库迁移后,在app/Models/目录中创建一个名为Train.php的文件。

如何添加 LaravelScoutSearchable 特征

通过将Laravel\Scout\Searchable特征添加到模型中来标记要搜索的Train模型,如下所示。

 <?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class Train extends Model { use Searchable; public $fillable = ['title'];

此外,您需要通过覆盖searchable方法来配置搜索索引。 Scout 的默认行为会保留模型以匹配模型表名称。

因此,将以下代码添加到Train.php文件中前一个块中的代码下方。

 /** * Retrieve the index name for the model. * * @return string */ public function searchableAs() { return 'trains_index'; } }

如何在 Scout 中使用 Algolia

对于使用 Laravel Scout 进行的第一次全文搜索,您将使用 Algolia 驱动程序。 Algolia 是一种软件即服务 (SaaS) 平台,用于搜索大量数据。 它为开发人员提供了一个 Web 仪表板来管理他们的搜索索引和一个强大的 API,您可以使用您首选的编程语言通过软件开发工具包 (SDK) 访问该 API。

在 Laravel 应用程序中,您将使用 PHP 的 Algolia 客户端包。

如何设置 Algolia

首先,您必须为您的应用程序安装 Algolia PHP 搜索客户端包。

执行下面的命令。

 composer require algolia/algoliasearch-client-php

接下来,您必须在.env文件中设置来自 Algolia 的应用程序 ID 和秘密 API 密钥凭据。

使用您的 Web 浏览器,导航到您的 Algolia 仪表板以获取应用程序 ID 和秘密 API 密钥凭据。

单击左侧边栏底部的“设置”以导航到“设置”页面。

接下来,单击设置页面的团队和访问部分中的API 密钥,以查看您的 Algolia 帐户的密钥。

导航到 Algolia Cloud 上的 API 密钥页面
Algolia Cloud 上的 API 密钥页面

在 API 密钥页面,记下应用程序 ID管理 API 密钥值。 您将使用这些凭证来验证 Laravel 应用程序和 Algolia 之间的连接。

从 Algolia API 密钥页面查看应用程序 ID 和管理 API 密钥
应用程序 ID 和管理 API 密钥

使用代码编辑器将以下代码添加到您的 .env 文件中,并将占位符替换为相应的 Algolia API 机密。

 ALGOLIA_APP_ID=APPLICATION_ID ALGOLIA_SECRET=ADMIN_API_KEY

此外,将SCOUT_DRIVER变量替换为以下代码,将值从meilisearch更改为algolia 。 更改此值将指示 Scout 使用 Algolia 驱动程序。

 SCOUT_DRIVER=algolia

如何创建应用程序控制器

app/Http/Controllers/目录中,创建一个TrainSearchController.php文件来存储应用程序的控制器。 控制器将列出数据并将其添加到Train模型。

将以下代码块添加到TrainSearchController.php文件中以构建控制器。

 <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests; use App\Models\Train; class TrainSearchController extends Controller { /** * Get the index name for the model. * * @return string */ public function index(Request $request) { if($request->has('titlesearch')){ $trains = Train::search($request->titlesearch) ->paginate(6); }else{ $trains = Train::paginate(6); } return view('Train-search',compact('trains')); } /** * Get the index name for the model. * * @return string */ public function create(Request $request) { $this->validate($request,['title'=>'required']); $trains = Train::create($request->all()); return back(); } }

如何创建申请途径

在此步骤中,您将创建用于列出新列车并将其添加到数据库的路线。

打开您的routes/web.php文件并用下面的块替换现有代码。

 <?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\TrainSearchController; Route::get('/', function () { return view('welcome'); }); Route::get('trains-lists', [TrainSearchController::class, 'index']) -> name ('trains-lists'); Route::post('create-item', [TrainSearchController::class, 'create']) -> name ('create-item');

上面的代码在应用程序中定义了两个路由。 /trains-lists路线的GET请求列出了所有存储的列车数据。 /create-item路线的POST请求创建新的列车数据。

如何创建应用程序视图

resources/views/目录中创建一个文件并将其命名为Train-search.blade.php 。 该文件将显示搜索功能的用户界面。

将下面代码块的内容添加到Train-search.blade.php文件中,为搜索功能创建一个页面。

 <!DOCTYPE html> <html> <head> <title>Laravel - Laravel Scout Algolia Search Example</title> <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> </head> <body> <div class="container"> <h2 class="text-bold">Laravel Full-Text Search Using Scout </h2><br/> <form method="POST" action="{{ route('create-item') }}" autocomplete="off"> @if(count($errors)) <div class="alert alert-danger"> <strong>Whoops!</strong> There is an error with your input. <br/> <ul> @foreach($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <input type="hidden" name="_token" value="{{ csrf_token() }}"> <div class="row"> <div class="col-md-6"> <div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}"> <input type="text" name="title" class="form-control" placeholder="Enter Title" value="{{ old('title') }}"> <span class="text-danger">{{ $errors->first('title') }}</span> </div> </div> <div class="col-md-6"> <div class="form-group"> <button class="btn btn-primary">Create New Train</button> </div> </div> </div> </form> <div class="panel panel-primary"> <div class="panel-heading">Train Management</div> <div class="panel-body"> <form method="GET" action="{{ route('trains-lists') }}"> <div class="row"> <div class="col-md-6"> <div class="form-group"> <input type="text" name="titlesearch" class="form-control" placeholder="Enter Title For Search" value="{{ old('titlesearch') }}"> </div> </div> <div class="col-md-6"> <div class="form-group"> <button class="btn btn-primary">Search</button> </div> </div> </div> </form> <table class="table"> <thead> <th>Id</th> <th>Train Title</th> <th>Creation Date</th> <th>Updated Date</th> </thead> <tbody> @if($trains->count()) @foreach($trains as $key => $item) <tr> <td>{{ ++$key }}</td> <td>{{ $item->title }}</td> <td>{{ $item->created_at }}</td> <td>{{ $item->updated_at }}</td> </tr> @endforeach @else <tr> <td colspan="4">No train data available</td> </tr> @endif </tbody> </table> {{ $trains->links() }} </div> </div> </div> </body> </html>

上面的 HTML 代码包含一个带有输入字段的表单元素和一个用于在将火车保存到数据库之前键入火车标题的按钮。 该代码还有一个 HTML 表,显示数据库中火车条目的idtitlecreated_atupdated_at详细信息。

如何使用 Algolia 搜索

要查看该页面,请从您的 Web 浏览器导航到 http://127.0.0.1:8000/trains-lists。

查看火车列表页面中显示的火车模型数据
训练模型数据

数据库当前为空,因此您需要在输入字段中输入演示列车的标题,然后单击“创建新列车”进行保存。

插入新的列车条目
插入新的列车条目

要使用搜索功能,请将任何保存的火车标题中的关键字输入到“输入搜索标题”输入字段中,然后单击“搜索”

如下图所示,只会显示标题中包含关键字的搜索条目。

使用搜索功能查找火车条目
使用搜索功能查找火车条目

美力搜索与 Laravel Scout

Meilisearch 是一个开源搜索引擎,专注于速度、性能和改进的开发人员体验。 它与 Algolia 共享多项功能,使用相同的算法、数据结构和研究——但使用不同的编程语言。

开发人员可以在其本地或云基础架构中创建和自行托管 Meil​​isearch 实例。 Meilisearch 还为希望在不管理其基础架构的情况下使用该产品的开发人员提供类似于 Algolia 的 beta 云产品。

在本教程中,您已经在 Docker 容器中运行了 Meil​​isearch 的本地实例。 您现在将扩展 Laravel Scout 功能以使用 Meil​​isearch 实例。

要将美丽搜索添加到 Laravel 应用程序,请在您的项目终端中运行以下命令。

 composer require meilisearch/meilisearch-php

接下来,您需要修改.env文件中的 Meil​​isearch 变量来配置它。

.env文件中的SCOUT_DRIVERMEILISEARCH_HOSTMEILISEARCH_KEY变量替换为以下变量。

 SCOUT_DRIVER=meilisearch MEILISEARCH_HOST=http://127.0.0.1:7700 MEILISEARCH_KEY=LockKey

SCOUT_DRIVER键指定 Scout 应该使用的驱动程序,而MEILISEARCH_HOST表示运行 Meil​​isearch 实例的域。 虽然在开发过程中不需要,但建议在生产中添加MEILISEARCH_KEY

注意:使用美力搜索作为首选驱动程序时,请注释掉 Algolia ID 和 Secret。

完成.env配置后,您应该使用下面的 Artisan 命令索引您预先存在的记录。

 php artisan scout:import "App\Models\Train"

带数据库引擎的 Laravel Scout

Scout 的数据库引擎可能最适合使用较小数据库或管理不太密集的工作负载的应用程序。 目前,数据库引擎支持 PostgreSQL 和 MySQL。

该引擎针对您现有的数据库使用“where-like”子句和全文索引,使其能够找到最相关的搜索结果。 使用数据库引擎时,您不需要为记录编制索引。

要使用数据库引擎,您必须将SCOUT_DRIVER .env变量设置为数据库。

在 Laravel 应用程序中打开.env文件并更改SCOUT_DRIVER变量的值。

 SCOUT_DRIVER = database

将驱动程序更改为数据库后,Scout 将切换为使用数据库引擎进行全文搜索。

使用 Laravel Scout 的集合引擎

除了数据库引擎,Scout 还提供了一个收集引擎。 该引擎使用“where”子句和集合过滤来提取最相关的搜索结果。

与数据库引擎不同,集合引擎支持 Laravel 也支持的所有关系数据库。

您可以通过将SCOUT_DRIVER环境变量设置为collection或通过在 Scout 配置文件中手动指定收集驱动程序来使用收集引擎。

 SCOUT_DRIVER = collection

使用 Elasticsearch 的资源管理器

凭借 Elasticsearch 查询的优势,Explorer 是 Laravel Scout 的现代 Elasticsearch 驱动程序。 它提供兼容的 Scout 驱动程序,并具有实时存储、搜索和分析大量数据等优势。 使用 Laravel 的 Elasticsearch 可在几毫秒内提供结果。

要在 Laravel 应用程序中使用 Elasticsearch Explorer 驱动程序,您需要配置 Laravel-Scout 脚本生成的样板文件docker-compose.yml文件。 您将为 Elasticsearch 添加额外的配置并重新启动容器。

打开您的docker-compose.yml文件并将其内容替换为以下内容。

 # For more information: https://laravel.com/docs/sail version: '3' services: laravel.test: build: context: ./vendor/laravel/sail/runtimes/8.1 dockerfile: Dockerfile args: WWWGROUP: '${WWWGROUP}' image: sail-8.1/app extra_hosts: - 'host.docker.internal:host-gateway' ports: - '${APP_PORT:-80}:80' - '${VITE_PORT:-5173}:${VITE_PORT:-5173}' environment: WWWUSER: '${WWWUSER}' LARAVEL_SAIL: 1 XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}' XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}' volumes: - '.:/var/www/html' networks: - sail depends_on: - mysql - redis - meilisearch - mailhog - selenium - pgsql - elasticsearch mysql: image: 'mysql/mysql-server:8.0' ports: - '${FORWARD_DB_PORT:-3306}:3306' environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' MYSQL_ROOT_HOST: "%" MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 1 volumes: - 'sail-mysql:/var/lib/mysql' - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh' networks: - sail healthcheck: test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"] retries: 3 timeout: 5s elasticsearch: image: 'elasticsearch:7.13.4' environment: - discovery.type=single-node ports: - '9200:9200' - '9300:9300' volumes: - 'sailelasticsearch:/usr/share/elasticsearch/data' networks: - sail kibana: image: 'kibana:7.13.4' environment: - elasticsearch.hosts=http://elasticsearch:9200 ports: - '5601:5601' networks: - sail depends_on: - elasticsearch redis: image: 'redis:alpine' ports: - '${FORWARD_REDIS_PORT:-6379}:6379' volumes: - 'sail-redis:/data' networks: - sail healthcheck: test: ["CMD", "redis-cli", "ping"] retries: 3 timeout: 5s pgsql: image: 'postgres:13' ports: - '${FORWARD_DB_PORT:-5432}:5432' environment: PGPASSWORD: '${DB_PASSWORD:-secret}' POSTGRES_DB: '${DB_DATABASE}' POSTGRES_USER: '${DB_USERNAME}' POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' volumes: - 'sailpgsql:/var/lib/postgresql/data' networks: - sail healthcheck: test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"] retries: 3 timeout: 5s meilisearch: image: 'getmeili/meilisearch:latest' ports: - '${FORWARD_MEILISEARCH_PORT:-7700}:7700' volumes: - 'sail-meilisearch:/meili_data' networks: - sail healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"] retries: 3 timeout: 5s mailhog: image: 'mailhog/mailhog:latest' ports: - '${FORWARD_MAILHOG_PORT:-1025}:1025' - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025' networks: - sail selenium: image: 'selenium/standalone-chrome' extra_hosts: - 'host.docker.internal:host-gateway' volumes: - '/dev/shm:/dev/shm' networks: - sail networks: sail: driver: bridge volumes: sail-mysql: driver: local sail-redis: driver: local sail-meilisearch: driver: local sailpgsql: driver: local sailelasticsearch: driver: local

接下来,运行以下命令以拉取您添加到docker-compose.yml文件中的新 Elasticsearch 图像。

 docker-compose up

然后,执行下面的 Composer 命令将 Explorer 安装到项目中。

 composer require jeroen-g/explorer

您还需要为 Explorer 驱动程序创建一个配置文件。

执行下面的 Artisan 命令生成一个explorer.config文件来存储配置。

 php artisan vendor:publish --tag=explorer.config

上面生成的配置文件将在/config目录中可用。

在您的config/explorer.php文件中,您可以使用indexes键引用您的模型。

 'indexes' => [ \App\Models\Train::class ],

.env文件中的SCOUT_DRIVER变量的值更改为elastic以将 Scout 配置为使用 Explorer 驱动程序。

 SCOUT_DRIVER = elastic

此时,您将通过实现 Explorer 接口并覆盖mappableAs()方法在Train模型中使用 Explorer。

打开App > Models目录中的Train.php文件,并将现有代码替换为以下代码。

 <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use JeroenG\Explorer\Application\Explored; use Laravel\Scout\Searchable; class Train extends Model implements Explored { use HasFactory; use Searchable; protected $fillable = ['title']; public function mappableAs(): array { return [ 'id'=>$this->Id, 'title' => $this->title, ]; } }

使用上面添加的代码,您现在可以使用 Explorer 在Train模型中搜索文本。

Laravel + Scout = 快速、健壮、干净的全文搜索集成。 构建一个演示应用程序并使用本指南进行试用️ 点击鸣叫

概括

对于 PHP 开发人员,Laravel 和 Scout 等附加组件可以轻而易举地集成快速、强大的全文搜索功能。 借助 Database Engine、Collection Engine 以及 Meil​​isearch 和 Elasticsearch 的功能,您可以与应用程序的数据库进行交互,并在短短几毫秒内实现高级搜索机制。

无缝管理和更新您的数据库意味着您的用户可以获得最佳体验,同时您的代码保持干净高效。

借助我们的应用程序和数据库托管解决方案,Kinsta 是满足您所有现代 Laravel 开发需求的一站式商店。 第一个 20 美元由我们承担。