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

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/searchable ,但它更加灵活易于使用,更重要的是速度提高了四倍(甚至更高,实际依赖查询中附加的 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()

二楞徐的闲谈杂鱼

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

译文地址:https://laravel-china.org/topics/13041/e...

本帖已被设为精华帖!
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1

:+1:

1个月前

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!