MySQL full-text search is good enough for small apps. But once you have tens of thousands of products and users who type with typos, it starts to fall short. Elasticsearch was built specifically for search, and the difference in quality is significant.
Here is how I integrated it into a Laravel e-commerce project.
What Elasticsearch actually does differently
When you search for "wireles headphons" in MySQL full-text search, you get zero results. Elasticsearch understands that you probably meant "wireless headphones" and returns the right products anyway. This is called fuzzy matching.
Elasticsearch also ranks results by relevance. A product named "Wireless Headphones" ranks higher than one that just mentions headphones in the description. MySQL does not do this well.
Setting up the PHP client
composer require elasticsearch/elasticsearchCreate a service class:
class SearchService {
private Client $client;
public function __construct() {
$this->client = ClientBuilder::create()
->setHosts([config('services.elasticsearch.host')])
->build();
}
public function indexProduct(Product $product): void {
$this->client->index([
'index' => 'products',
'id' => $product->id,
'body' => [
'name' => $product->name,
'description' => $product->description,
'price' => $product->price,
'category' => $product->category->name,
'in_stock' => $product->stock > 0,
],
]);
}
}Keeping the index in sync
Use a model observer to update Elasticsearch whenever a product changes:
class ProductObserver {
public function __construct(private SearchService $search) {}
public function saved(Product $product): void {
$this->search->indexProduct($product);
}
public function deleted(Product $product): void {
$this->search->deleteProduct($product->id);
}
}Searching with fuzzy matching
public function search(string $query, int $page = 1): array {
$results = $this->client->search([
'index' => 'products',
'body' => [
'query' => [
'multi_match' => [
'query' => $query,
'fields' => ['name^3', 'description', 'category'],
'fuzziness' => 'AUTO',
],
],
'filter' => [
'term' => ['in_stock' => true]
],
'from' => ($page - 1) * 20,
'size' => 20,
],
]);
$ids = collect($results['hits']['hits'])->pluck('_id');
return Product::whereIn('id', $ids)->get();
}The ^3 after name means matches in the product name are 3 times more relevant than matches in the description. fuzziness: AUTO handles typos automatically.
Using Laravel Scout
If you want a simpler integration, Laravel Scout with the babenkoivan/elastic-scout-driver package gives you Elasticsearch search with much less code. It is a good starting point.
When is Elasticsearch worth the complexity?
Elasticsearch adds infrastructure complexity. You need to run and maintain an Elasticsearch cluster. For a small app with 10,000 products, MySQL full-text search is probably fine.
Add Elasticsearch when: your dataset is large (100k+ records), typo tolerance is important, you need faceted search (filter by price range, category, rating), or search is a core feature of your product.




