Skip to content

ccennis/larelastic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

larelastic

An indexing and querying package to create, maintain and search an elastic instance with Laravel Scout as backbone.

Contents

Installation

Laravel

Add the Third Party Service Providers in config/app.php
Larelastic\Elastic\Providers\ElasticServiceProvider::class
Add the Third Party Aliases in config/app.php
'Elastic' => Larelastic\Elastic\Facades\Elastic::class
Get Config Files
php artisan vendor:publish
Add the following variables to your .env file
ELASTICSEARCH_HOST=http://elastic:9200
ELASTICSEARCH_PORT=9200
SCOUT_DRIVER=elastic
SCOUT_ELASTIC_HOST=http://elastic:9200

Indexing

(for a completely new installation -- skip ahead past 3rd step if index exists)

Since this package relies on the existence of models and index configurators to create, search and maintain indices, you must run the below commands to generate and set up the appropriate objects.

1.) create an indexConfigurator model (in this example, "Tattoo"):

 php artisan make:index-configurator TattooIndexConfigurator

2.) create your searchable Model:

php artisan make:searchable-model Product --index-configurator=TattooIndexConfigurator
3.) create your Elastic index using model with full path:
php artisan elastic:create-index "App\Models\Tattoo"

Indexing

4.) add data to your index

php artisan scout:import "App\Models\Tattoo"

Migrating to new Index

php artisan elastic:migrate "App\MyModel" my_index_v2

This process creates a new index, imports all data from previous to this index, and then links the old index to this new one via an alias

Update a mapping:

php artisan elastic:update-mapping "App\\Models\MyModel"

Update index:

php artisan elastic:update-index "App\Models\MyModelConfigurator"

Drop index:

php artisan elastic:drop-index "App\Models\MyModel"

Additional Configuration Options:

In your designated model, you may want to make use of the method:

public function searchableQuery()
{
    return $self->newQuery();
}

This will enable you to fine tune the actual query that is sent to elastic if you need to eager load or specify relationships.

Usage and Examples

Where/OrWhere queries make use of the bool methods (must, must_not, and should). Syntax is meant to be eloquent-like, but must use the search trait to differentiate it from actual Eloquent.

Valid Operators

Operator Function Usage
= equals ->where('col', '=', 'value')
->where('col', 'value')
<> not equals ->where('col', '<>', 'value')
in in field array ->where('col', 'in', ['value'])
begins_with search phrase beginning matched to search ->where('col', 'begins_with', 'value')
ends_with search phrase ending matched to search ->where('col', 'ends_with', 'value')
contains search phrase found in field ->where('col', 'contains', 'value')
gte >= ->where('col', 'gte', 'value')
lte <= ->where('col', 'lte', 'value')
gt > ->where('col', 'gt', 'value')
lt < ->where('col', 'lt', 'value')
between date found between two dates ->where('col', 'between', ['value1', 'value2'])
exists the value is not null and is found in index ->where('col', 'exists')

Sample Where query

$response = Tattoo::search()->where('name', 'mold')->get();
$response = Tattoo::search()->where('name', '=', 'mold')->get();

Both of the above queries are valid. Default operator is '=' unless provided.

Sample Or Where query

$response = Tattoo::search()->orWhere(['name', '=', 'mold'],['name', '=', 'Element'])->get();

takes two arrays, makes use of the should bool operator from Elastic. Evaluates to "find this OR that".

$response = Tattoo::search()->orWhere(function($query, $boolean){
            $query->where('name', '=','Mold', $boolean)
            ->where('model', '=','test', $boolean);
            return $query;
        })->orWhere(function($query, $boolean){
            $query->where('name', '=','element', $boolean)
            ->where('model', '=','test', $boolean);
            return $query;
        })->get();

Closure, makes use of multiple groupings under should bool operator from Elastic. Evaluates to "find (this AND that) OR (this and that)".

Sample Multimatch query

 $response = Tattoo::search()->whereMulti(['name', 'model'],'=','Mold')->get();
 

This makes use of the multimatch elastic function, takes an array of fields. Default search type is phrase prefix, but accepts an argument to override, such as best_fields:

 $response = Tattoo::search()->whereMulti(['name', 'model'],'=','Mold', 'best_fields')->get();
 

Pagination

 $response = Tattoo::search()->whereMulti(['name', 'model'],'=','Mold')->paginate(20);
 

Pagination functions much the same as in eloquent. It will wrap your response in the Paginator Length Aware metadata fields:

first_page_url: "http://myProject.com?page=1",
from: 1,
last_page: 2,
last_page_url: "http://myProject.com?page=3",
next_page_url: "http://myProject.com?page=2",
path: "http://myProject.com",
per_page: 20,
prev_page_url: null,
to: 2,
total: 36

Sorting

Simple Sorting:

$response = Tattoo::search()->where('name', 'mold')
sort->('name','desc')->get()

Sorting defaults to asc and can be stacked for multiple sorts.

If you need to specify a field_type for the sort field (i.e. 'keyword' or 'raw') you can include it as a param:

$response = Tattoo::search()->where('name', 'mold')
sort->('name', 'desc', 'keyword')->get()

The above may be necessary in the event you are already querying a nested object and want to ensure the datatype is listed separately.

Geosorting

Sorting by distance based on latitude and longitude. Sample query in Elastic:

{
"sort": [{
		"_geo_distance": {
			"location": {
				"lat": 40,
				"lon": -70
			},
			"order": "asc",
			"unit": "mi",
			"mode": "min",
			"distance_type": "arc",
			"ignore_unmapped": true
		}
	]}
}

In order to use this in the package, you can use the following syntax:

$data = [
                'field' => 'location_lat_long', 
                'lat' => $lat,
                'long' => $lat,
            ];

            $this->search->buildGeoSort($data);

There is also support to return the distance query as raw syntax, which can be used in the Top Level OR statement. An example:

        $latLongArray = explode(",", $this->user->location_lat_long);

        $response['bool']['must'] = $this->search->whereDistanceSyntax('artist.location_lat_long', $latLongArray[0], $latLongArray[1], '25mi');

        return $response;

Valid fields to pass in the data array are above in the elastic query.

Valid arguments for unit include: mi (miles), in (inches), yd (yards), km (kilometers), cm (centimeters), mm (millimeters).

There are two distance calculation modes: arc (the default), and plane. The arc calculation is the most accurate.

{

```php

mi (miles), in (inches), yd (yards), km (kilometers), cm (centimeters), mm (millimeters).


#### <a id="aggs"></a>Aggregation (aggs)

```php

$response = Tattoo::search()->where('name', 'mold')
->rollup('card_color')->get();

initial support for aggs takes a column name and creates buckets to count all matches. result set will be under an "aggs" object, like so:

{
	aggs: {
		agg_field: {
			doc_count_error_upper_bound: 0,
			sum_other_doc_count: 0,
			buckets: [{
					key: "G",
					doc_count: 35
				},
				{
					key: "B",
					doc_count: 1
				}
			]
		}
	}
}