invision-media / searchy
Laravel Searchy 使用户驱动的搜索变得简单,支持模糊搜索、基本字符串匹配、Levenshtein 距离等。这个分支允许你更改数据库连接。
Requires
- php: ^8.0
- illuminate/support: ^10.0 || ^11.0
Requires (Dev)
- graham-campbell/testbench: ^6.0
- phpunit/phpunit: ^10.0 || ^11.0
README
简化数据库搜索
Searchy 是一个易于使用、轻量级的 Laravel 包,只支持 MySQL,它可以使在模型数据上运行用户驱动的搜索变得简单和有效。它使用伪模糊搜索和其他加权机制,具体取决于你启用的搜索驱动程序。它不需要在你的服务器上安装其他软件(因此可能比专用搜索程序稍慢),但可以在几分钟内设置并投入使用。
!! Laravel 4 !!}
寻找 Laravel 4 兼容的 Searchy?查看 1.0 分支 :)
https://github.com/InvisionMedia/Laravel-Searchy/tree/1.0
安装
将 "invision-media/searchy" : "2.*" 添加到你的 composer.json 文件中的 require 部分
"require": { "laravel/framework": "5.*", "invision-media/searchy" : "2.*" }
在终端中运行 composer update 以将包拉入你的 vendors 文件夹。
将服务提供者添加到 Laravel 的 ./config/app.php 文件中的 providers 数组
InvisionMedia\Searchy\SearchyServiceProvider::class
如果你想在应用程序中快速访问它,可以将别名添加到 Laravel 的 ./config/app.php 文件中的 aliases 数组
'Searchy' => InvisionMedia\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() 方法。
这两个示例都返回包含搜索结果的对象数组。如果你想要对结果进行进一步的操作,可以使用 getQuery() 替代 get() 返回数据库查询对象的实例。
$users = Searchy::search('users')->fields('name', 'email')->query('John Smith') ->getQuery()->having('relevance', '>', 20)->get();
更改连接?
使用 ->connection() 方法设置它。
$users = Searchy::search('users')->connection('name_of_connection')->fields('name', 'email')->query('John Smith') ->getQuery()->having('relevance', '>', 20)->get();
结果返回限制
要限制结果,你可以使用 Laravel 内置的 DatabaseQuery Builder 方法,并链接其他方法来缩小结果。
// 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();
但是,这也会返回无论在此处输入什么都会返回的 relevance 别名列。
如何获取 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以覆盖设置,将配置复制到您的config文件夹中的searchy.php文件。
您可以在配置文件中设置用于搜索的默认驱动程序。当前选项有:fuzzy、simple和levenshtein。
当运行搜索时,您也可以使用以下语法覆盖这些方法
Searchy::driver('fuzzy')->users('name')->query('Batman')->get();
驱动程序
Searchy利用“驱动程序”来处理您指定的字段的匹配条件。
驱动程序是一组指定的“匹配器”,这些匹配器根据特定条件匹配字符串。
目前有三个驱动程序:简单、模糊和Levenshtein(实验性)。
简单搜索驱动程序
简单搜索驱动程序仅使用3个匹配器,每个匹配器都使用最适合我的测试环境的相关乘数。
protected $matchers = [ 'InvisionMedia\Searchy\Matchers\ExactMatcher' => 100, 'InvisionMedia\Searchy\Matchers\StartOfStringMatcher' => 50, 'InvisionMedia\Searchy\Matchers\InStringMatcher' => 30, ];
模糊搜索驱动程序
模糊搜索驱动程序是另一组匹配器,设置如下。乘数是我使用的,但您可以自由更改这些或创建具有相同匹配器的新驱动程序,并更改乘数以适应。
protected $matchers = [ 'InvisionMedia\Searchy\Matchers\ExactMatcher' => 100, 'InvisionMedia\Searchy\Matchers\StartOfStringMatcher' => 50, 'InvisionMedia\Searchy\Matchers\AcronymMatcher' => 42, 'InvisionMedia\Searchy\Matchers\ConsecutiveCharactersMatcher' => 40, 'InvisionMedia\Searchy\Matchers\StartOfWordsMatcher' => 35, 'InvisionMedia\Searchy\Matchers\StudlyCaseMatcher' => 32, 'InvisionMedia\Searchy\Matchers\InStringMatcher' => 30, 'InvisionMedia\Searchy\Matchers\TimesInStringMatcher' => 8, ];
Levenshtein搜索驱动程序(实验性)
Levenshtein搜索驱动程序使用Levenshtein距离来计算字符串之间的“距离”。它需要您在MySQL中有一个类似以下存储过程的存储过程:levenshtein(string1, string2)。在res文件夹中有一个包含合适函数的SQL文件 - 您可以自由使用这个文件。
protected $matchers = [ 'InvisionMedia\Searchy\Matchers\LevenshteinMatcher' => 100 ];
匹配器
ExactMatcher
匹配精确字符串,并应用高乘数将任何精确匹配项置于顶部。
StartOfStringMatcher
匹配以搜索字符串开头的字符串。例如,搜索“hel”将匹配“Hello World”或“helping hand”。
AcronymMatcher
匹配类似首字母缩略词的字符串,但不返回大写字母开头的匹配项。例如,搜索“fb”将匹配“foo bar”或“Fred Brown”,但不匹配“FreeBeer”。
ConsecutiveCharactersMatcher
匹配包含搜索字符串中所有字符的字符串,这些字符在字符串中相对定位。它还计算字符串中匹配的字符百分比,并相应地应用乘数。
例如,搜索“fba”将匹配“Foo Bar”或“Afraid of bats”,但不匹配“fabulous”。
StartOfWordsMatcher
匹配搜索中的每个单词的每个单词的起始位置。
例如,搜索“jo ta”将匹配“John Taylor”或“Joshua B. Takeshi”。
StudlyCaseMatcher
使用单词的第一个字母匹配大写字母开头的字符串。
例如,搜索“hp”将匹配“HtmlServiceProvider”或“HashParser”,但不匹配“hasProvider”。
InStringMatcher
匹配字符串中字符串的任何出现,并且是不区分大小写的。
例如,搜索“smi”将匹配“John Smith”或“Smiley Face”。
TimesInStringMatcher
根据搜索字符串在目标字符串中出现的次数进行匹配,然后对每个出现应用乘数。例如,搜索'tha'会匹配到"I hope that that cat has caught that mouse"(3倍乘数)或"Thanks, it was great!"(1倍乘数)。
LevenshteinMatcher
参见Levenshtein 驱动器
扩展
驱动程序
自己实现搜索驱动器非常简单。只需创建一个扩展InvisionMedia\Searchy\SearchDrivers\BaseSearchDriver的类,并添加一个名为$matchers的属性,其值为一个数组,其中包含匹配器类的名称作为键,以及每个匹配器的乘数作为值。您可以从中选择Searchy已包含的类,或者创建自己的类。
匹配器
要创建自己的匹配器,可以创建一个扩展InvisionMedia\Searchy\Matchers\BaseMatcher的类,并且(对于简单的匹配器)重写formatQuery方法以返回带有%通配符的字符串。对于更高级的扩展,您可能需要重写buildQuery方法和其他方法。
贡献代码及提交bug
如果您想改进这里提供的代码,请随意提交拉取请求。
如果您发现任何bug,请在这里提交,我会尽快响应。请确保提供尽可能多的信息。