- Notifications
You must be signed in to change notification settings - Fork0
Search among multiple models with ElasticSearch and Laravel Scout
License
m-lotze/laravel-scout-elasticsearch
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
UNITED24 launches the first fundraiser towards terrestrial robotic platforms. Squads of robots will save the lives of our military and civilians. They will become logistics devices, tow trucks, minelayers and deminers, as well as self-destructive robots. They will fight alongside people and for people.
The first robots are already proving their effectiveness on the battlefield. There will be more of them soon. Many more.

For Laravel Framework < 6.0.0 use3.x branch
The package provides the perfect starting point to integrateElasticSearch into your Laravel application. It is carefully crafted to simplify the usageof ElasticSearch within theLaravel Framework.
It’s built on top of the latest release ofLaravel Scout, the official Laravel searchpackage. Using this package, you are free to take advantage of all of Laravel Scout’sgreat features, and at the same time leverage the complete set of ElasticSearch’s search experience.
If you need any help,stack overflow is the preferred and recommended way to ask support questions.
Don't forget to ⭐ the package if you like it. 🙏
- Laravel Scout 10.x support
- Laravel Nova support
- Search amongst multiple models
- Zero downtime reimport - it’s a breeze to import data in production.
- Eager load relations - speed up your import.
- Parallel import to make your import as fast as possible (inalpha version for now)
- Import all searchable models at once.
- A fully configurable mapping for each model.
- Full power of ElasticSearch in your queries.
- PHP version >= 8.0
- Laravel Framework version >= 8.0.0
| Elasticsearch version | ElasticsearchDSL version |
|---|---|
| >= 8.0 | >= 8.0.0 |
| >= 7.0 | >= 3.0.0 |
| >= 6.0, < 7.0 | < 3.0.0 |
Use composer to install the package:
composer require matchish/laravel-scout-elasticsearch
Set env variables
SCOUT_DRIVER=Matchish\ScoutElasticSearch\Engines\ElasticSearchEngineThe package uses\ElasticSearch\Client from official package, but does not try to configure itbeyond connection configuration, so feel free do it in your app service provider.But if you don't want to do it right now,you can useMatchish\ElasticSearchServiceProvider from the package.
Register the provider, adding toconfig/app.php
'providers' => [// Other Service Providers \Matchish\ScoutElasticSearch\ElasticSearchServiceProvider::class],
SetELASTICSEARCH_HOST env variable
ELASTICSEARCH_HOST=host:portor use commas as separator for additional nodes
ELASTICSEARCH_HOST=host:port,host:portYou can disable SSL verification by setting the following in your env
ELASTICSEARCH_SSL_VERIFICATION=falseAnd publish config example for elasticsearchphp artisan vendor:publish --tag config
Note: This package adds functionalities toLaravel Scout, and for this reason, we encourage you toread the Scout documentation first. Documentation for Scout can be found on theLaravel website.
It is very important to define the mapping when we create an index — an inappropriate preliminary definition and mapping may result in the wrong search results.
To define mappings or settings for index, set config with right value.
For example if methodsearchableAs returnsproducts string
Config key for mappings should beelasticsearch.indices.mappings.products
Or you you can specify default mappings with config keyelasticsearch.indices.mappings.default
Same way you can define settings
For indexproducts it will beelasticsearch.indices.settings.products
And for default settingselasticsearch.indices.settings.default
To speed up import you can eager load relations on import using global scopes.
You should configureImportSourceFactory in your service provider(register method)
useMatchish\ScoutElasticSearch\Searchable\ImportSourceFactory;...publicfunctionregister(): void{$this->app->bind(ImportSourceFactory::class, MyImportSourceFactory::class);
Here is an example ofMyImportSourceFactory
namespaceMatchish\ScoutElasticSearch\Searchable;finalclass MyImportSourceFactoryimplements ImportSourceFactory{publicstaticfunctionfrom(string$className):ImportSource {//Add all required scopesreturnnewDefaultImportSource($className, [newWithCommentsScope()]); }}class WithCommentsScopeimplements Scope {/** * Apply the scope to a given Eloquent query builder. * * @param \Illuminate\Database\Eloquent\Builder $builder * @param \Illuminate\Database\Eloquent\Model $model * @return void */publicfunctionapply(Builder$builder,Model$model) {$builder->with('comments'); }}
You can also customize your indexed data when you save models by leveraging thetoSearchableArray methodprovided by Laravel Scout through theSearchable trait
class Productextends Model {use Searchable;/** * Get the indexable data array for the model. * * @return array */publicfunctiontoSearchableArray() {$with = ['categories', ];$this->loadMissing($with);return$this->toArray(); }}
This example will make sure the categories relationship gets always loaded on the model whensaving it.
While working in production, to keep your existing search experience available while reimporting your data, you also can usescout:import Artisan command:
php artisan scout:import
The command create new temporary index, import all models to it, and then switch to the index and remove old index.
To be fully compatible with original scout package, this package does not add new methods.
So how we can build complex queries?There is two ways.
By default, when you pass a query to thesearch method, the engine builds aquery_string query, so you can build queries like this
Product::search('(title:this OR description:this) AND (title:that OR description:that)')
If it's not enough in your case you can pass a callback to the query builder
$results = Product::search('zonga',function(\Elastic\Elasticsearch\Client$client,$body) {$minPriceAggregation =newMinAggregation('min_price');$minPriceAggregation->setField('price');$maxPriceAggregation =newMaxAggregation('max_price');$maxPriceAggregation->setField('price');$brandTermAggregation =newTermsAggregation('brand');$brandTermAggregation->setField('brand');$body->addAggregation($minPriceAggregation);$body->addAggregation($brandTermAggregation);return$client->search(['index' =>'products','body' =>$body->toArray()])->asArray();})->raw();
Note : The callback function will get 2 parameters. First one is
$clientand it is an object of\Elastic\Elasticsearch\Clientclass fromelasticsearch/elasticsearch package.And the second one is$bodywhich is an object of\ONGR\ElasticsearchDSL\Searchfromongr/elasticsearch-dsl package. So, whileas you can see the example above,$client->search(....)method will return an\Elastic\Elasticsearch\Response\Elasticsearchobject. And you need to useasArray()method to get array result.Otherwise, theHitsIteratorAggregateclass will throw an error. You can check the issuehere.
Scout supports only 3 conditions:->where(column, value) (strict equation),->whereIn(column, array) and->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 does not support any operators, but you can pass ElasticSearch terms likeRangeQuery as value to->where():
useONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;Product::search('(title:this OR description:this) AND (title:that OR description:that)') ->where('price',newRangeQuery('price', [ RangeQuery::GTE =>100, RangeQuery::LTE =>1000, ]);
And if you just want to search using RangeQuery without any query_string, you can call the search() method directly and leave the param empty.
useONGR\ElasticsearchDSL\Query\TermLevel\RangeQuery;Product::search() ->where('price',newRangeQuery('price', [ RangeQuery::GTE =>100, ]);
Full list of ElasticSearch terms is invendor/handcraftedinthealps/elasticsearch-dsl/src/Query/TermLevel.
You can do it withMixedSearch class, just pass indices names separated by commas to thewithin method.
MixedSearch::search('title:Barcelona or to:Barcelona')within(implode(',', [ (newTicket())->searchableAs(), (newBook())->searchableAs(), ]))->get();
In this example you will get collection ofTicket andBook models where ticket's arrival city orbook title isBarcelona
Often your response isn't collection of models but aggregations or models with higlights an so on.In this case you need to implement your own implementation ofHitsIteratorAggregate and bind it in your service provider
Scout ElasticSearch is an open-sourced software licensed under theMIT license.
About
Search among multiple models with ElasticSearch and Laravel Scout
Resources
License
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Languages
- PHP97.0%
- Makefile1.6%
- Dockerfile1.4%
