Laravel Scout: الدليل الشامل لبناء البحث في Laravel من Full-Text Search إلى Semantic Search
لديك متجر أو منصة محتوى مبنية بـ Laravel، ويبحث المستخدم عن كلمة مثل "Laravel queues"، لكن تنفيذ استعلامات LIKE '%query%' على عدة أعمدة بدأ يصبح بطيئًا، والنتائج لا تُرتب بحسب الصلة، وإضافة الفلاتر أو البحث الدلالي أصبحت أكثر تعقيدًا مع نمو البيانات. يمكنك ربط تطبيقك مباشرة بمحرك بحث خارجي وكتابة طبقة مزامنة كاملة بنفسك، لكنك ستحتاج إلى إدارة إنشاء الفهارس وتحديثها وحذف السجلات ومزامنة Eloquent Models مع محرك البحث. هنا يأتي دور Laravel Scout.
Laravel Scout هو الحزمة الرسمية التي توفر طبقة بحث موحدة لتطبيقات Laravel. تضيف Trait بسيطًا إلى Eloquent Model، تحدد البيانات القابلة للبحث، ثم تستخدم API قريبة من أسلوب Laravel المعتاد لتنفيذ البحث سواء عبر قاعدة البيانات مباشرة أو عبر محركات مثل Algolia وMeilisearch وTypesense وTurbopuffer.
والأهم في Laravel 13 أن Scout لم يعد مقتصرًا على البحث النصي التقليدي؛ يدعم التوثيق الرسمي أيضًا Semantic Search وHybrid Search عبر مجموعة من المحركات، بما في ذلك Database Engine عند استخدام PostgreSQL مع pgvector.
يعتمد هذا الدليل على توثيق Laravel Scout 13.x الرسمي فقط، مع الرجوع إلى توثيق Laravel الرسمي للـ Queues وLaravel AI SDK عند الحاجة.
ما هو Laravel Scout؟
Laravel Scout هو طبقة تكامل رسمية بين Eloquent ومحركات البحث. وظيفته الأساسية ليست أن يصبح Search Engine بحد ذاته، بل أن يجعل Model في Laravel قابلًا للفهرسة والبحث باستخدام واجهة موحدة.
عند إضافة Laravel\Scout\Searchable إلى Model، يسجل Scout Model Observer يتابع إنشاء السجلات وتعديلها وحذفها، ثم يزامن التغييرات مع محرك البحث الذي اخترته.
Scout هو Search Abstraction Layer: أنت تتعامل مع API واحدة داخل Laravel، بينما يمكن تغيير المحرك الموجود خلفها حسب احتياجات المشروع.
هذه الطبقة مفيدة جدًا لأنها تفصل منطق التطبيق عن تفاصيل كل Search Provider. يمكن أن تبدأ باستخدام Database Engine دون بنية تحتية إضافية، ثم تنتقل لاحقًا إلى Meilisearch أو Typesense أو Algolia دون إعادة كتابة كل منطق البحث في Controllers.
كيف يعمل Laravel Scout؟
يمكن تبسيط دورة العمل إلى أربع مراحل:
- تحدد Model الذي تريد جعله قابلًا للبحث.
- تحدد البيانات التي يجب إرسالها إلى Search Engine.
- يقوم Scout بمزامنة إنشاء وتحديث وحذف السجلات.
- تستخدم
Model::search()للحصول على النتائج.
Database / Eloquent Model
|
v
Laravel Scout
|
+-- Database Engine
+-- Algolia
+-- Meilisearch
+-- Typesense
+-- Turbopuffer
+-- Custom Engine
|
v
Search Results
|
v
Eloquent Modelsمع المحركات الخارجية، يحصل Scout على معرفات النتائج من Search Engine ثم يستخدم Eloquent لاسترجاع Models المطابقة من قاعدة البيانات. هذا التفصيل مهم عند استخدام العلاقات أو Global Scopes أو محاولة إضافة شروط Eloquent بعد البحث.
محركات البحث التي يدعمها Laravel Scout
| المحرك | بنية إضافية | الفهرسة الخارجية | Semantic Search | الاستخدام المناسب |
|---|---|---|---|---|
| Database | لا | لا | نعم مع PostgreSQL وpgvector | مشاريع تريد بحثًا قويًا دون خدمة خارجية |
| Collection | لا | لا | لا | Tests وPrototypes وبيانات صغيرة جدًا |
| Algolia | خدمة خارجية | نعم | غير مدرج ضمن محركات Scout الداعمة لـ semantic() في التوثيق الحالي | بحث مُدار وقابل للتوسع |
| Meilisearch | خادم Meilisearch | نعم | نعم | بحث سريع مع إمكانية الاستضافة الذاتية |
| Typesense | خادم أو Typesense Cloud | نعم | نعم | Keyword وSemantic وGeo وVector Search |
| Turbopuffer | خدمة خارجية | نعم | نعم | Full-Text وSemantic وHybrid Search |
اختيار المحرك يجب أن يعتمد على حجم البيانات، الحاجة إلى Ranking وFaceting، تكلفة البنية التحتية، ومتطلبات Semantic Search، وليس فقط على Benchmark واحد.
تثبيت Laravel Scout
ابدأ بتثبيت الحزمة:
composer require laravel/scoutبعدها انشر ملف الإعداد:
php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"سينشئ ذلك:
config/scout.phpثم أضف Trait إلى Model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Article extends Model
{
use Searchable;
}إذا أردت أبسط إعداد ممكن دون Search Service خارجي، يمكنك استخدام Database Engine:
SCOUT_DRIVER=databaseبعد ذلك تستطيع مباشرة تنفيذ:
$articles = Article::search('Laravel Scout')->get();تحديد البيانات القابلة للبحث
افتراضيًا، يقوم Scout باستخدام التمثيل الناتج من toArray() للـ Model عند إنشاء سجل داخل Search Index. لكن إرسال كل حقول Model ليس دائمًا قرارًا جيدًا.
يمكنك تحديد الحقول المطلوبة عبر toSearchableArray():
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'title' => $this->title,
'summary' => $this->summary,
'body' => $this->body,
'status' => $this->status,
'published_at' => $this->published_at?->timestamp,
];
}هذه الخطوة تؤثر في الأداء والخصوصية معًا. لا ترسل إلى Search Index حقولًا لا تحتاج إليها، خصوصًا بيانات المستخدمين أو الحقول الداخلية أو الأسرار.
استخدام محرك مختلف لـ Model محدد
يمكن تغيير المحرك على مستوى Model بدل الالتزام بالمحرك الافتراضي:
use Laravel\Scout\Engines\Engine;
use Laravel\Scout\Scout;
public function searchableUsing(): Engine
{
return Scout::engine('meilisearch');
}هذا يسمح لتطبيق واحد باستخدام أكثر من Search Engine إذا كان لديك سبب معماري واضح لذلك.
استخدام Database Engine
يدعم Database Engine حاليًا MySQL وPostgreSQL. وهو يبحث مباشرة داخل جداول قاعدة البيانات باستخدام Full-Text Indexes وعمليات LIKE، لذلك لا يحتاج إلى مزامنة Index خارجي.
SCOUT_DRIVER=databaseالميزة الأساسية لهذا المحرك هي البساطة: لا توجد خدمة بحث إضافية، ولا API Key، ولا عملية Import أولية.
تحسين استراتيجية البحث
افتراضيًا يستخدم Database Engine بحثًا من نوع LIKE للحقول القابلة للبحث. لكن يمكنك توجيه Scout لاستخدام Prefix Search أو Full-Text Search:
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;
#[SearchUsingPrefix(['id', 'slug'])]
#[SearchUsingFullText(['title', 'body'])]
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'slug' => $this->slug,
'title' => $this->title,
'body' => $this->body,
];
}قبل استخدام SearchUsingFullText يجب أن تكون الأعمدة المقابلة لها مزودة فعليًا بـ Full-Text Index داخل قاعدة البيانات.
Semantic Search داخل PostgreSQL
يدعم Database Engine البحث الدلالي والهجين عندما تستخدم PostgreSQL مع امتداد pgvector. تضيف Vector Column وفهرسًا متجهيًا إضافة إلى Full-Text Index:
Schema::ensureVectorExtensionExists();
Schema::table('articles', function (Blueprint $table) {
$table->vector('embedding', dimensions: 1536)->nullable();
$table->vectorIndex('embedding');
$table->fullText(['title', 'body']);
});ثم تحدد النص الذي يجب تحويله إلى Embedding:
public function toSearchableEmbedding(): string|array
{
return $this->title.' '.$this->body;
}إذا كان Scout مسؤولًا عن توليد Embeddings فستحتاج إلى Laravel AI SDK وإعداد مزود Embeddings مناسب.
Collection Engine: مفيد، لكن ليس للإنتاج الكبير
SCOUT_DRIVER=collectionCollection Engine يجلب جميع السجلات المحتملة من قاعدة البيانات ثم يفلترها داخل PHP باستخدام أدوات Laravel. لذلك لا يحتاج إلى فهرسة أو Search Engine خارجي.
لكن التوثيق الرسمي يوصي به فقط للـ Prototypes والاختبارات ومجموعات البيانات الصغيرة جدًا، في حدود بضع مئات من السجلات تقريبًا.
هو أكثر قابلية للنقل من Database Engine لأنه يعمل مع قواعد البيانات العلائقية التي يدعمها Laravel، بما فيها SQLite وSQL Server، لكنه أقل كفاءة بشكل واضح عند نمو البيانات.
إعداد محركات البحث الخارجية
Algolia
composer require algolia/algoliasearch-client-phpبعد ذلك تضبط بيانات الاعتماد المطلوبة داخل إعداد Scout. ومع Algolia يمكن أيضًا تعريف Index Settings مثل Searchable Attributes وFaceting داخل config/scout.php ثم مزامنتها أثناء النشر.
Meilisearch
composer require meilisearch/meilisearch-php http-interop/http-factory-guzzleSCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
MEILISEARCH_KEY=masterKeyعند استخدام Filters أو Sorting يجب تعريف filterableAttributes وsortableAttributes المناسبة في إعداد Index.
Typesense
composer require typesense/typesense-phpSCOUT_DRIVER=typesense
TYPESENSE_API_KEY=masterKey
TYPESENSE_HOST=localhostيحتاج Typesense أيضًا إلى Collection Schema يصف أنواع الحقول القابلة للبحث، ويجب الانتباه إلى أنواع البيانات داخل toSearchableArray().
Turbopuffer
SCOUT_DRIVER=turbopuffer
TURBOPUFFER_API_KEY=tpuf_...
TURBOPUFFER_REGION=gcp-us-central1يدعم Turbopuffer داخل Scout البحث النصي والدلالي والهجين. قيمة TURBOPUFFER_REGION اختيارية، والقيمة الافتراضية الحالية هي gcp-us-central1.
الفهرسة ومزامنة السجلات
هذه العمليات مهمة بصورة أساسية عند استخدام Search Engine خارجي. Database Engine لا يحتاج إلى Import منفصل لأنه يبحث في الجدول نفسه.
استيراد السجلات الموجودة مسبقًا
php artisan scout:import "App\Models\Article"إذا كان لديك عدد كبير من السجلات ويمكنك الاعتماد على Queues:
php artisan scout:queue-import "App\Models\Article" --chunk=500حذف جميع سجلات Model من Index
php artisan scout:flush "App\Models\Article"إضافة سجلات عبر Query
Article::where('status', 'published')->searchable();يعمل searchable() كعملية Upsert: إذا كان السجل موجودًا يتم تحديثه، وإن لم يكن موجودًا يتم إضافته.
إزالة سجلات من البحث
Article::where('status', 'draft')->unsearchable();ولإزالة جميع سجلات Model:
Article::removeAllFromSearch();تعليق المزامنة مؤقتًا
Article::withoutSyncingToSearch(function () {
// Bulk database operations...
});هذه الطريقة مفيدة عندما تنفذ تحديثًا ضخمًا ولا تريد إرسال آلاف عمليات Indexing وسيطة غير ضرورية.
فهرسة السجلات وفق شرط
public function shouldBeSearchable(): bool
{
return $this->status === 'published';
}انتبه إلى أن shouldBeSearchable() لا يطبق على Database Engine لأن البيانات الأصلية موجودة بالفعل في قاعدة البيانات؛ في هذه الحالة استخدم شروط البحث المناسبة.
استخدام Laravel Queues مع Scout
عند استخدام Engine خارجي، يوصي التوثيق الرسمي بشدة باستخدام Queue حتى لا ينتظر المستخدم عملية مزامنة Search Index أثناء Request.
'queue' => true,ويمكن تخصيص Connection وQueue:
'queue' => [
'connection' => 'redis',
'queue' => 'scout',
],ثم تشغيل Worker:
php artisan queue:work redis --queue=scoutراجع أيضًا توثيق Laravel Queues الرسمي عند إعداد Workers للإنتاج.
Unique Indexing Jobs
في التطبيقات ذات الكتابة المكثفة قد يتم إرسال أكثر من Job لنفس السجل قبل معالجة السابقة. يوفر Scout إمكانية استخدام Jobs فريدة:
use Laravel\Scout\Jobs\MakeSearchableUniquely;
use Laravel\Scout\Jobs\RemoveFromSearchUniquely;
use Laravel\Scout\Scout;
Scout::makeSearchableUsing(MakeSearchableUniquely::class);
Scout::removeFromSearchUsing(RemoveFromSearchUniquely::class);تستخدم هذه Jobs آلية Unique Job Locks في Laravel لتقليل العمليات المكررة لنفس Model Record أثناء انتظار Jobs في Queue.
تنفيذ عمليات البحث
API الأساسية بسيطة:
$articles = Article::search('Laravel Scout')->get();يمكن أيضًا الوصول إلى النتائج الخام التي يعيدها Search Engine قبل تحويلها إلى Eloquent Models:
$results = Article::search('Laravel Scout')->raw();تحميل العلاقات مع النتائج
use Illuminate\Database\Eloquent\Builder;
$articles = Article::search('Laravel Scout')
->query(fn (Builder $query) => $query->with('author'))
->get();مع Third-Party Engines يتم تنفيذ Callback الخاص بـ query() بعد أن يكون Search Engine قد حدد النتائج. لذلك لا تستخدمه كبديل لفلاتر Scout؛ استخدم where() للفلاتر التي يجب أن تؤثر في مجموعة نتائج البحث نفسها.
الفلاتر باستخدام Where Clauses
يمكن دمج البحث النصي مع شروط إضافية:
$articles = Article::search('Laravel')
->where('author_id', 10)
->get();ويدعم Scout معاملات مقارنة متعددة:
$products = Product::search('keyboard')
->where('status', '=', 'active')
->where('price', '>', 50)
->where('price', '<=', 300)
->get();كما يدعم:
$orders = Order::search('Laravel')
->whereIn('status', ['open', 'paid'])
->get();
$orders = Order::search('Laravel')
->whereNotIn('status', ['cancelled'])
->get();عند استخدام Meilisearch، يجب إعداد الحقول المستخدمة في where() كـ Filterable Attributes أولًا.
Pagination لنتائج البحث
$articles = Article::search('Laravel')->paginate(15);يعيد Scout LengthAwarePaginator كما في Eloquent، لذلك يمكنك استخدام Pagination المعتادة في Blade أو API.
وعند استخدام Database Engine، يدعم Scout أيضًا:
$articles = Article::search('Laravel')->simplePaginate(15);simplePaginate() لا يحتاج إلى حساب العدد الإجمالي الكامل للنتائج، لذلك قد يكون أكثر كفاءة عندما تحتاج فقط إلى Previous وNext.
Semantic Search وHybrid Search في Laravel Scout
البحث النصي التقليدي يبحث عن الكلمات أو أشكال قريبة منها. أما Semantic Search فيحاول مطابقة المعنى.
مثلاً، قد يبحث المستخدم عن:
how to keep an application fast under heavy trafficوقد يكون لديك مقال بعنوان "Scaling Laravel Applications". لا توجد مطابقة حرفية قوية، لكن المعنى قد يكون قريبًا.
يدعم Scout الحالي Semantic Search عبر Database وMeilisearch وTypesense وTurbopuffer بعد إعداد Embeddings المطلوبة.
$articles = Article::search('staying cool in the summer')
->semantic()
->get();وبعض المحركات تسمح بتحديد Minimum Similarity:
$articles = Article::search('renewable energy storage')
->semantic(minSimilarity: 0.6)
->get();Hybrid Search
Hybrid Search يجمع بين Text Search وSemantic Search:
$articles = Article::search('renewable energy storage')
->hybrid(
textWeight: 1,
semanticWeight: 2
)
->get();بهذا تستطيع إعطاء أهمية أكبر للمعنى أو للكلمات نفسها حسب طبيعة التطبيق.
لا تضف Semantic Search لمجرد أنه أحدث تقنية. ابدأ من سلوك مستخدميك: إذا كان البحث عن أسماء Products أو IDs أو Codes، فقد يكون Keyword Search أدق وأرخص. أما المحتوى الطويل والأسئلة الطبيعية فقد يستفيد أكثر من البحث الدلالي.
التعامل مع Soft Deletes
إذا كنت تستخدم SoftDeletes وتحتاج إلى إبقاء السجلات المحذوفة منطقيًا قابلة للبحث، فعّل:
'soft_delete' => true,عند تفعيل الخيار، لا يزيل Scout السجل من Search Index عند Soft Delete، بل يضيف حالة داخلية باسم __soft_deleted.
بعدها تستطيع استخدام:
$articles = Article::search('Laravel')
->withTrashed()
->get();
$deletedArticles = Article::search('Laravel')
->onlyTrashed()
->get();إعداد Laravel Scout للإنتاج
1. استخدم Queue للمحركات الخارجية
اجعل تحديث Search Index مهمة Background حتى لا يتأثر Response Time للمستخدم.
2. شغّل Queue Workers بصورة دائمة
وجود 'queue' => true دون Worker يعني أن Index لن يتحدث حتى تتم معالجة Jobs.
3. مزامنة إعدادات Index أثناء Deployment
عند استخدام Algolia أو Meilisearch وإدارة Index Settings من config/scout.php، شغّل:
php artisan scout:sync-index-settingsيمكن أن يصبح هذا الأمر جزءًا من Deployment Pipeline.
4. استورد البيانات عند إنشاء Index جديد
php artisan scout:import "App\Models\Article"للمجموعات الكبيرة:
php artisan scout:queue-import "App\Models\Article" --chunk=5005. افصل إعدادات البيئات
استخدم Credentials وIndexes مستقلة للتطوير والاختبار والإنتاج حتى لا يكتب Developer Machine داخل Production Index عن طريق الخطأ.
الأمان والخصوصية في Laravel Scout
لا تفهرس بيانات أكثر مما تحتاج
عند استخدام محرك خارجي، كل قيمة ترجعها من toSearchableArray() قد تنتقل إلى مزود البحث. لذلك لا ترسل Password Hashes أو Tokens أو معلومات داخلية أو بيانات شخصية لا تحتاج إليها عملية البحث.
احتفظ بمفاتيح Search Engine خارج Git
MEILISEARCH_KEY=...
TYPESENSE_API_KEY=...
TURBOPUFFER_API_KEY=...يجب أن توجد الأسرار في Environment Variables أو Secret Manager، لا داخل Repository.
لا تعتبر Search Index طبقة Authorization
وجود Record داخل Search Index لا يعني أن المستخدم الحالي مخول لرؤيته. طبّق Permissions المناسبة في التطبيق، واستخدم فلاتر مرتبطة بالمستخدم أو المؤسسة عندما تكون البيانات متعددة المستأجرين.
انتبه إلى SCOUT_IDENTIFY مع Algolia
يوفر Scout خيار SCOUT_IDENTIFY=true عند استخدام Algolia لربط عمليات البحث بالمستخدم. وفق التوثيق الرسمي، يؤدي ذلك إلى إرسال IP Address ومعرف المستخدم المصادق عليه إلى Algolia. لذلك يجب أن يكون تفعيله متوافقًا مع سياسة الخصوصية لديك.
تحسين أداء Laravel Scout
قلل حجم Search Document
كلما كان toSearchableArray() أكثر دقة، انخفض حجم البيانات التي يتم إرسالها وتخزينها ومعالجتها.
استخدم Database Full-Text بدل LIKE عند الحاجة
إذا كان Database Engine كافيًا لمشروعك، فإضافة Full-Text Index للحقول المناسبة قد تكون أكثر كفاءة من البحث عبر %term%.
لا تستخدم Collection Engine لآلاف السجلات
Collection Engine يجلب البيانات ثم يبحث داخل PHP؛ هذه راحة للتطوير وليست استراتيجية Scale.
استخدم Queued Indexing
لا تجعل المستخدم ينتظر API Call إلى Search Provider بعد كل Update إذا لم تكن هناك حاجة لذلك.
استخدم Unique Jobs في Write-Heavy Applications
إذا كان Model يتغير عدة مرات بسرعة، فقد تقلل Unique Indexing Jobs من عمليات Indexing المتكررة.
اختر الحقول القابلة للفلترة والترتيب بعناية
بعض المحركات تحتاج إلى تعريف Filterable وSortable Fields مسبقًا. لا تحول كل حقل إلى Facet أو Filter لمجرد إمكانية ذلك.
قيّم الحاجة إلى Semantic Search
Embeddings تضيف تكلفة حسابية وتخزينية. استخدمها عندما تضيف قيمة فعلية لتجربة البحث.
مثال عملي: بناء بحث لمقالات تقنية
سننشئ Model للمقالات بحيث تظهر المقالات المنشورة فقط في Search Index الخارجي.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Article extends Model
{
use Searchable;
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'title' => $this->title,
'summary' => $this->summary,
'body' => $this->body,
'category_id' => $this->category_id,
'published_at' => $this->published_at?->timestamp,
];
}
public function shouldBeSearchable(): bool
{
return $this->status === 'published';
}
}ثم Controller للبحث:
<?php
namespace App\Http\Controllers;
use App\Models\Article;
use Illuminate\Http\Request;
class ArticleSearchController extends Controller
{
public function __invoke(Request $request)
{
$query = (string) $request->string('q');
$articles = Article::search($query)
->when(
$request->filled('category'),
fn ($search) => $search->where(
'category_id',
$request->integer('category')
)
)
->paginate(15);
return response()->json($articles);
}
}وعند إضافة Scout إلى مشروع قائم:
php artisan scout:import "App\Models\Article"بعد ذلك، أي عملية save() أو create() على Model القابل للبحث ستؤدي إلى مزامنة Index تلقائيًا، ومع Queue سيتم تنفيذ هذه المزامنة في الخلفية.
Laravel Scout مقارنة بالبدائل
Scout مقابل Eloquent LIKE
استعلام LIKE البسيط قد يكون كافيًا لمشروع صغير. Scout يصبح أكثر فائدة عندما تريد API موحدة، Full-Text Strategies، Engine خارجيًا، Ranking، Filtering، Pagination أو Semantic Search.
Scout مقابل استخدام SDK لمحرك البحث مباشرة
استخدام SDK مباشرة يمنحك الوصول إلى كل ميزة خاصة بالمزود، لكنه يربط التطبيق بتفاصيله. Scout يقلل هذا الاقتران ويهتم بمزامنة Models ويقدم API متجانسة.
ومع ذلك لا يمنعك Scout من النزول إلى مستوى Engine نفسه؛ يوفر التوثيق طرقًا لتخصيص Search Engine Query عندما تحتاج ميزة خاصة بالمزود.
Scout ليس بديلًا عن Elasticsearch بحد ذاته
Scout ليس Search Server. هو Integration Layer. إذا كنت تحتاج Engine غير مدعوم افتراضيًا، يستطيع Laravel Scout دعم Custom Engines عبر تنفيذ Contract الخاص بمحركات Scout.
أخطاء شائعة عند استخدام Laravel Scout
الخطأ 1: إضافة Searchable Trait ثم نسيان استيراد البيانات القديمة
السجلات الجديدة ستتم مزامنتها، لكن البيانات الموجودة قبل تثبيت Scout تحتاج إلى scout:import عند استخدام Third-Party Engine.
الخطأ 2: تفعيل Queue دون تشغيل Worker
النتيجة: قاعدة البيانات تتحدث لكن Search Index يبقى قديمًا.
الخطأ 3: إرسال كل Model إلى Search Provider
الاعتماد على toArray() دون مراجعة قد يؤدي إلى تخزين حقول غير مطلوبة أو حساسة.
الخطأ 4: استخدام Collection Engine على Dataset كبيرة
هذا المحرك مصمم أساسًا للبيانات الصغيرة جدًا والاختبارات.
الخطأ 5: استخدام where مع Meilisearch دون Filterable Attributes
يجب تعريف الحقول المطلوبة في Index Settings ثم مزامنة الإعداد.
الخطأ 6: استخدام query() كفلتر بعد Third-Party Search
عند المحركات الخارجية، Search Engine يكون قد حدد النتائج أصلًا. استخدم Scout Where Clauses للفلاتر.
الخطأ 7: الاعتماد على Global Scopes مع Pagination
Search Engines لا تعرف Global Scopes الخاصة بـ Eloquent. يجب إعادة تطبيق القيود المناسبة في Search Query.
الخطأ 8: تغيير Index Settings ونسيان مزامنتها
php artisan scout:sync-index-settingsالخطأ 9: إضافة Semantic Search دون استراتيجية Embeddings
البحث الدلالي يحتاج إلى Vector Data صحيحة وإعداد Engine مناسب؛ استدعاء semantic() وحده ليس إعدادًا كاملًا.
أفضل الممارسات مع Laravel Scout
- ابدأ بـ Database Engine إذا كانت متطلبات البحث بسيطة ولا تحتاج بنية إضافية.
- استخدم Third-Party Engine عندما تحتاج إمكانات Ranking أو Search UX أو Scale تتجاوز قاعدة البيانات.
- خصص
toSearchableArray()ولا ترسل كل البيانات افتراضيًا. - اجعل Queueing جزءًا من تصميم الإنتاج للمحركات الخارجية.
- راقب Failed Jobs لأن فشل Indexing قد يسبب اختلافًا بين قاعدة البيانات ونتائج البحث.
- اجعل
scout:sync-index-settingsجزءًا من Deployment عند إدارة Settings من التطبيق. - استخدم
scout:queue-importللبيانات الكبيرة. - استخدم Unique Jobs عندما يكون Model عرضة لتحديثات متكررة بسرعة.
- لا تعتمد على Search Index لتنفيذ Authorization.
- استخدم Filters داخل Scout بدل محاولة فلترة النتائج بعد استرجاعها.
- اختبر Relevance وليس Response Time فقط.
- استخدم Full-Text Indexes الصحيحة عند Database Engine.
- استخدم Semantic Search للمحتوى الذي يستفيد فعلًا من فهم المعنى.
- افصل Credentials وIndexes بين Development وStaging وProduction.
- خطط لإعادة بناء Index بالكامل إذا تغير Schema بصورة جوهرية.
الأسئلة الشائعة حول Laravel Scout
هل Laravel Scout هو محرك بحث؟
لا. هو طبقة تكامل رسمية بين Laravel/Eloquent ومحركات البحث أو قاعدة البيانات.
هل أحتاج Algolia أو Meilisearch لاستخدام Scout؟
لا. يوفر Scout Database Engine وCollection Engine دون خدمة بحث خارجية.
ما قواعد البيانات التي يدعمها Database Engine؟
التوثيق الحالي يحدد MySQL وPostgreSQL لـ Database Engine.
هل يحتاج Database Engine إلى scout:import؟
لا، لأنه يبحث مباشرة داخل جداول قاعدة البيانات ولا يحتفظ بـ Search Index منفصل.
متى أستخدم Collection Engine؟
للاختبارات والـ Prototypes ومجموعات البيانات الصغيرة جدًا. لا ينصح به للبيانات الكبيرة.
هل يدعم Scout Semantic Search؟
نعم. Laravel Scout 13.x يدعم Semantic Search عبر Database Engine وMeilisearch وTypesense وTurbopuffer، وفق متطلبات كل Engine.
هل يدعم Hybrid Search؟
نعم. يمكنك استخدام hybrid() للجمع بين Text وSemantic Search مع التحكم بأوزان كل منهما.
هل Database Semantic Search يعمل على MySQL؟
وفق التوثيق الحالي، Semantic وHybrid Search للـ Database Engine يتطلبان PostgreSQL مع امتداد pgvector.
هل يجب استخدام Queues؟
ليست مطلوبة للـ Database وCollection Engines، لكن التوثيق يوصي بقوة باستخدام Queue مع المحركات الخارجية لتحسين زمن استجابة واجهة التطبيق.
ماذا يحدث عند تحديث Model؟
عند استخدام Searchable Trait يراقب Scout تغيرات Model ويزامنها تلقائيًا مع Index الخاص بالمحرك المستخدم.
كيف أعيد بناء Index؟
يمكنك إزالة السجلات ثم إعادة استيرادها:
php artisan scout:flush "App\Models\Article"
php artisan scout:import "App\Models\Article"هل يمكن استخدام Engine مختلف لكل Model؟
نعم، باستخدام searchableUsing().
هل يمكن البحث في السجلات المحذوفة Soft Delete؟
نعم، عند تفعيل soft_delete ثم استخدام withTrashed() أو onlyTrashed().
هل Scout مناسب للبحث متعدد المستأجرين Multi-Tenant؟
يمكن استخدامه، لكن يجب تصميم Filters وIndex Data بحيث تضمن عدم إعادة نتائج Tenant آخر، مع إبقاء Authorization داخل التطبيق.
الخلاصة
Laravel Scout يحل واحدة من أكثر المشكلات تكرارًا في التطبيقات التي تنمو تدريجيًا: كيف تضيف بحثًا متقدمًا دون تحويل التطبيق إلى مجموعة من Integrations المتفرقة مع Search Providers.
يمكنك البدء بأبسط صورة عبر Database Engine والاستفادة من Full-Text Search وPrefix Strategies دون أي خدمة إضافية، ثم الانتقال إلى Meilisearch أو Typesense أو Algolia أو Turbopuffer عندما تحتاج إمكانات أوسع.
وفي Laravel 13 توسع دور Scout بصورة مهمة مع دعم Semantic وHybrid Search، بما في ذلك PostgreSQL وpgvector في Database Engine. هذا يجعل Scout طبقة موحدة ليس فقط للبحث بالكلمات، بل أيضًا لبناء تجارب بحث تفهم معنى Query عند الحاجة.
لكن جودة البحث لا تأتي من تثبيت الحزمة وحدها. النجاح يعتمد على اختيار Engine المناسب، تصميم toSearchableArray() بعناية، إعداد الفهارس والفلاتر، استخدام Queues بصورة صحيحة، ومراقبة التزامن بين قاعدة البيانات وSearch Index.
التعليقات (0)
لا توجد تعليقات بعد — كن أول من يشارك رأيه.
أضف تعليقك