nicolaslopezj/searchable

Eloquent模型搜索特性。

1.13.0 2020-03-30 12:30 UTC

README

Searchable是一个用于Laravel 4.2+和Laravel 5.0的特质,它为Eloquent模型添加了简单的搜索功能。

Searchable允许你在表中执行搜索,并为表及其关系中的每个字段赋予优先级。

此功能不是为大规模搜索优化的,但有时你只需要使其简单(尽管它并不慢)。

安装

简单地将包添加到你的composer.json文件,并运行composer update

"nicolaslopezj/searchable": "1.*"

用法

将特质添加到你的模型和搜索规则中。

use Nicolaslopezj\Searchable\SearchableTrait;

class User extends \Eloquent
{
    use SearchableTrait;

    /**
     * Searchable rules.
     *
     * @var array
     */
    protected $searchable = [
        /**
         * Columns and their priority in search results.
         * Columns with higher values are more important.
         * Columns with equal values have equal importance.
         *
         * @var array
         */
        '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('Post');
    }

}

现在你可以搜索你的模型了。

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

// Search and get relations
// It will not get the relations if you don't do this
$users = User::search($query)
            ->with('posts')
            ->get();

分页搜索

与laravel默认查询一样简单

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

混合查询

搜索方法与任何Eloquent方法兼容。你可以做类似这样的事情

// Search only active users
$users = User::where('status', 'active')
            ->search($query)
            ->paginate(20);

自定义阈值

默认的接受相关性阈值是所有属性相关性的总和除以4。要更改此值,可以在search()中传递第二个参数,如下所示

// Search with lower relevance threshold
$users = User::where('status', 'active')
            ->search($query, 0)
            ->paginate(20);

上述代码将按相关性顺序返回所有用户。

全文搜索

默认情况下,多词搜索词会被分割,Searchable会分别搜索每个单词。相关性在优先排序匹配多个单词的匹配项中发挥作用。如果你想优先考虑包含多词搜索的匹配项(因此,不需要分割成单词),你可以通过将第三个值设置为true来启用全文搜索。示例

// Prioritize matches containing "John Doe" above matches containing only "John" or "Doe".
$users = User::search("John Doe", null, true)->get();

如果你明确只想搜索全文匹配,你可以通过将第四个参数设置为true来禁用多词分割。

// Do not include matches that only matched "John" OR "Doe".
$users = User::search("John Doe", null, true, true)->get();

它是如何工作的?

Searchable通过使用Laravel的Eloquent构建一个查询,该查询搜索你的模型。以下是一个示例查询

Eloquent模型

use Nicolaslopezj\Searchable\SearchableTrait;

class User extends \Eloquent
{
    use SearchableTrait;

    /**
     * Searchable rules.
     *
     * @var array
     */
    protected $searchable = [
        'columns' => [
            'first_name' => 10,
            'last_name' => 10,
            'bio' => 2,
            'email' => 5,
        ],
    ];

}

搜索

$search = User::search('Sed neque labore', null, true)->get();

结果

select `users`.*, 

-- If third parameter is set as true, it will check if the column starts with the search
-- if then it adds relevance * 30
-- this ensures that relevant results will be at top
(case when first_name LIKE 'Sed neque labore%' then 300 else 0 end) + 

-- For each column you specify makes 3 "ifs" containing 
-- each word of the search input and adds relevace to 
-- the row

-- The first checks if the column is equal to the word,
-- if then it adds relevance * 15
(case when first_name LIKE 'Sed' || first_name LIKE 'neque' || first_name LIKE 'labore' then 150 else 0 end) + 

-- The second checks if the column starts with the word,
-- if then it adds relevance * 5
(case when first_name LIKE 'Sed%' || first_name LIKE 'neque%' || first_name LIKE 'labore%' then 50 else 0 end) + 

-- The third checks if the column contains the word, 
-- if then it adds relevance * 1
(case when first_name LIKE '%Sed%' || first_name LIKE '%neque%' || first_name LIKE '%labore%' then 10 else 0 end) + 

-- Repeats with each column
(case when last_name LIKE 'Sed' || last_name LIKE 'neque' || last_name LIKE 'labore' then 150 else 0 end) + 
(case when last_name LIKE 'Sed%' || last_name LIKE 'neque%' || last_name LIKE 'labore%' then 50 else 0 end) +
(case when last_name LIKE '%Sed%' || last_name LIKE '%neque%' || last_name LIKE '%labore%' then 10 else 0 end) + 

(case when bio LIKE 'Sed' || bio LIKE 'neque' || bio LIKE 'labore' then 30 else 0 end) + 
(case when bio LIKE 'Sed%' || bio LIKE 'neque%' || bio LIKE 'labore%' then 10 else 0 end) + 
(case when bio LIKE '%Sed%' || bio LIKE '%neque%' || bio LIKE '%labore%' then 2 else 0 end) + 

(case when email LIKE 'Sed' || email LIKE 'neque' || email LIKE 'labore' then 75 else 0 end) + 
(case when email LIKE 'Sed%' || email LIKE 'neque%' || email LIKE 'labore%' then 25 else 0 end) + 
(case when email LIKE '%Sed%' || email LIKE '%neque%' || email LIKE '%labore%' then 5 else 0 end) 

as relevance 
from `users` 
group by `id` 

-- Selects only the rows that have more than
-- the sum of all attributes relevances and divided by 4
-- Ej: (20 + 5 + 2) / 4 = 6.75
having relevance > 6.75 

-- Orders the results by relevance
order by `relevance` desc

贡献

欢迎任何人为此做出贡献。Fork,做出你的更改,然后提交pull request。

Support via Gittip