- Notifications
You must be signed in to change notification settings - Fork307
This package offers advanced functionality for searching and filtering data in Elasticsearch.
License
babenkoivan/scout-elasticsearch-driver
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
💥Introducinga new Elasticsearch ecosystem for Laravel. 💥
This package offers advanced functionality for searching and filtering data in Elasticsearch.Check out itsfeatures!
- Features
- Requirements
- Installation
- Configuration
- Index configurator
- Searchable model
- Usage
- Console commands
- Search rules
- Available filters
- Zero downtime migration
- Debug
- Alternatives
- An easy way toconfigure andcreate an Elasticsearch index.
- A fully configurable mapping for eachmodel.
- A possibility to add a new field to an existing mappingautomatically or usingthe artisan command.
- Lots of different ways to implement your search algorithm: usingsearch rules or araw search.
- Various filter types to make a search query more specific.
- Zero downtime migration from an old index to a new index.
- Bulk indexing, seethe configuration section.
The package has been tested in the following configuration:
- PHP version >=7.1.3, <=7.3
- Laravel Framework version >=5.8, <=6
- Elasticsearch version >=7
Use composer to install the package:
composer require babenkoivan/scout-elasticsearch-driverIf you are using Laravel version <= 5.4 orthe package discoveryis disabled, add the following providers inconfig/app.php:
'providers' => [Laravel\Scout\ScoutServiceProvider::class,ScoutElastic\ScoutElasticServiceProvider::class,]
To configure the package you need to publish settings first:
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"php artisan vendor:publish --provider="ScoutElastic\ScoutElasticServiceProvider"Then, set the driver setting toelastic in theconfig/scout.php file (or setSCOUT_DRIVER=elastic in the.env) and configure the driver itself in theconfig/scout_elastic.php file.The available options are:
| Option | Description |
|---|---|
| client | A setting hash to build Elasticsearch client. More information you can findhere. By default the host is set tolocalhost:9200. |
| update_mapping | The option that specifies whether to update a mapping automatically or not. By default it is set totrue. |
| indexer | Set tosingle for the single document indexing and tobulk for the bulk document indexing. By default is set tosingle. |
| document_refresh | This option controls when updated documents appear in the search results. Can be set to'true','false','wait_for' ornull. More details about this option you can findhere. By default set tonull. |
Note, that if you use the bulk document indexing you'll probably want to change the chunk size, you can do that in theconfig/scout.php file.
An index configurator class is used to set up settings for an Elasticsearch index.To create a new index configurator use the following artisan command:
php artisan make:index-configurator MyIndexConfiguratorIt'll create the fileMyIndexConfigurator.php in theapp folder of your project.You can specify index name and settings like in the following example:
<?phpnamespaceApp;useScoutElastic\IndexConfigurator;class MyIndexConfiguratorextends IndexConfigurator{// It's not obligatory to determine name. By default it'll be a snaked class name without `IndexConfigurator` part.protected$name ='my_index';// You can specify any settings you want, for example, analyzers.protected$settings = ['analysis' => ['analyzer' => ['es_std' => ['type' =>'standard','stopwords' =>'_spanish_' ] ] ] ];}
More about index settings you can find in theindex management section of Elasticsearch documentation.
To create an index just run the artisan command:
php artisan elastic:create-index "App\MyIndexConfigurator"Note, that every searchable model requires its own index configurator.
Indices created in Elasticsearch 6.0.0 or later may only contain a single mapping type. Indices created in 5.x with multiple mapping types will continue to function as before in Elasticsearch 6.x. Mapping types will be completely removed in Elasticsearch 7.0.0.
You can find more informationhere.
To create a model with the ability to perform search requests in an Elasticsearch index use the command:
php artisan make:searchable-model MyModel --index-configurator=MyIndexConfiguratorAfter executing the command you'll find the fileMyModel.php in youapp folder:
<?phpnamespaceApp;useScoutElastic\Searchable;useIlluminate\Database\Eloquent\Model;class MyModelextends Model{use Searchable;protected$indexConfigurator = MyIndexConfigurator::class;protected$searchRules = [// ];// Here you can specify a mapping for model fieldsprotected$mapping = ['properties' => ['title' => ['type' =>'text',// Also you can configure multi-fields, more details you can find here https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-fields.html'fields' => ['raw' => ['type' =>'keyword', ] ] ], ] ];}
Each searchable model represents an Elasticsearch type.By default a type name is the same as a table name, but you can set any type name you want through thesearchableAs method.You can also specify fields which will be indexed by the driver through thetoSearchableArray method.More information about these options you will find inthe scout official documentation.
The last important option you can set in theMyModel class is the$searchRules property.It allows you to set different search algorithms for a model.We'll take a closer look at it inthe search rules section.
After setting up a mapping in your model you can update an Elasticsearch type mapping:
php artisan elastic:update-mapping "App\MyModel"Once you've created an index configurator, an Elasticsearch index itself and a searchable model, you are ready to go.Now you canindex andsearch data according to the documentation.
Basic search usage example:
// set query stringApp\MyModel::search('phone')// specify columns to select ->select(['title','price'])// filter ->where('color','red')// sort ->orderBy('price','asc')// collapse by field ->collapse('brand')// set offset ->from(0)// set limit ->take(10)// get results ->get();
If you only need the number of matches for a query, use thecount method:
App\MyModel::search('phone') ->count();
If you need to load relations, use thewith method:
App\MyModel::search('phone') ->with('makers') ->get();
In addition to standard functionality the package offers you the possibility to filter data in Elasticsearch without specifying a query string:
App\MyModel::search('*') ->where('id',1) ->get();
Also you can override modelsearch rules:
App\MyModel::search('Brazil') ->rule(App\MySearchRule::class) ->get();
And usevariety ofwhere conditions:
App\MyModel::search('*') ->whereRegexp('name.raw','A.+') ->where('age','>=',30) ->whereExists('unemployed') ->get();
And filter out results with a score less thanmin_score:
App\MyModel::search('sales') ->minScore(1.0) ->get();
And add more complex sorting (geo_distance eg.)
$model =App\MyModel::search('sales') ->orderRaw(['_geo_distance' => ['coordinates' => ['lat' =>51.507351,'lon' => -0.127758 ],'order' =>'asc','unit' =>'m' ] ]) ->get();// To retrieve sort result, use model `sortPayload` attribute:$model->sortPayload;
At last, if you want to send a custom request, you can use thesearchRaw method:
App\MyModel::searchRaw(['query' => ['bool' => ['must' => ['match' => ['_all' =>'Brazil' ] ] ] ]]);
This query will return raw response.
Available artisan commands are listed below:
| Command | Arguments | Description |
|---|---|---|
| make:index-configurator | name - The name of the class | Creates a new Elasticsearch index configurator. |
| make:searchable-model | name - The name of the class | Creates a new searchable model. |
| make:search-rule | name - The name of the class | Creates a new search rule. |
| elastic:create-index | index-configurator - The index configurator class | Creates an Elasticsearch index. |
| elastic:update-index | index-configurator - The index configurator class | Updates settings and mappings of an Elasticsearch index. |
| elastic:drop-index | index-configurator - The index configurator class | Drops an Elasticsearch index. |
| elastic:update-mapping | model - The model class | Updates a model mapping. |
| elastic:migrate-model | model - The model class,target-index - The index name to migrate | Migrates model to another index. |
For detailed description and all available options runphp artisan help [command] in the command line.
A search rule is a class that describes how a search query will be executed.To create a search rule use the command:
php artisan make:search-rule MySearchRuleIn the fileapp/MySearchRule.php you will find a class definition:
<?phpnamespaceApp;useScoutElastic\SearchRule;class MySearchextends SearchRule{// This method returns an array, describes how to highlight the results.// If null is returned, no highlighting will be used.publicfunctionbuildHighlightPayload() {return ['fields' => ['name' => ['type' =>'plain' ] ] ]; }// This method returns an array, that represents bool query.publicfunctionbuildQueryPayload() {return ['must' => ['match' => ['name' =>$this->builder->query ] ] ]; }}
You can read more about bool querieshereand about highlightinghere.
The default search rule returns the following payload:
return ['must' => ['query_string' => ['query' =>$this->builder->query ] ]];
This means that by default when you callsearch method on a model it tries to find the query string in any field.
To determine default search rules for a model just add a property:
<?phpnamespaceApp;useScoutElastic\Searchable;useIlluminate\Database\Eloquent\Model;class MyModelextends Model{use Searchable;// You can set several rules for one model. In this case, the first not empty result will be returned.protected$searchRules = [ MySearchRule::class ];}
You can also set a search rule in a query builder:
// You can set either a SearchRule classApp\MyModel::search('Brazil') ->rule(App\MySearchRule::class) ->get();// or a callableApp\MyModel::search('Brazil') ->rule(function($builder) {return ['must' => ['match' => ['Country' =>$builder->query ] ] ]; }) ->get();
To retrieve highlight, use modelhighlight attribute:
// Let's say we highlight field `name` of `MyModel`.$model =App\MyModel::search('Brazil') ->rule(App\MySearchRule::class) ->first();// Now you can get raw highlighted value:$model->highlight->name;// or string value:$model->highlight->nameAsString;
You can use different types of filters:
| Method | Example | Description |
|---|---|---|
| where($field, $value) | where('id', 1) | Checks equality to a simple value. |
| where($field, $operator, $value) | where('id', '>=', 1) | Filters records according to a given rule. Available operators are: =, <, >, <=, >=, <>. |
| whereIn($field, $value) | whereIn('id', [1, 2, 3]) | Checks if a value is in a set of values. |
| whereNotIn($field, $value) | whereNotIn('id', [1, 2, 3]) | Checks if a value isn't in a set of values. |
| whereBetween($field, $value) | whereBetween('price', [100, 200]) | Checks if a value is in a range. |
| whereNotBetween($field, $value) | whereNotBetween('price', [100, 200]) | Checks if a value isn't in a range. |
| whereExists($field) | whereExists('unemployed') | Checks if a value is defined. |
| whereNotExists($field) | whereNotExists('unemployed') | Checks if a value isn't defined. |
| whereMatch($field, $value) | whereMatch('tags', 'travel') | Filters records matching exact value.Here you can find more about syntax. |
| whereNotMatch($field, $value) | whereNotMatch('tags', 'travel') | Filters records not matching exact value.Here you can find more about syntax. |
| whereRegexp($field, $value, $flags = 'ALL') | whereRegexp('name.raw', 'A.+') | Filters records according to a given regular expression.Here you can find more about syntax. |
| whereGeoDistance($field, $value, $distance) | whereGeoDistance('location', [-70, 40], '1000m') | Filters records according to given point and distance from it.Here you can find more about syntax. |
| whereGeoBoundingBox($field, array $value) | whereGeoBoundingBox('location', ['top_left' => [-74.1, 40.73], 'bottom_right' => [-71.12, 40.01]]) | Filters records within given boundings.Here you can find more about syntax. |
| whereGeoPolygon($field, array $points) | whereGeoPolygon('location', [[-70, 40],[-80, 30],[-90, 20]]) | Filters records within given polygon.Here you can find more about syntax. |
| whereGeoShape($field, array $shape, $relation = 'INTERSECTS') | whereGeoShape('shape', ['type' => 'circle', 'radius' => '1km', 'coordinates' => [4, 52]], 'WITHIN') | Filters records within given shape.Here you can find more about syntax. |
In most cases it's better to use raw fields to filter records, i.e. not analyzed fields.
As you might know, you can't change the type of already created field in Elasticsearch.The only choice in such case is to create a new index with necessary mapping and import your models into the new index.
A migration can take quite a long time, so to avoid downtime during the process the driver reads from the old index and writes to the new one.As soon as migration is over it starts reading from the new index and removes the old index.This is how the artisanelastic:migrate-model command works.
Before you run the command, make sure that your index configurator uses theScoutElastic\Migratable trait.If it's not, add the trait and run the artisanelastic:update-index command using your index configurator class name as an argument:
php artisan elastic:update-index "App\MyIndexConfigurator"When you are ready, make changes in the model mapping and run theelastic:migrate-model command using the model class as the first argument and desired index name as the second argument:
php artisan elastic:migrate-model "App\MyModel" my_index_v2Note, that if you need just to add new fields in your mapping, use theelastic:update-mapping command.
There are two methods that can help you to analyze results of a search query:
Both methods return raw data from ES.
Besides, you can get a query payload that will be sent to ES, by calling thebuildPayload method.
App\MyModel::search('Brazil') ->buildPayload();
Note, that this method returns a collection of payloads, because of possibility of using multiple search rules in one query.
Recently I've released a new Elasticsearch ecosystem for Laravel, it includes:
- Elastic Scout Driver - a generic Elasticsearch driver for Laravel Scout.It's perfect, if you need to build a simple search in your Laravel application.
- Elastic Scout Driver Plus - an extension for Elastic Scout Driver.If you want to take advantage of such Elasticsearch features as bool queries, highlighting, etc., it's a way to go.
- Elastic Migrations - an easy way to create, delete or updateElasticsearch index schema and share it with your teammates. It has quite similar interface to Laravel database migrations.
If any of it sounds interesting to you and you want to get more details, please readThe Ultimate Guide to Elasticsearch in Laravel Application.The article makes a good overview of the mentioned packages and provides usage examples.
FAQ:
- Why did you create a new package instead of a new
scout-elasticsearch-driverversion? - I didn't want to create anotherall in one package for obvious reasons: no separation of concerns, not compatible with other Scout drivers, hard to testand develop, etc. As Elastic Scout Driver is a generic driver and doesn't implement all thescout-elasticsearch-driverfeatures, it would be wrong to call it a newscout-elasticsearch-driverversion. - What does it mean for scout-elasticsearch-driver? - Well, it's maintained by the community at the moment(thank you @iget-esoares and @lucamichot for keeping the project alive 🎉). I hope they will continue contributing to theproject and bring a new version of
scout-elasticsearch-driverin the future.
About
This package offers advanced functionality for searching and filtering data in Elasticsearch.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.