minh7721 / laravel-scout-elasticsearch
使用ElasticSearch和Laravel Scout在多个模型中进行搜索
Requires
- php: ^8.0.12|^8.1
- elasticsearch/elasticsearch: ^8.0
- laravel/scout: ^8.0|^9.0|^10.0
- minh7721/elasticsearch-dsl: ^8.0.3
- roave/better-reflection: ^4.3|^5.0|^6.18
Requires (Dev)
- laravel/legacy-factories: ^1.0
- nunomaduro/larastan: ^2.4
- orchestra/testbench: ^6.17|^7.0|^8.0
- php-http/guzzle7-adapter: ^1.0
- phpunit/phpunit: ^9.4.0
This package is auto-updated.
Last update: 2024-09-09 10:38:08 UTC
README
对于Laravel框架 < 6.0.0,请使用3.x分支
该包为将ElasticSearch集成到您的Laravel应用程序提供了完美的起点。它经过精心设计,以简化在Laravel框架中使用ElasticSearch。
它建立在最新版本的Laravel Scout之上,这是官方的Laravel搜索包。使用此包,您可以充分利用Laravel Scout的所有优秀功能,同时利用ElasticSearch的完整搜索体验。
如果您需要任何帮助,请通过stack overflow提出支持问题,这是首选和推荐的方式。
💕 特点
如果喜欢这个包,别忘了⭐它。🙏
- Laravel Scout 10.x 支持
- Laravel Nova 支持
- 搜索多个模型
- 零停机时间重新导入 - 在生产环境中导入数据非常容易。
- 预加载关系 - 加快导入速度。
- 一次性导入所有可搜索的模型。
- 为每个模型提供完全可配置的映射。
- 在查询中充分利用ElasticSearch的全部功能。
⚠️ 要求
- 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
并发布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 通过 Searchable
特性提供的 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:import2
Artisan 命令
php artisan scout:import2
该命令创建一个新的临时索引,将所有模型导入到其中,然后切换到索引并删除旧索引。
搜索
为了与原始 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();
在此示例中,您将获得包含 Ticket
和 Book
模型的集合,其中 ticket 的到达城市或 book 的标题为 Barcelona
处理结果
通常,您的响应不是模型集合,而是聚合或带有高亮的模型等。在这种情况下,您需要实现自己的 HitsIteratorAggregate
实现,并将其绑定到服务提供者中
🆓 许可证
Scout ElasticSearch 是一个开源软件,许可协议为 MIT 许可协议。