caneara / quest
为Laravel数据库查询提供伪模糊搜索的包。
Requires
- php: ^7.4|^8.0
Requires (Dev)
- orchestra/testbench: ^8.0
- phpunit/phpunit: ^10.0
README
此包可以在Laravel数据库和Eloquent查询中启用伪模糊搜索。由于其模式匹配方法,它仅支持MySQL或MariaDB,但我欢迎任何PR以启用对Postgres等数据库的支持。
此库的大部分内容基于Tom Lingham现在已废弃的Laravel Searchy包的出色工作。如果您对模糊搜索的工作原理感兴趣,请查看该项目的README。
安装
使用composer引入此包
composer require caneara/quest
用法
Quest自动注册一个包含多个宏的服务提供者。然后,这些宏附加到底层的Illuminate\Database\Query\Builder
类。
过滤结果
您可以通过调用whereFuzzy
方法执行模糊搜索。此方法接受两个参数。第一个是字段名。第二个是用于搜索的值,例如。
DB::table('users') ->whereFuzzy('name', 'jd') // matches John Doe ->first(); User::whereFuzzy('name', 'jd') // matches John Doe ->first();
您还可以通过链式调用多个whereFuzzy
方法在多个列之间执行模糊搜索
User::whereFuzzy('name', 'jd') // matches John Doe ->whereFuzzy('email', 'gm') // matches @gmail.com ->first();
您还可以通过调用orWhereFuzzy
方法在多个列之间执行搜索
User::whereFuzzy(function ($query) { $query->orWhereFuzzy('name', 'jd'); // matches John Doe $query->orWhereFuzzy('email', 'gm'); // matches @gmail.com })->first();
排序结果
当使用Quest时,将在您的搜索结果中包含一个'fuzzy_relevance_*'
列。星号(*)将替换为您正在搜索的字段名称,例如。
User::whereFuzzy('email', 'gm') // fuzzy_relevance_email
此列包含在将其应用于记录的每个模糊搜索模式匹配器之后所获得的分数。分数越高,记录与搜索词的匹配程度越高。
当然,您会想按分数排序结果,以便具有最高分数的记录首先出现。为了简化这一点,Quest包含一个orderByFuzzy
辅助方法,该方法包装相关的orderBy
子句
User::whereFuzzy('name', 'jd') ->orderByFuzzy('name') ->first(); // Equivalent to: User::whereFuzzy('name', 'jd') ->orderBy('fuzzy_relevance_name', 'desc') ->first();
如果您正在搜索多个字段,您可以将一个array
提供给orderByFuzzy
方法
User::whereFuzzy('name', 'jd') ->whereFuzzy('email', 'gm') ->orderByFuzzy(['name', 'email']) ->first(); // Equivalent to: User::whereFuzzy('name', 'jd') ->orderBy('fuzzy_relevance_name', 'desc') ->orderBy('fuzzy_relevance_email', 'desc') ->first();
应用最小阈值
当使用Quest时,将在_fuzzy_relevance_
列中为每个记录分配一个总分数。此分数表示为介于0和295之间的整数。
请注意,
fuzzy_relevance
分数不是除以列数。因此,如果两个字段完全匹配,它可能达到590。
您可以使用withMinimumRelevance()
方法强制执行最小分数以通过结果进行限制。设置更高的分数将返回较少,但可能更相关的结果。
// Before User::whereFuzzy('name', 'jd') ->having('_fuzzy_relevance_', '>', 70) ->first(); // After User::whereFuzzy('name', 'jd') ->withMinimumRelevance(70) ->first();
当使用orWhereFuzzy
时,将最小相关性作为可选的第三个参数包含
// Returns results which exceed 70 on the name column or 90 on the email column User::whereFuzzy(function ($query) { $query->orWhereFuzzy('name', 'jd', 70); $query->orWhereFuzzy('email', 'gm', 90); })->get();
性能(大型数据集)
当搜索大型表以仅确认是否存在匹配项时,移除排序和相关性检查将显着提高查询性能。为此,只需为whereFuzzy
或orWhereFuzzy
方法提供第三个参数为false
即可
DB::table('users') ->whereFuzzy('name', 'jd', false) ->orWhereFuzzy('name', 'gm', 0, false); ->first();
要调整相关性阈值,如果需要,您可以手动过滤相关性数据。
您还可以通过选择性地禁用一个或多个模式匹配器来进一步提高性能。只需提供要禁用的模式匹配器的array
即可,例如。
DB::table('users') ->whereFuzzy('name', 'jd', true, [ 'AcronymMatcher', 'StudlyCaseMatcher', ]); ->first();
以下模式匹配器可以包含在array
中
- ExactMatcher
- 字符串开始匹配器
- 缩写匹配器
- 连续字符匹配器
- 单词开始匹配器
- 大驼峰式匹配器
- 字符串内匹配器
- 字符串中出现次数匹配器
查看 /src/Matchers
目录,了解每个匹配器对查询的作用。
限制
无法使用带有 Quest 的 paginate
方法,因为在 Laravel 运行的二次查询中省略了相关性字段,以获取 LengthAwarePaginator
所需的记录数。然而,您可以使用 simplePaginate
方法而不会出现问题。在许多情况下,这仍然是一个更好的选择,尤其是在处理大量数据集时,因为当滚动大量页面时,paginate
方法会变得很慢。
贡献
感谢您考虑为 Quest 贡献。欢迎您提交包含改进的 PR,但如果它们本质上是重大的,请确保还包括测试或测试用例。
许可
MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件。