matchish / laravel-scout-elasticsearch

使用ElasticSearch和Laravel Scout在多个模型中进行搜索

8.0.0-alpha.2 2024-06-20 16:13 UTC

README

与乌克兰同在

UNITED24 启动了第一个针对地面机器人平台的活动筹集资金。机器人部队将拯救我们的军事人员和平民的生命。它们将成为物流设备、拖车、布雷车和排雷机器人,以及自毁机器人。它们将与人类并肩作战,为人类而战。

第一批机器人已经在战场上证明了它们的有效性。很快就会有更多。更多。

Support Ukraine

Import progress report

Build Status Coverage Total Downloads Latest Version License

对于Laravel框架 < 6.0.0,请使用3.x分支

该包为将ElasticSearch集成到您的Laravel应用程序中提供了完美的起点。它经过精心设计,以简化在Laravel框架中使用ElasticSearch。

它建立在最新版本的Laravel Scout之上,这是官方的Laravel搜索包。使用此包,您可以自由利用Laravel Scout的所有出色功能,同时利用ElasticSearch的完整搜索体验。

如果您需要任何帮助,请通过stack overflow提问,这是首选和推荐的支持提问方式。

💕 特点

如果您喜欢这个包,请别忘了⭐它。🙏

⚠️ 要求

  • PHP版本 >= 8.0
  • Laravel框架版本 >= 8.0.0

🚀 安装

使用composer安装包

composer require matchish/laravel-scout-elasticsearch

设置环境变量

SCOUT_DRIVER=Matchish\ScoutElasticSearch\Engines\ElasticSearchEngine

该包使用官方包中的\ElasticSearch\Client,但不会尝试对其进行配置,超出连接配置之外,因此您可以在应用程序服务提供程序中自由进行配置。但如果你现在不想这样做,你可以使用包中的Matchish\ElasticSearchServiceProvider
注册提供程序,将其添加到config/app.php

'providers' => [
    // Other Service Providers

    \Matchish\ScoutElasticSearch\ElasticSearchServiceProvider::class
],

设置环境变量ELASTICSEARCH_HOST

ELASTICSEARCH_HOST=host:port

或使用逗号作为分隔符以分隔额外的节点

ELASTICSEARCH_HOST=host:port,host:port

您可以通过在您的环境中设置以下内容来禁用SSL验证

ELASTICSEARCH_SSL_VERIFICATION=false

并发布elasticsearch配置示例
php artisan vendor:publish --tag config

💡 用法

注意:此包增加了对Laravel Scout的功能,因此我们建议您首先阅读Scout文档。Scout的文档可以在Laravel网站上找到。

索引 设置映射

当我们创建索引时,定义映射非常重要——不恰当的初步定义和映射可能会导致搜索结果错误。

为了定义索引的映射或设置,设置正确的配置值。

例如,如果方法 searchableAs 返回 products 字符串

映射的配置键应为
elasticsearch.indices.mappings.products
或者您可以使用配置键 elasticsearch.indices.mappings.default 指定默认映射

同样,您可以定义设置

对于索引 products,它将是
elasticsearch.indices.settings.products

而对于默认设置
elasticsearch.indices.settings.default

预加载

为了加快导入速度,您可以使用全局范围在导入时预加载关系。

您应该在服务提供者中配置 ImportSourceFactory(在 register 方法中)

use Matchish\ScoutElasticSearch\Searchable\ImportSourceFactory;
...
public function register(): void
{
$this->app->bind(ImportSourceFactory::class, MyImportSourceFactory::class);

以下是 MyImportSourceFactory 的一个示例

namespace Matchish\ScoutElasticSearch\Searchable;

final class MyImportSourceFactory implements ImportSourceFactory
{
    public static function from(string $className): ImportSource
    {
        //Add all required scopes
        return new DefaultImportSource($className, [new WithCommentsScope()]);
    }
}

class WithCommentsScope implements Scope {

    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param \Illuminate\Database\Eloquent\Builder $builder
     * @param \Illuminate\Database\Eloquent\Model $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->with('comments');
    }
}

当您通过利用 Laravel Scout 提供的 toSearchableArray 方法保存模型时,也可以自定义您的索引数据

