使用 Laravel Search 扩展包基于 Elasticsearch、 Algolia 以及 ZendSearch 实现全文搜索功能

logo-elastic
Laravel Search扩展包为不同的全文搜索服务提供了统一的API,当前支持的搜索服务包括ElasticSearchAlgoliaZendSearch

1、安装

我们通过Composer来安装这个依赖包:

composer require mmanos/laravel-search dev-master

安装完成后,在config/app.php中注册服务提供者到providers数组:

'providers' => array(
    // ...
    Mmanos\Search\SearchServiceProvider::class,
)

然后添加门面到aliases数组:

'aliases' => array(
    // ...
    'Search' => Mmanos\Search\Facade::class,
)

2、配置

发布扩展包自带的配置文件到应用配置目录下:

php artisan vendor:publish

依赖

以下是相关搜索驱动需要的依赖包:

默认索引

该扩展包提供了简洁的语法来处理默认索引:编辑配置文件中的default_index来修改这个值。

3、索引操作

使用这个扩展包处理索引非常简单,只需要为文档提供一个唯一的标识符并指定一个关联数组到该索引即可。

如果你首次访问这个索引不存在,则该索引会自动创建。

索引一个文档

添加一个id为1的默认索引到文档:

Search::insert(1, array(
    'title' => 'My title',
    'content' => 'The quick brown fox...',
    'status' => 'published',
));

注:id可能是一个字符串或整型数据,这个id可用于删除记录也可以在搜索结果中返回。

在文档中存储额外的参数

你可以在文档中存储额外的参数以便在后续搜索结果中获取到,这个特性在引用时间戳或其他标识记录时很有用。

Search::insert(
    "post-1",
    array(
        'title' => 'My title',
        'content' => 'The quick brown fox...',
        'status' => 'published',
    ),
    array(
        'created_at' => time(),
        'creator_id' => 5,
    )
);

注:额外参数并没有被索引但是存储在索引中以便后续获取到。

删除一个文档

可以从索引中通过id删除一个文档:

Search::delete(1);

删除一个索引

Search::deleteIndex();

4、搜索操作

搜索文档

搜索默认索引对应文档中content包含“fox”的所有记录:

$results = Search::search('content', 'fox')->get();

搜索多个字段

$results = Search::search(array('title', 'content'), 'fox')->get();

搜索所有字段

$results = Search::search(null, 'fox')->get();

执行模糊搜索

$results = Search::search('content', 'update', array('fuzzy'=>true))->get();

注:你也可以传递一个介于0和1之间的数值给fuzzy参数,这个数值越接近1表示越相似,默认是0.5

查询中使用过滤器

你也可以在查询中使用过滤器,过滤器尝试匹配你指定的整个语句:

$results = Search::search('content', 'fox')
    ->where('status', 'published')
    ->get();

注:如果指定值包含多个单词的话过滤器并不能保证精准匹配整个字段值。

(Geo-Search)位置搜索

有些驱动支持基于位置的搜索:

$results = Search::search('content', 'fox')
    ->whereLocation(36.16781, -96.023561, 10000)
    ->get();

上述参数分别表示纬度、经度和距离(米)。

注:目前只有algolia驱动支持基于位置的搜索,此外需要确保每个索引记录包含本地信息,如:_geoloc => ['lat' => 1.23, 'lng' => 1.23]

限制结果集

$results = Search::search('content', 'fox')
    ->where('status', 'published')
    ->limit(10) // Limit 10
    ->get();

$results = Search::search('content', 'fox')
    ->where('status', 'published')
    ->limit(10, 30) // Limit 10, offset 30
    ->get();

对结果集进行分页

$paginator = Search::search('content', 'fox')->paginate(15);

限制返回的字段数

$results = Search::select('id', 'created_at')
    ->search('content', 'fox')
    ->get();

多个搜索和过滤器链

$results = Search::select('id', 'created_at')
    ->where('title', 'My title')
    ->where('status', 'published')
    ->search('content', 'fox')
    ->search('content', 'quick')
    ->limit(10)
    ->get();

删除所有匹配某个查询的文档

Search::search('content', 'fox')->delete();

5、处理多个索引

如果你需要处理多个索引可以在指定索引名后像单个索引一样使用上述方法。添加文档到名为“posts”的索引:

Search::index('posts')->insert(1, array(
    'title' => 'My title',
    'content' => 'The quick brown fox...',
    'status' => 'published',
));

查询content包含foxstatuspublished的posts:

$results = Search::index('posts')->search('content', 'fox')
    ->where('status', 'published')
    ->get();

从posts中删除id为1的文档:

Search::index('posts')->delete(1);

删除所有posts:

Search::index('posts')->deleteIndex();

6、高级查询回调

如果你想要对查询有更多控制,可以在所有条件添加到查询后在查询执行之前添加一个回调函数:

$results = Search::index('posts')->select('id', 'created_at')
    ->search('content', 'fox')
    ->addCallback(function ($query) {
        // Make changes to $query...
        return $query;
    })
    ->get();

由于每个驱动都有其自己的$query对象/数组,你可以只为某一个驱动执行回调:

$results = Search::index('posts')->select('id', 'created_at')
    ->search('content', 'fox')
    ->addCallback(function ($query) {
        // Adjust pagination for an elasticsearch query array.
        $query['from'] = 0;
        $query['size'] = 20;
        return $query;
    }, 'elasticsearch')
    ->get();

注:你也可以传递一个驱动数组作为第二个参数。

学院君

学院君 has written 554 articles

资深PHP工程师,Laravel学院院长