البحث النصي المفهرس
البحث في النص المفهرس هو النسخة ذات الذاكرة المؤقتة المُهيأة من البحث النصي. ينشئ الاستدعاء الأول مخزنًا على القرص للثلاثيات وقوائم مواضع المعرّفات؛ وتستخدم الاستدعاءات اللاحقة المخزن لتجاوز الملفات التي لا يمكن أن تحتوي على النمط بوضوح. والنتيجة زمن استجابة أقل بكثير عند تكرار الاستعلامات في المستودعات الكبيرة، من دون تشغيل عملية خدمة أو مراقبة.
تشمل إمكانات البحث النصي الدافئ الآن:
- البحث بفهرس واحد
- البحث المتكرر متعدد الفهارس
--index-dir - البحث ضمن مجموعة مدعومة ببيان
- التعامل مع الفهارس القديمة وفق دورة حياتها
- تشخيصات المخطط عبر
--trace-plan
يتاح الفهرس عبر greph-index CLI وطريقتَي الواجهة Greph::buildTextIndex() / Greph::searchTextIndexed().
إنشاء الفهرس
# Full build at the current directory
./vendor/bin/greph-index build .
# Full build at an explicit root
./vendor/bin/greph-index build path/to/repo
# Use a non-default index directory
./vendor/bin/greph-index build . --index-dir /tmp/greph-index
# Build with an explicit lifecycle policy
./vendor/bin/greph-index build . \
--lifecycle opportunistic-refresh \
--auto-refresh-max-files 32 \
--auto-refresh-max-bytes 1048576
يُخزَّن الفهرس افتراضيًا في <root>/.greph-index/.
يعرض الإنشاء الناجح ملخصًا في سطر واحد:
Built index for 2547 files in .greph-index (193428 trigrams, +2547 ~0 -0 =0)
العدادات الأربعة هي أعداد الملفات المضافة والمحدّثة والمحذوفة وغير المتغيرة. في إنشاء جديد، يساوي عداد الملفات المضافة عدد الملفات، وتكون بقية العدادات صفرًا.
تحديث الفهرس
./vendor/bin/greph-index refresh .
يعيد refresh اجتياز الجذر المفهرس، ويحسب تجزئة كل ملف، ثم يعيد كتابة الإدخالات التي تغيرت بياناتها الوصفية فقط. يستخدم الناتج العدادات الأربعة نفسها لتتمكن من معرفة ما تغير بدقة:
Refreshed index for 2547 files in .greph-index (193428 trigrams, +3 ~7 -1 =2536)
شغّل refresh بعد تعديل الملفات المتتبعة عند استخدام manual-refresh. أما في الفهارس opportunistic-refresh، فيمكن لـGreph تحديث الفهرس تلقائيًا أثناء البحث إذا كانت مجموعة التغييرات لا تزال صغيرة بما يكفي.
ملفات تعريف دورة الحياة
يظل Greph بلا خدمة خلفية. وتتحكم ملفات تعريف دورة الحياة في سلوك الفهرس الدافئ عند تغير شجرة المصدر:
static: لا يتحقق مطلقًا من حداثة البيانات ولا يجري تعديلات تلقائيةmanual-refresh: يعرض معلومات التقادم فيstats، دون تحديث أثناء البحث مطلقًاopportunistic-refresh: يحدّث أثناء البحث فقط إذا كانت مجموعة التغييرات دون الحدود المضبوطةstrict-stale-check: يرفض عمليات البحث الدافئة على الفهارس القديمة بدلًا من تحديثها
استخدم greph-index stats --dry-refresh لمعاينة ما سيفعله البحث الدافئ قبل تشغيله:
./vendor/bin/greph-index stats . --dry-refresh
الاستعلام في الفهرس
# Fixed-string search
./vendor/bin/greph-index search -F "function" .
# Case-insensitive whole-word
./vendor/bin/greph-index search -F -i -w "function" .
# Counts
./vendor/bin/greph-index search -F -c "function" .
# Files only
./vendor/bin/greph-index search -F -l "function" .
# Multi-index search
./vendor/bin/greph-index search -F "apply_filters" . \
--index-dir wordpress/.greph-index \
--index-dir wp-content/plugins/my-plugin/.greph-index \
--show-index-origin
# Regex search
./vendor/bin/greph-index search "function\s+\w+" .
# JSON output
./vendor/bin/greph-index search --json -F "function" .
# Planner trace to stderr
./vendor/bin/greph-index search --trace-plan -F "function" .
مجموعة الأعلام هي نفسها المستخدمة في البحث النصي الأصلي. راجع مرجع CLI للاطلاع على القائمة الكاملة.
إذا لم يكن الفهرس موجودًا في الموقع المطلوب، يصدر greph-index search خطأً. لا يوجد في هذا الأمر رجوع تلقائي إلى فحص غير مفهرس (تتيح أوامر AST خيار --fallback scan، لكن الأمر النصي لا يتيحه). أنشئ الفهرس أولًا.
مجموعات الفهارس المسماة
إذا كنت تبحث مرارًا في البنية الدافئة نفسها، فاستخدم بيانًا بدلًا من تكرار أعلام --index-dir:
{
"name": "wordpress-local",
"indexes": [
{
"name": "core-text",
"root": "wordpress",
"mode": "text",
"lifecycle": "static",
"priority": 100
},
{
"name": "plugin-text",
"root": "wp-content/plugins/my-plugin",
"mode": "text",
"lifecycle": "opportunistic-refresh",
"max_changed_files": 16,
"max_changed_bytes": 262144,
"priority": 200
}
]
}
احفظه باسم .greph-index-set.json، ثم:
./vendor/bin/greph-index set build
./vendor/bin/greph-index set stats --dry-refresh
./vendor/bin/greph-index set search --show-index-origin -F "apply_filters" .
ما الذي يخزنه الفهرس
فهرس النص مخزن للثلاثيات ونشرات المعرّفات. يستخرج Greph لكل ملف مفهرس ما يلي:
- مجموعة الثلاثيات: مجموعة تسلسلات من ثلاثة بايتات موجودة في محتوى الملف. تُستخدم كمرشح أولي تقريبي للاستعلامات الحرفية واستعلامات التعابير النمطية.
- نشرات المعرّفات: مجموعة الرموز التي تشبه المعرّفات (
[A-Za-z_][A-Za-z0-9_]*) الموجودة في الملف. تُستخدم لتسريع استعلامات الكلمات الكاملة. - بيانات دورة الحياة الوصفية: الحدود المضبوطة وسلوك التحقق من التقادم.
- بيانات المحتوى الوصفية: الحجم ووقت التعديل لاتخاذ قرارات التحديث وفحص التقادم.
عند ورود استعلام، يستخرج Greph الأنماط نفسها من النمط (الثلاثيات من المقاطع الحرفية، ورموز المعرّفات من أنماط الكلمات الكاملة)، ويقاطع النشرات، ثم يعيد قراءة الملفات المطابقة فقط. وتُبحث الملفات التي تجتاز التقاطع باستخدام المحرك نفسه المستخدم في وضع النص الأصلي.
في بعض استعلامات الملخص الدافئة، يستطيع Greph تقديم الإجابة مباشرةً من النشرات:
-lللكلمة الكاملة-Lللكلمة الكاملة-qللكلمة الكاملة
يُجنّب ذلك إعادة فتح الملفات المرشحة تمامًا عندما تثبت النشرات الإجابة مسبقًا.
هذه الفكرة مماثلة للفهرسة الأولية الاختيارية في ripgrep وفهرس الثلاثيات في codesearch، لكنها مصممة خصيصًا للأنماط المخزنة على القرص التي يستطيع PHP الدافئ الوصول إليها بأعلى سرعة.
تشخيصات المخطط
يرسل --trace-plan قرار مخطط البحث النصي الدافئ إلى stderr، مع إبقاء تدفق النتائج العادي دون تغيير.
يتضمن التتبع:
- ملف تعريف دورة الحياة
- عدد الملفات المحدد
- مصدر المرشحين (
full-scanأوtrigram-postingsأوword-postingsأوinvert-scan) - عدد مصطلحات النشرات
- أعداد الملفات المرشحة والمتحقق منها
- أهلية الملخص المباشر
- أهلية ذاكرة الاستعلام المؤقتة وقرار ملئها
متى تستخدمه
يكون الوضع المفهرس هو الخيار المناسب عندما:
- تستعلم عن المستودع نفسه مرات عديدة متتالية (مهام CI وحلقات الوكلاء وتكاملات بيئات التطوير).
- يكون المستودع كبيرًا بما يكفي ليصبح الفحص الأصلي عنق الزجاجة.
- تتضمن الأنماط مقاطع حرفية أو رموز معرّفات يمكن للفهرس استخدامها كمرشح أولي.
يظل الفحص الأصلي هو الخيار المناسب عندما:
- تستعلم عن مستودع صغير تهيمن فيه تكلفة إنشاء الفهرس.
- تبحث في مسار لمرة واحدة لن تستعلم عنه مجددًا.
- تحتاج إلى كل المطابقات في استدعاء مخصص واحد ولا تريد صيانة فهرس.
تُظهر أرقام الأداء المنشورة في README أن الوضع المفهرس الدافئ يتقدم على كل من rg وgrep في استعلامات التعابير النمطية، وكذلك استعلامات العدّ والملفات ذات المطابقات والملفات التي بلا مطابقات على مجموعة البيانات WordPress. أما في الاستعلامات الحرفية البسيطة، فيتفوق على grep لكنه يظل أبطأ قليلًا من rg.
الاستخدام البرمجي
use Greph\Greph;
use Greph\Text\TextSearchOptions;
use Greph\Index\IndexLifecycleProfile;
// Build once
Greph::buildTextIndex('.', lifecycle: IndexLifecycleProfile::OpportunisticRefresh);
// Refresh after edits
Greph::refreshTextIndex('.');
// Query
$results = Greph::searchTextIndexed(
'function',
'src',
new TextSearchOptions(fixedString: true),
);
يقبل searchTextIndexed قيم TextSearchOptions نفسها التي يقبلها البحث النصي الأصلي، ويعيد بنية list<TextFileResult> نفسها. لتدفقات العمل متعددة الفهارس أو المدعومة ببيان، استخدم searchTextIndexedMany(...) وsearchTextIndexedSet(...).