benjamin-odiowa/laravel-searchy

Laravel Searchy 通过模糊搜索、基本字符串匹配、Levenshtein 距离等功能,让用户驱动的搜索变得简单高效。

v1.0.0 2020-05-07 02:47 UTC

This package is auto-updated.

Last update: 2024-09-07 13:35:38 UTC


README

数据库搜索变得简单

Searchy 是一个易于使用、轻量级、仅支持 MySQL 的 Laravel 扩展包,它可以让您在模型中的数据上运行用户驱动的搜索变得简单而有效。它使用伪模糊搜索和其他根据您启用的搜索驱动程序确定的加权机制。它不需要在您的服务器上安装其他软件(因此可能比专门的搜索程序慢一些),但可以在几分钟内设置和运行。

!! Laravel 4 !!}

寻找 Laravel 4 兼容的 Searchy?查看 1.0 分支 :)

https://github.com/TomLingham/Laravel-Searchy/tree/1.0

安装

在终端中运行 composer require benjamin-odiowa/laravel-searchy 以将包拉入您的 vendors 文件夹。

将服务提供者添加到 Laravel 的 ./config/app.php 文件中的 providers 数组中

TomLingham\Searchy\SearchyServiceProvider::class

如果您想快速访问它,请将别名添加到 Laravel 的 ./config/app.php 文件中的 aliases 数组中

'Searchy' => TomLingham\Searchy\Facades\Searchy::class

用法

添加使用 Searchy 命名空间

  use TomLingham\Searchy\Facades\Searchy;

要使用 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();

返回结果的数量限制

要限制您的结果,您可以使用 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_namelast_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

您可以在配置文件中设置用于搜索的默认驱动。目前(在此阶段)您的选项有:fuzzysimplelevenshtein

在运行搜索时,您也可以使用以下语法来覆盖这些方法

Searchy::driver('fuzzy')->users('name')->query('Batman')->get();

驱动程序

Searchy利用'驱动程序'来处理您指定的字段的各种匹配条件。

驱动程序是一组指定的'Matchers',根据特定的条件匹配字符串。

目前只有三个驱动程序:Simple、Fuzzy和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
];

匹配器

ExactMatcher

匹配精确字符串并应用高乘数,将任何精确匹配项带到顶部。

StartOfStringMatcher

匹配以搜索字符串开头的字符串。例如,搜索'hel'会匹配'Hello World'或'helping hand'。

AcronymMatcher

匹配类似于首字母缩略词的字符串,但不返回PascalCase匹配项。例如,搜索'fb'会匹配'foo bar'或'Fred Brown',但不会匹配'FreeBeer'。

ConsecutiveCharactersMatcher

匹配包含搜索字符串中所有字符的字符串,这些字符在字符串中的相对位置。它还计算字符串中匹配字符的百分比,并相应地应用乘数。

例如,搜索'fba'会匹配'Foo Bar'或'Afraid of bats',但不会匹配'fabulous'。

StartOfWordsMatcher

匹配每个单词的开头与搜索中每个单词的开头进行匹配。

例如,搜索'jo ta'会匹配'John Taylor'或'Joshua B. Takeshi'。

StudlyCaseMatcher

仅使用单词的首字母匹配PascalCase字符串。

例如,搜索'hp'会匹配'HtmlServiceProvider'或'HashParser',但不会匹配'hasProvider'。

InStringMatcher

匹配字符串中任何出现的字符串,且不区分大小写。

例如,搜索'smi'会匹配'John Smith'或'Smiley Face'。

TimesInStringMatcher

根据搜索字符串在字符串中出现的次数匹配字符串,然后为每次出现应用乘数。例如,搜索'tha'会匹配'I hope that that cat has caught that mouse'(3 x 乘数)或'Thanks, it was great!'(1 x 乘数)。

LevenshteinMatcher

Levenshtein驱动程序

扩展

驱动程序

自己制作搜索驱动器非常简单。只需创建一个扩展 TomLingham\Searchy\SearchDrivers\BaseSearchDriver 的类,并添加一个名为 $matchers 的属性,该属性为一个数组,以匹配器类作为键,每个匹配器的乘数作为值。您可以从中选择Searchy已包含的类,或者创建自己的类。

匹配器

要创建自己的匹配器,您可以创建一个扩展 TomLingham\Searchy\Matchers\BaseMatcher 的类,并且对于简单的匹配器,可以覆盖 formatQuery 方法以返回带有 % 通配符的字符串(在需要的位置)。对于更高级的扩展,您可能还需要覆盖 buildQuery 方法和其他方法。

贡献代码与报告错误

如果您想改进这里的代码,请随时提交拉取请求。

如果您发现任何错误,请在此处提交,我会尽快回复。请确保提供尽可能多的信息。