Индексирано търсене в текст
Индексираното търсене в текст е вариантът с предварително загрят кеш на търсенето в текст. При първото извикване се изгражда дисково хранилище на триграми и публикации на идентификатори; следващите извиквания използват хранилището, за да пропускат файлове, които очевидно не могат да съдържат шаблона. Така латентността при повтарящи се заявки към големи хранилища става много по-ниска, без да се добавя демон или процес наблюдател.
Обхватът на загрятото търсене в текст вече включва:
- търсене в един индекс
- повтарящо се търсене в множество индекси
--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 задачи, цикли на агенти, IDE интеграции).
- Хранилището е достатъчно голямо, за да се превърне нативното сканиране в тясно място.
- Шаблоните включват буквални поднизове или токени на идентификатори, които индексът може предварително да филтрира.
Нативното сканиране все още е подходящият инструмент, когато:
- Търсите в малко хранилище, където разходът за изграждане на индекса е по-голям.
- Търсите еднократно в път, който няма да заявявате отново.
- Нуждаете се от всички съвпадения при еднократно импровизирано извикване и не искате да поддържате индекс.
Публикуваните бенчмарк резултати в 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(...).