Laravel ile Elasticsearch Entegrasyonu
Büyük veri setlerinde hızlı ve performanslı arama yapmak istiyorsanız Elasticsearch güçlü bir çözüm. Açık kaynaklı, RESTful API destekli ve gerçek zamanlı indeksleme sunuyor. Bu yazıda Laravel projesine Elasticsearch entegrasyonunu adım adım anlatıyorum.
Elasticsearch Nedir?
Açık kaynaklı bir arama ve analiz motoru. Temel özellikleri:
- Tam metin arama: Büyük veri setlerinde bile hızlı sonuç
- Gerçek zamanlı indeksleme: Veriler anında sorgulanabilir
- Ölçeklenebilirlik: Yatayda kolayca genişletilebilir
- RESTful API: HTTP üzerinden entegrasyon
1. Elasticsearch Kurulumu (Docker)
# docker-compose.yml
version: '3.7'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.10.0
container_name: elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
kibana:
image: docker.elastic.co/kibana/kibana:8.10.0
container_name: kibana
ports:
- "5601:5601"
environment:
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
docker-compose up -d
Elasticsearch: localhost:9200, Kibana: localhost:5601
2. Laravel'e Elasticsearch Ekleme
composer require elasticsearch/elasticsearch
config/services.php:
'elasticsearch' => [
'hosts' => [
env('ELASTICSEARCH_HOST', 'localhost:9200'),
],
],
.env:
ELASTICSEARCH_HOST=localhost:9200
3. Service Provider
php artisan make:provider ElasticsearchServiceProvider
namespace App\Providers;
use Elasticsearch\ClientBuilder;
use Illuminate\Support\ServiceProvider;
class ElasticsearchServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton('elasticsearch', function () {
return ClientBuilder::create()
->setHosts(config('services.elasticsearch.hosts'))
->build();
});
}
}
4. Model Entegrasyonu
Searchable trait oluşturalım:
namespace App\Traits;
trait ElasticSearchable
{
public function toSearchableArray(): array
{
return $this->toArray();
}
public function indexInElasticsearch(): void
{
app('elasticsearch')->index([
'index' => $this->getTable(),
'id' => $this->getKey(),
'body' => $this->toSearchableArray(),
]);
}
public function removeFromElasticsearch(): void
{
app('elasticsearch')->delete([
'index' => $this->getTable(),
'id' => $this->getKey(),
]);
}
}
Model'de kullanım:
class Post extends Model
{
use ElasticSearchable;
public function toSearchableArray(): array
{
return [
'title' => $this->title,
'content' => $this->content,
'author' => $this->author->name ?? null,
'published_at' => $this->published_at?->toISOString(),
];
}
}
Model observer ile otomatik senkronizasyon:
class PostObserver
{
public function saved(Post $post): void
{
$post->indexInElasticsearch();
}
public function deleted(Post $post): void
{
$post->removeFromElasticsearch();
}
}
5. Arama Repository
namespace App\Repositories;
class ElasticsearchRepository
{
private $client;
public function __construct()
{
$this->client = app('elasticsearch');
}
public function search(string $index, string $query, array $fields = ['*']): array
{
return $this->client->search([
'index' => $index,
'body' => [
'query' => [
'multi_match' => [
'query' => $query,
'fields' => $fields,
'fuzziness' => 'AUTO',
],
],
],
]);
}
public function searchWithFilters(string $index, string $query, array $filters = []): array
{
$must = [
['multi_match' => [
'query' => $query,
'fields' => ['title^3', 'content'],
'fuzziness' => 'AUTO',
]],
];
foreach ($filters as $field => $value) {
$must[] = ['term' => [$field => $value]];
}
return $this->client->search([
'index' => $index,
'body' => [
'query' => ['bool' => ['must' => $must]],
],
]);
}
}
6. Controller
class SearchController extends Controller
{
public function __construct(
private ElasticsearchRepository $search
) {}
public function index(Request $request)
{
$query = $request->get('q', '');
$results = $this->search->search('posts', $query, ['title^3', 'content']);
return response()->json($results['hits']['hits']);
}
}
7. Toplu İndeksleme
Mevcut verileri indekslemek için artisan komutu:
class IndexPostsCommand extends Command
{
protected $signature = 'search:index-posts';
public function handle(): void
{
$bar = $this->output->createProgressBar(Post::count());
Post::chunk(100, function ($posts) use ($bar) {
foreach ($posts as $post) {
$post->indexInElasticsearch();
$bar->advance();
}
});
$bar->finish();
$this->newLine();
$this->info('Tüm postlar indekslendi!');
}
}
Performans İpuçları
- Queue kullanın: Büyük veri setlerini indekslerken queue ile arka planda çalıştırın
- Redis cache: Sık tekrarlanan sorguları cache'leyin
- Bulk API: Toplu indekslemede tek tek yerine bulk API kullanın
- Index aliasing: Zero-downtime reindex için alias kullanın
Ne Zaman Elasticsearch?
Uygun: Büyük veri setleri, karmaşık sorgular, log analizi, e-ticaret arama, gerçek zamanlı analytics.
Uygun değil: Küçük projeler (Meilisearch daha pratik), basit LIKE sorguları yeterli olan durumlar.
Sonuç
Elasticsearch büyük veri setlerinde güçlü ve performanslı bir arama altyapısı sunuyor. Laravel ile entegrasyonu biraz kurulum gerektirse de sonuç etkileyici. Küçük-orta projeler için Meilisearch'ü de değerlendirin — daha basit ve hafif.