
LIKE操作符进行搜索,但这在数据达到一定规模后,性能瓶颈就暴露无遗。我尝试过优化SQL查询、添加索引,但效果甚微。我深知,要解决这个问题,需要引入专业的全文本搜索引擎。市面上不乏优秀的解决方案,比如Elasticsearch、Algolia等,但它们通常意味着更高的学习曲线、更复杂的部署和维护成本,这对于一个快速迭代的项目来说,无疑增加了额外的负担。我渴望找到一个既能提供高性能搜索,又能在Laravel生态中无缝集成、保持开发效率的方案。
Composer在线学习地址:学习地址
问题的症结:传统数据库搜索的局限性
想象一下,当你的电商网站拥有成千上万件商品,或者博客系统积累了海量的文章,用户输入一个关键词进行搜索时:
-
性能低下:
SELECT * FROM products WHERE name LIKE '%关键词%'这样的查询,在数据量大时,会导致全表扫描,效率极低。即使有索引,也难以覆盖所有模糊匹配场景。 -
相关性差: 简单的
LIKE匹配无法理解语义,无法根据词频、位置等因素提供更相关的搜索结果。 - 缺乏容错: 用户打错字(typo)是常有的事,传统数据库搜索对此束手无策,导致用户体验不佳。
- 功能受限: 诸如分面搜索(faceted search)、同义词、排序等高级搜索功能,通过SQL实现起来异常复杂甚至不可能。
解决方案:Typesense与Laravel Scout的强强联手
是不是感觉眼前一亮?我发现了一个完美的组合来解决这些痛点:Typesense 作为高性能的后端搜索引擎,以及 Laravel Scout 作为Laravel模型与搜索引擎之间的优雅桥梁。
认识 Typesense
Typesense 是一个现代化的、开源的、快速且容错的全文本搜索引擎。它的设计目标是提供与Algolia类似的开发者体验,但作为开源项目,它让你拥有完全的控制权。Typesense 的核心优势在于:
- 极速响应: 专为低延迟搜索而设计,即便在大量数据下也能提供毫秒级的搜索结果。
- 容错性强: 内置错别字容忍功能,用户即使输入有误也能找到正确结果。
- 易于部署: 单个二进制文件即可运行,部署和管理相对简单。
- 多功能性: 支持排序、过滤、分面搜索、同义词等高级功能。
拥抱 Laravel Scout
Laravel Scout 是 Laravel 官方提供的一个轻量级解决方案,用于为 Eloquent 模型添加全文本搜索。它的核心思想是提供一个统一的 API,让你可以在不修改应用代码逻辑的情况下,轻松切换不同的搜索驱动(如Algolia, Elasticsearch, MeiliSearch等)。Scout 的优点在于:
-
API 统一: 无论底层使用何种搜索引擎,你的应用代码都使用相同的
search()方法。 - 模型同步: 当你的Eloquent模型被创建、更新或删除时,Scout 会自动将这些更改同步到搜索引擎中。
- 开发友好: 极大地简化了搜索功能的开发和维护。
typesense/laravel-scout-typesense-driver:连接二者的桥梁
最初,typesense/laravel-scout-typesense-driver 作为独立的 Composer 包提供了将 Typesense 集成到 Laravel Scout 的能力。但好消息是,它的核心功能已被原生集成到Laravel Scout中!这意味着现在你可以更无缝地享受 Typesense 带来的强大搜索体验,无需额外安装这个特定的驱动包(除非你需要一些高级的、非原生支持的特性,或者你正在使用较旧的Laravel版本)。
本文将以原生Laravel Scout集成Typesense的方式进行说明,但请注意,原始的typesense/laravel-scout-typesense-driver包的安装和配置方式与原生集成非常相似,它为原生支持奠定了基础。
如何开始使用?
1. 安装必要的HTTP客户端
Typesense PHP SDK 使用 httplug 来抽象 HTTP 客户端。你需要根据你的 guzzlehttp/guzzle 版本安装对应的 httplug 适配器。例如,如果你的 Laravel 项目使用 Guzzle 7 (Laravel 8+ 通常如此):
composer require php-http/guzzle7-adapter
2. 安装 Laravel Scout
如果你的项目还没有安装 Laravel Scout,请先安装它:
composer require laravel/scout
3. 发布 Scout 配置
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
这会在 config/scout.php 文件中生成 Scout 的配置。
4. 配置 Typesense 驱动
在你的 .env 文件中,指定 Scout 使用 Typesense 驱动:
SCOUT_DRIVER=typesense
然后,在 config/scout.php 文件中添加 Typesense 的配置信息。你需要确保 Typesense 服务正在运行。
// config/scout.php
return [
// ... 其他配置
'typesense' => [
'api_key' => env('TYPESENSE_API_KEY', 'your_typesense_api_key'), // 你的 Typesense API Key
'nodes' => [
[
'host' => env('TYPESENSE_HOST', 'localhost'),
'port' => env('TYPESENSE_PORT', '8108'),
'path' => env('TYPESENSE_PATH', ''),
'protocol' => env('TYPESENSE_PROTOCOL', 'http'),
],
],
'nearest_node' => [ // 可选,用于读操作的最近节点
'host' => env('TYPESENSE_NEAREST_HOST', 'localhost'),
'port' => env('TYPESENSE_NEAREST_PORT', '8108'),
'path' => env('TYPESENSE_NEAREST_PATH', ''),
'protocol' => env('TYPESENSE_NEAREST_PROTOCOL', 'http'),
],
'connection_timeout_seconds' => 2,
'healthcheck_interval_seconds' => 30,
'num_retries' => 3,
'retry_interval_seconds' => 1,
],
];建议将 api_key 和节点信息也放入 .env 文件,方便管理。
5. 在模型中集成 Typesense
在你的 Eloquent 模型中,你需要使用 Laravel\Scout\Searchable trait,并实现 Typesense\LaravelTypesense\Interfaces\TypesenseDocument 接口(这个接口在原生Scout中可能不再强制,但其方法是Typesense驱动所需的)。
toArray(),
[
'id' => (string) $this->id, // Typesense通常将ID视为字符串
'created_at' => $this->created_at->timestamp, // 将日期转换为时间戳
]
);
}
/**
* Typesense Collection 的 Schema 定义。
*
* @return array
*/
public function getCollectionSchema(): array
{
return [
'name' => $this->searchableAs(), // Collection 名称,通常是模型的表名
'fields' => [
['name' => 'id', 'type' => 'string'],
['name' => 'name', 'type' => 'string'],
['name' => 'description', 'type' => 'string'],
['name' => 'price', 'type' => 'float'],
['name' => 'created_at', 'type' => 'int64'],
],
'default_sorting_field' => 'created_at', // 默认排序字段
];
}
/**
* 定义 Typesense 搜索时要查询的字段。
*
* @return array
*/
public function typesenseQueryBy(): array
{
return [
'name',
'description',
];
}
}6. 导入数据到 Typesense
当模型准备好后,你需要将现有数据导入到 Typesense 中:
php artisan scout:import "App\\Models\\Product"
7. 开始搜索!
现在,你就可以像使用任何 Laravel Scout 驱动一样进行搜索了:
use App\Models\Product;
// 简单搜索
$results = Product::search('手机')->get();
// 带有过滤和排序的搜索
$filteredResults = Product::search('笔记本')
->where('price', '<', 5000)
->orderBy('created_at', 'desc')
->paginate(10);
// 多重搜索 (Multi-Search)
// Typesense 驱动也支持 Laravel Scout 的 multi-search 功能
$searchRequests = [
['collection' => 'products', 'q' => '手机'],
['collection' => 'articles', 'q' => '编程'],
];
// 具体的实现方式可能需要查看 Typesense PHP SDK 或 Scout 扩展的文档
// 例如:Product::search('')->searchMulti($searchRequests)->paginateRaw();核心优势与实际应用效果
通过集成 Typesense 和 Laravel Scout,你的应用将获得:
-
卓越的搜索性能: 告别数据库
LIKE查询的漫长等待,用户将体验到近乎实时的搜索响应。 - 智能的搜索结果: Typesense 内置的错别字容忍、相关性排序等功能,能显著提升搜索结果的准确性和用户满意度。
- 开发效率的提升: Laravel Scout 提供了简洁统一的 API,让你无需深入了解 Typesense 的底层细节,就能轻松实现复杂的搜索功能。模型的自动同步也大大减少了手动维护的负担。
- 强大的高级功能: 轻松实现分面搜索、同义词、地理空间搜索等高级功能,为用户提供更精细的搜索体验。
- 可伸缩性: Typesense 作为一个独立的搜索服务,可以根据需求独立扩展,与 Laravel 应用解耦,提升整体架构的弹性。
- 多租户支持: 利用 Typesense 的 Scoped API Keys 功能,可以轻松实现多租户环境下的数据隔离和权限控制,确保每个用户只能搜索到自己的数据。
总结
从最初的搜索性能瓶颈和复杂的集成困境,到如今通过 Typesense 和 Laravel Scout 提供的闪电般快速、智能且易于管理的全文本搜索体验,我的Laravel应用焕发了新的生机。这不仅极大地提升了用户满意度,也让开发团队从繁琐的搜索优化中解脱出来,专注于核心业务逻辑的开发。如果你也正在为 Laravel 应用的搜索性能而烦恼,那么 Typesense 与 Laravel Scout 的组合,绝对值得你一试!











