onepage/searchable

Eloquent 模型搜索特性。

维护者

详细信息

github.com/zxc20033/searchable

来源

3.0.1 2020-02-17 06:26 UTC

README

Laravel 特性,为 Eloquent 模型添加 search 方法,该方法在模型中执行优先级搜索。

安装

$ composer require "jabbtech/searchable": "~3.0"

配置

导入 SearchableTrait 类并在模型中添加 $searchable 属性,指定要搜索的列及其在搜索结果中的优先级。值越高的列越重要

namespace App;

use Illuminate\Database\Eloquent\Model;
use Jabbtech\Searchable\SearchableTrait;

class User extends Model
{

    use SearchableTrait;

    protected $searchable = [
        'columns' => [
            'users.first_name' => 10,
            'users.last_name' => 10,
            'users.bio' => 2,
            'users.email' => 5,
            'posts.title' => 2,
            'posts.body' => 1,
        ],
        'joins' => [
            'posts' => ['users.id','posts.user_id'],
        ],
    ];

    public function posts()
    {
        return $this->hasMany('App\Post');
    }

}

基本用法

在查询构建实例上使用 search 方法将构建一个使用 Laravel Eloquent 搜索模型的查询。最基础的 search 调用需要一个参数,即搜索字符串。

$users = User::search($query)->get();

search 方法应与任何 Eloquent 方法兼容(SQL Server 除外)

$users = User::search($query)->with('posts')->get();

$users = User::search($query)->with('posts')->paginate(20);

$users = User::search($query)->where('status', 'active')->take(10)->get();

接受的关联度阈值

第二个参数是一个整数,可以改变默认的接受关联度阈值。默认情况下,接受关联度阈值是所有属性关联度之和除以 4。

按关联度顺序返回所有匹配搜索的用户

$users = User::search($query, 0)->get();

优先全文搜索

第三个参数是一个布尔值,优先匹配包含多词搜索的条目。默认情况下,多词搜索项会被分割,Searchable 会分别搜索每个单词。相关性在优先匹配包含多个单词的条目中发挥作用。

优先匹配包含 "John Doe" 的条目,高于仅包含 "John" 或 "Doe" 的条目

$users = User::search("John Doe", null, true)->get();

仅全文匹配

第四个参数是一个布尔值,允许仅搜索全文匹配。

排除仅匹配 "John" 或 "Doe" 的条目。

$users = User::search("John Doe", null, true, true)->get();

SQL Server

当与 SQL Server 一起使用时,search 方法支持大多数 Eloquent 方法,但有一些限制。

  • 强烈建议(在某些情况下是必需的)使用 select 方法
    • 要连接的表的列约束需要包含在 select 方法中
    • where 方法所需的列需要包含在 select 方法中
  • 大多数方法需要在 search 方法之前使用
    • join
    • leftJoin
    • crossJoin
    • where
  • search 方法之后包括 orderBy('relevance', 'desc')
$users = User::select('first_name', 'last_name')
    ->search($query)
    ->orderBy('relevance', 'desc')
    ->get();

$users = User::select(
        'users.id',
        'users.first_name',
        'users.last_name',
        'users.bio',
        'users.email',
        'users.status',
        'posts.title',
        'posts.body'
    )->leftJoin('posts', 'users.id', 'posts.user_id')
    ->where('users.status', 'active')
    ->serch($query)
    ->orderBy('relevance', 'desc')
    ->get();

它是如何工作的?

Searchable 会构建一个查询,通过 Laravel Eloquent 搜索模型。以下是一个示例查询

模型

protected $searchable = [
    'columns' => [
        'first_name' => 10,
        'last_name' => 5
    ],
];

搜索

$search = User::search('John Doe', null, true)->get();

结果

select * from (
    select `users`.*, max(
        (case when LOWER(`users`.`first_name`) LIKE 'John' then 150 else 0 end) + -- column equals word: priority * 15
        (case when LOWER(`users`.`first_name`) LIKE 'Doe' then 150 else 0 end) +
        (case when LOWER(`users`.`first_name`) LIKE 'John%' then 50 else 0 end) + -- column starts with word: priority * 5
        (case when LOWER(`users`.`first_name`) LIKE 'Doe%' then 50 else 0 end) +
        (case when LOWER(`users`.`first_name`) LIKE '%John%' then 10 else 0 end) + -- column contains word: priority * 1
        (case when LOWER(`users`.`first_name`) LIKE '%Doe%' then 10 else 0 end) +
        (case when LOWER(`users`.`first_name`) LIKE 'John Doe' then 500 else 0 end) + -- column matches full text: priority * 50
        (case when LOWER(`users`.`first_name`) LIKE '%John Doe%' then 300 else 0 end) + -- column contains full text: priority * 30
        (case when LOWER(`users`.`last_name`) LIKE 'John' then 75 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'Doe' then 75 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'John%' then 25 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'Doe%' then 25 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE '%John%' then 5 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE '%Doe%' then 5 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE 'John Doe' then 250 else 0 end) + 
        (case when LOWER(`users`.`last_name`) LIKE '%John Doe%' then 150 else 0 end)
    ) as relevance 
    from `users` 
    group by `users`.`id` 
    having relevance >= 3.75 -- sum of priorities (10 + 5) / 4
    order by `relevance` desc
) as `users`

致谢

贡献

欢迎任何人为其做出贡献。Fork,进行修改,然后提交拉取请求。