elastic_search_laravel_2021
Elastic Search ver 7 with Laravel 8
composer require elasticsearch/elasticsearch
composer require laravel/breeze --dev
php artisan breeze:install
artisan make:model -mf Article
code
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->json('tags');
$table->timestamps();
});
'json',
];
}
times(50)->create();
}
}
$this->faker->sentence(),
'body' => $this->faker->text(),
'tags' => collect(['php', 'ruby', 'java', 'javascript', 'bash'])
->random(2)
->values()
->all(),
];
}
}
### Update view dashboard.php
{{ __('Articles') }} ({{ $articles->count() }})
@if (request()->has('q'))
Using search: "{{ request('q') }}". Clear filters
@endif
@forelse ($articles as $article)
{{ $article->body }}
@foreach ($article->tags as $tag)
{{ $tag}}
@endforeach
@empty
No articles found
@endforelse
where(fn ($query) => (
$query->where('body', 'LIKE', "%{$term}%")
->orWhere('title', 'LIKE', "%{$term}%")
))
->get();
}
}
use App\Articles\SearchRepository;
Route::get('/dashboard', function (SearchRepository $searchRepository) {
return view('dashboard', [
'articles' => request()->has('q')
? $searchRepository->search(request('q'))
: App\Models\Article::all(),
]);
})->middleware(['auth'])->name('dashboard');
elasticSearchIndex($this->elasticsearchClient);
}
public function deleted($model)
{
$model->elasticSearchDelete($this->elasticsearchClient);
}
}
index([
'index' => $this->getTable(),
'type' => '_doc',
'id' => $this->getKey(),
'body' => $this->toElasticsearchDocumentArray(),
]);
}
public function elasticsearchDelete(Client $elasticsearchClient)
{
$elasticsearchClient->delete([
'index' => $this->getTable(),
'type' => '_doc',
'id' => $this->getKey(),
]);
}
abstract public function toElasticsearchDocumentArray(): array;
}
elasticsearch = $elasticsearch;
}
public function search(string $query = ''): Collection
{
$items = $this->searchOnElasticsearch($query);
return $this->buildCollection($items);
}
private function searchOnElasticsearch(string $query = ''): array
{
$model = new Article;
$items = $this->elasticsearch->search([
'index' => $model->getSearchIndex(),
'type' => $model->getSearchType(),
'body' => [
'query' => [
'multi_match' => [
'fields' => ['title^5', 'body', 'tags'],
'query' => $query,
],
],
],
]);
return $items;
}
private function buildCollection(array $items): Collection
{
$ids = Arr::pluck($items['hits']['hits'], '_id');
return Article::findMany($ids)
->sortBy(function ($article) use ($ids) {
return array_search($article->getKey(), $ids);
});
}
}
app->bind(Articles\ArticlesRepository::class, function ($app) {
// This is useful in case we want to turn-off our
// search cluster or when deploying the search
// to a live, running application at first.
if (! config('services.search.enabled')) {
return new Articles\EloquentRepository();
}
return new Articles\ElasticsearchRepository(
$app->make(Client::class)
);
});
}
}
app->bind(Articles\ArticlesRepository::class, function () {
// This is useful in case we want to turn-off our
// search cluster or when deploying the search
// to a live, running application at first.
if (! config('services.search.enabled')) {
return new Articles\EloquentRepository();
}
return new Articles\ElasticsearchRepository(
$app->make(Client::class)
);
});
$this->bindSearchClient();
}
private function bindSearchClient()
{
$this->app->bind(Client::class, function ($app) {
return ClientBuilder::create()
->setHosts($app['config']->get('services.search.hosts'))
->build();
});
}
}
### Update config /services.php
[
'enabled' => env('ELASTICSEARCH_ENABLED', false),
'hosts' => explode(',', env('ELASTICSEARCH_HOSTS')),
],
];
### Add to .ENV file
ELASTICSEARCH_ENABLED=true
ELASTICSEARCH_HOSTS="localhost:9200"
elasticsearch = $elasticsearch;
}
public function handle()
{
$this->info('Indexing all articles. This might take a while...');
foreach (Article::cursor() as $article)
{
$this->elasticsearch->index([
'index' => $article->getSearchIndex(),
'type' => $article->getSearchType(),
'id' => $article->getKey(),
'body' => $article->toSearchArray(),
]);
// PHPUnit-style feedback
$this->output->write('.');
}
$this->info("\nDone!");
}
}
### CLI
php artisan make:command ReindexCommand --command="search:reindex"
### Advance
[
'multi_match' => [
'fields' => ['title^5', 'body', 'tags'],
'query' => $query,
],
],