示例

class Product extends Model 
{
    use Searchable;

    /**
     * Get the indexable data array for the model.
     *
     * @return array
     */
    public function toSearchableArray()
    {
        $with = [
            'categories',
        ];

        $this->loadMissing($with);

        return $this->toArray();
    }
}

此示例将确保在保存模型时始终加载类别关系。

零停机重新导入

在生产环境中工作,为了在重新导入数据时保持现有的搜索体验,您也可以使用 scout:import Artisan 命令

php artisan scout:import

该命令将创建一个新的临时索引,将所有模型导入其中,然后切换到该索引并删除旧索引。

搜索

为了与原始 scout 包完全兼容,此包不添加新方法。
那么我们如何构建复杂的查询呢?有两种方法。
默认情况下,当您将查询传递给 search 方法时,引擎将构建一个 query_string 查询,因此您可以构建这样的查询

Product::search('(title:this OR description:this) AND (title:that OR description:that)')

如果这不足以满足您的需求,您可以将回调传递给查询构建器

$results = Product::search('zonga', function(\Elastic\Elasticsearch\Client $client, $body) {

    $minPriceAggregation = new MinAggregation('min_price');
    $minPriceAggregation->setField('price');
    
    $maxPriceAggregation = new MaxAggregation('max_price');
    $maxPriceAggregation->setField('price');
    
    $brandTermAggregation = new TermsAggregation('brand');
    $brandTermAggregation->setField('brand');

    $body->addAggregation($minPriceAggregation);
    $body->addAggregation($brandTermAggregation);
    
    return $client->search(['index' => 'products', 'body' => $body->toArray()])->asArray();
})->raw();

注意:回调函数将获得两个参数。第一个是 $client,它是来自 elasticsearch/elasticsearch 包的 \Elastic\Elasticsearch\Client 类的对象。第二个是 $body,它是来自 ongr/elasticsearch-dsl 包的 \ONGR\ElasticsearchDSL\Search 对象。所以,如您在上面的示例中所见,$client->search(....) 方法将返回一个 \Elastic\Elasticsearch\Response\Elasticsearch 对象。您需要使用 asArray() 方法来获取数组结果。否则,HitsIteratorAggregate 类将引发错误。您可以在 这里 查看问题。

条件

Scout 只支持 3 个条件:->where(column, value)(严格相等)、->whereIn(column, array)->whereNotIn(column, array)

Product::search('(title:this OR description:this) AND (title:that OR description:that)')
    ->where('price', 100)
    ->whereIn('type', ['used', 'like new'])
    ->whereNotIn('type', ['new', 'refurbished']);

Scout 不支持任何运算符,但您可以将 ElasticSearch 术语(如 RangeQuery)作为值传递给 ->where()

use ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;

Product::search('(title:this OR description:this) AND (title:that OR description:that)')
    ->where('price', new RangeQuery('price', [
        RangeQuery::GTE => 100,
        RangeQuery::LTE => 1000,
    ]);

如果您只想使用 RangeQuery 进行搜索而不使用任何 query_string,则可以直接调用 search() 方法并将参数留空。

use ONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;

Product::search()
    ->where('price', new RangeQuery('price', [
        RangeQuery::GTE => 100,
    ]);

ElasticSearch 术语的完整列表在 vendor/handcraftedinthealps/elasticsearch-dsl/src/Query/TermLevel 中。

在多个模型中进行搜索

您可以使用MixedSearch类来实现,只需将索引名称用逗号分隔后传递给within方法。

MixedSearch::search('title:Barcelona or to:Barcelona')
    within(implode(',', [
        (new Ticket())->searchableAs(),
        (new Book())->searchableAs(),
    ]))
->get();

在这个例子中,您将获得包含TicketBook模型的集合,其中票的到达城市或书籍标题为Barcelona

处理结果

通常,您的响应不是模型的集合,而是聚合或带有高亮的模型等。在这种情况下,您需要实现自己的HitsIteratorAggregate实现,并将其绑定到服务提供者中。

这是一个例子

🆓 许可证

Scout ElasticSearch是一个开源软件,遵循MIT许可协议MIT license