todayqq / searchy
Laravel Searchy通过模糊搜索、基本字符串匹配、Levenshtein距离等,使用户驱动的搜索变得简单易用。
Requires
- php: >=7.4.0
- illuminate/support: ^4.2|^5|^6|^7|^8|^9
Requires (Dev)
- graham-campbell/testbench: ^3.4 || ^4.0 || ^5.0
- phpunit/phpunit: ^4.8 || ^5.7 || ^6.3 || ^7.0 || ^8.0
README
轻松实现数据库搜索
Searchy是一个轻量级、仅支持MySQL、易于使用的Laravel扩展包,它可以让在模型数据上运行用户驱动的搜索变得简单而有效。它根据您启用的搜索驱动程序使用伪模糊搜索和其他加权机制。它不需要在服务器上安装其他软件(因此可能比专用搜索程序慢一些),但可以在几分钟内设置并运行。
支持PHP 8.0版本
安装
将 "todayqq/searchy" : "3.1" 添加到您的 composer.json 文件中的 require 部分
"require": { "laravel/framework": "5.*", "todayqq/searchy" : "3.1" }
在终端中运行 composer update 以将包拉入您的 vendors 文件夹。
将服务提供者添加到 Laravel 的 ./config/app.php 文件中的 providers 数组
TomLingham\Searchy\SearchyServiceProvider::class
如果您希望在应用程序中快速访问它,请将别名添加到 Laravel 的 ./config/app.php 文件中的 aliases 数组
'Searchy' => TomLingham\Searchy\Facades\Searchy::class
使用方法
要使用 Searchy,您可以利用魔法方法。
如果您正在搜索 users 表中用户的名称和电子邮件列/字段,您会运行,例如
$users = Searchy::users('name', 'email')->query('John Smith')->get();
您也可以这样写
$users = Searchy::search('users')->fields('name', 'email')->query('John Smith')->get();
在这种情况下,将您想要搜索的列传递给 fields() 方法。
这两个示例都返回包含搜索结果的 Object 数组。如果您想对结果进行进一步操作,可以使用 getQuery() 代替 get() 返回数据库查询对象实例。
$users = Searchy::search('users')->fields('name', 'email')->query('John Smith') ->getQuery()->having('relevance', '>', 20)->get();
返回结果的数量限制
要限制结果,您可以使用 Laravel 内置的数据库查询构建器方法,并通过链式调用进一步方法来缩小结果。
// Only get the top 10 results $users = Searchy::search('users')->fields('name', 'email')->query('John Smith') ->getQuery()->limit(10)->get();
搜索多个列
您还可以将多个参数添加到要搜索的字段/列列表中。
例如,如果您想搜索用户的名称、电子邮件地址和用户名,您可能会运行
$users = Searchy::users('name', 'email', 'username')->query('John Smith')->get();
如果您需要动态构建您的表格列表,您也可以将字段数组作为第一个参数传递(所有其他后续参数将被忽略)
$users = Searchy::users(['name', 'email', 'username'])->query('John Smith')->get();
搜索连接/连接的列
有时您可能想利用连接列的搜索。例如,在一个 first_name 和 last_name 字段上,但您只想运行一个查询。为此,可以使用双冒号分隔列
$users = Searchy::users('first_name::last_name')->query('John Smith')->get();
软删除的记录
默认情况下,软删除将不会包含在您的结果中。但是,如果您想包括软删除的记录,您可以在指定表和字段后添加 withTrashed()。
Searchy::users('name')->withTrashed()->query('Batman')->get();
仅返回特定列
您可以在搜索中指定要返回哪些列
$users = Searchy::users('first_name::last_name')->query('John Smith')->select('first_name')->get(); // Or you can swap those around... $users = Searchy::users('first_name::last_name')->select('first_name')->query('John Smith')->get();
然而,这也会返回无论在此处输入什么都会出现的相关性别名列。
如何获取 Laravel Eloquent 集合
将搜索结果转换为 Laravel Eloquent 模型集合不在本项目范围内。然而,使用 Eloquent 的 hydrate() 方法在不必要地击中数据库的情况下轻松实现这一点。
\App\User::hydrate(Searchy::users('name', 'email')->query('Andrew')->get());
此方法从纯数组创建模型集合。这正是我们的情况,因为 Searchy 的结果以数组的形式提供,并且使用 hydrate 我们将它们转换为 User 模型的实例。
Unicode 字符支持
如果您因为搜索数据中有 Unicode 字符而导致返回结果有问题,可以使用 FuzzySearchUnicodeDriver。
请注意:在将字符串插入原始 MySQL 语句之前,FuzzySearchUnicodeDriver 不会对传入的字符串进行清理。您必须首先自己清理字符串,否则可能会使您的应用程序面临 SQL 注入攻击。已被警告。
使用方法:首先按照说明发布您的配置文件(php artisan vendor:publish),并将默认驱动从 fuzzy 更改为 ufuzzy。
return [ 'default' => 'ufuzzy', ... ]
配置
您可以将配置文件发布到您的 app 目录,并通过运行 php artisan vendor:publish 覆盖设置,将配置复制到您的配置文件夹作为 searchy.php。
您可以在配置文件中设置用于搜索的默认驱动。目前您的选项是:fuzzy、simple 和 levenshtein。
您还可以使用以下语法在搜索时覆盖这些方法
Searchy::driver('fuzzy')->users('name')->query('Batman')->get();
驱动程序
Searchy 利用 '驱动程序' 来处理您指定的字段的多种条件。
驱动程序简单地是一个指定的 '匹配器' 组,它根据特定条件匹配字符串。
目前只有三个驱动程序:简单、模糊和 Levenshtein(实验性)。
简单搜索驱动程序
简单搜索驱动程序仅使用 3 个匹配器,每个匹配器都有最适合我的测试环境的相关乘数。
protected $matchers = [ 'TomLingham\Searchy\Matchers\ExactMatcher' => 100, 'TomLingham\Searchy\Matchers\StartOfStringMatcher' => 50, 'TomLingham\Searchy\Matchers\InStringMatcher' => 30, ];
模糊搜索驱动程序
模糊搜索驱动程序是另一组按以下方式设置的匹配器。乘数是我使用的,但您可以根据需要更改这些或创建自己的驱动程序,使用相同的匹配器并更改乘数以适应。
protected $matchers = [ 'TomLingham\Searchy\Matchers\ExactMatcher' => 100, 'TomLingham\Searchy\Matchers\StartOfStringMatcher' => 50, 'TomLingham\Searchy\Matchers\AcronymMatcher' => 42, 'TomLingham\Searchy\Matchers\ConsecutiveCharactersMatcher' => 40, 'TomLingham\Searchy\Matchers\StartOfWordsMatcher' => 35, 'TomLingham\Searchy\Matchers\StudlyCaseMatcher' => 32, 'TomLingham\Searchy\Matchers\InStringMatcher' => 30, 'TomLingham\Searchy\Matchers\TimesInStringMatcher' => 8, ];
Levenshtein 搜索驱动程序(实验性)
Levenshtein 搜索驱动程序使用 Levenshtein 距离来计算字符串之间的 '距离'。它要求您在 MySQL 中有一个类似以下的存储过程:levenshtein(string1, string2)。在 res 文件夹中有一个合适的函数的 SQL 文件 - 欢迎使用。
protected $matchers = [ 'TomLingham\Searchy\Matchers\LevenshteinMatcher' => 100 ];
匹配器
精确匹配器
匹配精确字符串,并应用高倍数系数,将任何精确匹配结果提升到顶部。
字符串开头匹配器
匹配以搜索字符串开头的字符串。例如,搜索 'hel' 将匹配 'Hello World' 或 'helping hand'。
首字母缩写匹配器
匹配首字母缩写字符串的匹配,但不返回首字母大写的匹配结果。例如,搜索 'fb' 将匹配 'foo bar' 或 'Fred Brown',但不匹配 'FreeBeer'。
连续字符匹配器
匹配包含搜索字符串中所有字符的字符串,并且这些字符在字符串中相对位置。它还会计算字符串中匹配字符的百分比,并相应地应用系数。
例如,搜索 'fba' 将匹配 'Foo Bar' 或 'Afraid of bats',但不匹配 'fabulous'。
单词开头匹配器
匹配搜索中的每个单词与每个单词的开头。
例如,搜索 'jo ta' 将匹配 'John Taylor' 或 'Joshua B. Takeshi'。
首字母大写匹配器
使用单词的首字母匹配首字母大写的字符串。
例如,搜索 'hp' 将匹配 'HtmlServiceProvider' 或 'HashParser',但不匹配 'hasProvider'。
字符串内匹配器
对字符串中任意位置的字符串进行匹配,且不区分大小写。
例如,搜索 'smi' 将匹配 'John Smith' 或 'Smiley Face'。
字符串中出现次数匹配器
根据搜索字符串在字符串中出现的次数进行匹配,然后为每个出现应用系数。例如,搜索 'tha' 将匹配 'I hope that that cat has caught that mouse'(3 x 系数)或 'Thanks, it was great!'(1 x 系数)。
Levenshtein 匹配器
参见 Levenshtein 驱动程序
扩展
驱动程序
自己编写搜索驱动程序非常简单。只需创建一个扩展 TomLingham\Searchy\SearchDrivers\BaseSearchDriver 的类,并添加一个名为 $matchers 的属性,其值为一个数组,其中包含匹配器类的键和每个匹配器的系数。您可以选择与 Searchy 一起包含的类,也可以创建自己的类。
匹配器
要创建自己的匹配器,您可以创建一个扩展 TomLingham\Searchy\Matchers\BaseMatcher 的类,并且(对于简单的匹配器)重写 formatQuery 方法以返回一个字符串,该字符串在所需位置带有 % 通配符。对于更高级的扩展,您可能需要重写 buildQuery 方法和其他方法。
贡献 & 报告错误
如果您想改进这里的代码,请随时提交拉取请求。
如果您发现任何错误,请在此处提交,我会尽快回复。请确保提供尽可能多的信息。