Tìm Kiếm Siêu Tốc Với Laravel Scout và Meilisearch

· 6 min read

User::where('name', 'like', '%john%')->get() ổn cho 100 người dùng. Với 100,000 người dùng, nó chậm. Và nếu người dùng gõ "Jonh", nó không trả về gì cả.

Laravel Scout cung cấp giải pháp dựa trên driver để thêm tìm kiếm full-text vào các models của bạn. Meilisearch là search engine mã nguồn mở, cực nhanh, kết hợp hoàn hảo với Laravel.

Truy vấn SQL LIKE truyền thống có nhiều hạn chế:

  1. Hiệu năng: Chúng quét toàn bộ bảng, chậm dần theo cấp số nhân khi dữ liệu tăng
  2. Không chịu lỗi đánh máy: "Jonh" sẽ không match với "John"
  3. Không xếp hạng độ liên quan: Kết quả không được sắp xếp theo mức độ phù hợp
  4. Không stemming: "running" sẽ không match với "run"

Search engine full-text giải quyết tất cả vấn đề này bằng cách xây dựng inverted index và sử dụng các thuật toán tinh vi.

Cài Đặt

  1. Cài đặt Scout:
composer require laravel/scout
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
  1. Cài đặt Meilisearch Driver:
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzle
  1. Cấu hình .env:
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=your-master-key

Cấu Hình

Thêm trait Searchable vào model của bạn.

use Laravel\Scout\Searchable;

class Post extends Model
{
    use Searchable;

    // Tùy chọn: Tùy chỉnh dữ liệu nào được index
    public function toSearchableArray()
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => strip_tags($this->content),
            'author' => $this->author->name,
            'tags' => $this->tags->pluck('name')->toArray(),
            'published_at' => $this->published_at?->timestamp,
        ];
    }

    // Tùy chỉnh tên search index
    public function searchableAs(): string
    {
        return 'posts_index';
    }
}

Chạy Meilisearch

Cách dễ nhất là qua Laravel Sail (Docker):

# docker-compose.yml
meilisearch:
    image: 'getmeili/meilisearch:latest'
    ports:
        - '7700:7700'
    environment:
        - MEILI_MASTER_KEY=your-master-key
    volumes:
        - 'sail-meilisearch:/meili_data'

Hoặc cài đặt local trên macOS:

brew install meilisearch
meilisearch --master-key="your-master-key"

Index Dữ Liệu

Đẩy dữ liệu hiện có của bạn tới search engine:

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

Để re-index sau khi thay đổi schema:

php artisan scout:flush "App\Models\Post"
php artisan scout:import "App\Models\Post"

Tìm Kiếm

Bây giờ thay thế các truy vấn tiêu chuẩn của bạn bằng truy vấn Scout:

// SQL tiêu chuẩn (Chậm, nghiêm ngặt)
Post::where('title', 'like', '%larvel%')->get(); // Không trả về gì

// Scout (Nhanh, chịu lỗi đánh máy)
Post::search('larvel')->get(); // Trả về các posts 'Laravel'

Filters và Sorting

Scout hỗ trợ filtering và sorting thông qua các tính năng mạnh mẽ của Meilisearch:

// Filtering cơ bản
Post::search('tutorial')
    ->where('status', 'published')
    ->paginate(20);

// Nhiều filters
Post::search('laravel')
    ->where('category_id', 5)
    ->where('published_at', '>', now()->subMonth()->timestamp)
    ->get();

Cấu hình Filterable Attributes

Để sử dụng filters, bạn phải cấu hình Meilisearch:

// Trong AppServiceProvider hoặc một command
use Meilisearch\Client;

$client = new Client(config('scout.meilisearch.host'));
$client->index('posts_index')->updateFilterableAttributes([
    'status',
    'category_id',
    'published_at',
    'tags',
]);

$client->index('posts_index')->updateSortableAttributes([
    'published_at',
    'views_count',
]);

Phân Trang

Scout tích hợp mượt mà với pagination của Laravel:

$results = Post::search('laravel')->paginate(15);

// Trong Blade
@foreach($results as $post)
    <h2>{{ $post->title }}</h2>
@endforeach

{{ $results->links() }}

Cập Nhật Real-Time

Scout tự động đồng bộ các thay đổi tới search index:

// Điều này tự động cập nhật search index
$post->update(['title' => 'Tiêu đề mới']);

// Điều này xóa khỏi search index
$post->delete();

Queue Index Updates

Để hiệu năng tốt hơn, đưa các index operations vào queue:

// config/scout.php
'queue' => true,

Meilisearch vs Algolia

Tính năng Meilisearch Algolia
Giá Miễn phí (self-hosted) Trả phí theo search
Chịu lỗi đánh máy
Faceted search
Hosting Self-hosted hoặc Cloud Chỉ managed
Hiệu năng Xuất sắc Xuất sắc

Với hầu hết dự án, Meilisearch mang lại sự cân bằng tốt nhất giữa tính năng và chi phí.

Best Practices

  1. Chỉ index nội dung có thể tìm kiếm: Không index passwords hoặc dữ liệu nhạy cảm
  2. Sử dụng queue cho datasets lớn: Tránh request timeout
  3. Cấu hình stop words: Loại trừ các từ phổ biến như "the", "và"
  4. Thiết lập synonyms: Map "JS" tới "JavaScript"
  5. Giám sát kích thước index: Giữ search data gọn gàng

Full-text search biến đổi trải nghiệm người dùng. Với Scout và Meilisearch, bạn có được khả năng tìm kiếm cấp doanh nghiệp mà không cần chi phí doanh nghiệp.

Bình luận