[扩展推荐] 为 Laravel Eloquent 提供搜索支持

file

在这个系列的第一部分 https://github.com/jarektkaczyk/eloquence – 这个包允许以更加简单的管理方式来使用 Eloquent 模型 - 接下来我将向你介绍 Builder 类的可搜索特性。

假设一个拥有简单好友关系的应用:

// 用户模型

// 多对多关联
public function friends()
{
   return $this->belongsToMany(static::class, 'friends', 'user_id', 'friend_id');
}

// 1-1 relation
public function profile()
{
   return $this->hasOne(Profile::class);
}

一个简单的基于用户为核心的表 usersfriends 表作为好友多对多关联表,这对于演示来说是足够的。 在用户表中我们只存储邮箱和用户名,在用户简介表 profiles 中存储用户的真实数据比如用户的名字、姓氏(first_name, last_name)等。

显然密码、时间戳等其他相关的字段不是我们现在应该关心的内容。

现在, 为了找到一个人,我们可以使用几个字段的组合:users.username, users.email, profiles.first_name, profiles.last_name, friends.first_name, friends.last_name

以下是原始的 Eloquent 做法::

$name = strtolower(Input::get('query'));

$matchingUsers = User::where(function ($q) use ($name) {
      $q->where('email', 'like', '%'.str_replace(' ', '', $name).'%')
        ->orWhere('username', 'like', "%{$name}%")
        ->orWhereHas('profile', function ($q) {
          $q->where(function ($q) {
            $q->where('first_name', 'like', "%{$name}%")
              ->orWhere('last_name', 'like', "%{$name}%");
        });
      });
    })->get();

它很简单但是缺乏关键的搜索元素 - 相关性分数,也使得搜索朋友行不通。

像这样的查询返回分数需要一些计算,但是很显现,我们没有必要再创造一个谷歌哈?

不过,理论上我们喜欢这样的方式:

$name = 'john doe';

$matchingUsers = User::search($name, [
    'profile.last_name' => 20,
    'email' => 10,
    'username' => 10,
    'profile.first_name' => 5,
    'friends.username' => 2,
    'friends.email' => 2,
    'friends.profile.first_name' => 1,
    'friends.profile.last_name' => 1,
  ])->get()

//如果这些字段不轻易变动,那么在模型中定义下它们:
protected $searchableColumns = [
    'profile.last_name' => 20,
    'email' => 10,
    'username' => 10,
    'profile.first_name' => 5,
    'friends.username' => 2,
    'friends.email' => 2,
    'friends.profile.first_name' => 1,
    'friends.profile.last_name' => 1,
];

//然后简单地调用
User::search($name)->get()

这些列都是定义在模型中的普通关联映射,只需要这些。每个列对应的数字是它的权重,我们通过分数来定义它们的重要性。

Eloquence\Builder 这个包的工作原理是自动地加入关联表格,添加一些履行条款并且通过关联搜索排序结果。

这个功能和得分算法的创意都是基于这个包 https://github.com/nicolaslopezj/searchabl... ,但它更加灵活易于使用,更重要的是速度提高了四倍(甚至更高,实际依赖查询中附加的 where 子句)

通过下面几个例子,你可以知道怎么使用这种方式来搜索。这个搜索方式同样会提升搜索速度 – 全文搜索不会使用索引,所以在大表或者多个连接表进行搜索时会变的很慢。

假如你的需求是这样,你想禁用掉全文索引,并且使用右侧通配符 ( word *) 来代替全文索引。

// 全文搜索 + 指定字段搜索权重:
User::search('john doe', ['email' => 10, 'profile.name' => 20, 'friends.profile.name' => 5])->take(10)->get()

// 全文搜索默认的字段:
User::search('"going to LA"')->get()

// 指定搜索
User::search('"going to LA"', $fulltext = false)->get()

// 通配符搜索
User::search(['going to *', '*LA*', '*NY*'], $fulltext = false)->get()
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://softonsofa.com/laravel-searchabl...

译文地址:https://learnku.com/laravel/t/13041/exte...

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 2

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!