
# Индексирано търсене в AST

Индексираното търсене в AST е вариантът с предварително зареден кеш на [търсенето в AST](https://greph.inline0.dev/bg/docs/modes/ast). При първото извикване се извличат факти на ниво възел (имена на извиквания, инстанции, декларации на класове и декларации на методи) и се записват на диска; при следващите извиквания хранилището се използва за пропускане на файлове, които очевидно не могат да съдържат структурно съвпадение. След това съпоставителят проверява отново кандидатите спрямо изходния код.

Индексът на факти е достъпен чрез подкомандата `greph-index ast-index` CLI и методите на фасада `Greph::buildAstIndex()` / `Greph::searchAstIndexed()`. Той участва и в работните процеси с предварително заредени индекси в няколко набора, както и в тези, чиито набори се описват с манифест.

## Създаване на индекса

```bash
# Full build at the current directory
./vendor/bin/greph-index ast-index build .

# Full build at an explicit root
./vendor/bin/greph-index ast-index build path/to/repo

# Use a non-default index directory
./vendor/bin/greph-index ast-index build . --index-dir /tmp/greph-ast-index

# Build a mutable overlay that can refresh cheaply on demand
./vendor/bin/greph-index ast-index build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576
```

По подразбиране индексът на факти се съхранява в `<root>/.greph-ast-index/`.

При успешно създаване се извежда едноредово обобщение:

```text
Built AST index for 2547 files in .greph-ast-index (84931 fact rows, +2547 ~0 -0 =0)
```

Четирите брояча показват добавените, обновените, изтритите и непроменените файлове след последното създаване.

## Обновяване на индекса

```bash
./vendor/bin/greph-index ast-index refresh .
```

`refresh` обхожда отново индексирания корен, анализира отново променените файлове и пренаписва само променените редове с факти. Изходът използва същите четири брояча като текстовия индекс.

Профилите за жизнения цикъл работят по същия начин като при предварително заредените текстови индекси:

- `static`: никога не проверява актуалността и не променя автоматично
- `manual-refresh`: отчита остаряло състояние в `stats`, но никога не обновява при търсене
- `opportunistic-refresh`: обновява при търсене само ако наборът от промени е достатъчно малък
- `strict-stale-check`: отхвърля търсенията с остарели данни, вместо да обновява

## Заявки към индекса

```bash
./vendor/bin/greph-index ast-index search 'new $CLASS()' src
./vendor/bin/greph-index ast-index search '$obj->$method($$$ARGS)' src
./vendor/bin/greph-index ast-index search --json 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search -l 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search --trace-plan 'new $CLASS()' src
```

Синтаксисът на метапроменливите е идентичен с този при нативното търсене в AST. Вижте [Режими / Търсене в AST](https://greph.inline0.dev/bg/docs/modes/ast) за пълната граматика.

### Опции

| Флаг | Значение |
|---|---|
| `--lang NAME` | Език на AST. По подразбиране: `php` |
| `-j N`, `--jobs N` | Брой паралелни работници |
| `-l`, `--files-with-matches` | Изброява само съвпадащите файлове |
| `--glob GLOB` | Включва само файлове, чиито пътища съвпадат с GLOB |
| `--type NAME` / `--type-not NAME` | Филтър по тип файл |
| `--json` | Извежда изход във формат JSON |
| `--no-ignore` | Игнорира `.gitignore` и `.grephignore` |
| `--hidden` | Включва скритите файлове |
| `--strict-parse` | Прекратява при грешки при анализиране, вместо да ги пропуска |
| `--fallback MODE` | Поведение при липсващ индекс: `fail` (по подразбиране) или `scan` |
| `--index-dir DIR` | Използва директория за индекс, различна от тази по подразбиране |
| `--trace-plan` | Извежда диагностиката на планировчика за предварително зареден AST в `stderr` |
| `--show-index-origin` | Добавя към изхода етикета на съвпадащия индекс в режим с няколко индекса или набори |

### Резервен режим при липсващ индекс

По подразбиране `ast-index search` извежда грешка, когато на посоченото място няма индекс. Подайте `--fallback scan`, за да преминете към нативно сканиране на AST. Това е подходящата настройка за инструменти, които използват индексирано търсене, когато има индекс, но трябва да извеждат резултати и преди създаването му.

```bash
./vendor/bin/greph-index ast-index search --fallback scan 'new $CLASS()' src
```

### Търсене в няколко индекса

Можете да търсите в няколко предварително заредени индекса на AST с една команда, като повторите `--index-dir`. Това е полезно за оформления като ядро на WordPress плюс плъгин или тема.

```bash
./vendor/bin/greph-index ast-index search \
  --index-dir ../wordpress/.greph-ast-index \
  --index-dir ./.greph-ast-index \
  --show-index-origin \
  'new $CLASS()' .
```

Когато `--show-index-origin` е активиран, към изхода се добавя името на съвпадналия запис в предварително заредения индекс, за да виждате кой корен е дал резултата.

### Набори от индекси с манифест

За стабилни конфигурации с предварително заредени индекси задайте манифест и позволете на `greph-index set` да работи с групираните индекси:

```bash
./vendor/bin/greph-index set build
./vendor/bin/greph-index set stats --mode ast-index --dry-refresh
./vendor/bin/greph-index set search --mode ast-index --show-index-origin 'new $CLASS()' .
```

Подкомандите за набори споделят същата обработка на жизнения цикъл, проверки за остарели данни и диагностика на планировчика като прякото използване на `ast-index`.

### Диагностика на планировчика

`--trace-plan` показва как Greph е стеснил заявката, преди да стартира пълният съпоставител. За `ast-index` това обикновено включва:

- грубия подпис на факти, извлечен от шаблона
- броя на претърсените предварително заредени индекси
- броя на файловете, отхвърлени от филтъра за факти
- броя на файловете кандидати, анализирани повторно за точна структурна проверка

## Какво съхранява индексът

За всеки индексиран файл извличателят на факти от AST записва по един ред за всеки „интересен“ възел. Видовете факти обхващат конструкциите, към които най-често са насочени шаблоните за AST:

- Извиквания на функции и методи (по име на извиканото)
- Инстанции на класове (по име на класа)
- Декларации на класове, интерфейси, трейтове и enum-и (по име)
- Декларации на функции (по име)
- Декларации на методи (по име и видимост)
- Инструкции use

Когато постъпи заявка, `Greph\Ast\AstFactQuery` преобразува шаблона за търсене в груб подпис на факти (например „трябва да съдържа `new` от произволен клас“) и търси пресечението в хранилището с факти. След това оцелелите при тази проверка файлове се анализират отново и се съпоставят с пълния шаблон.

Това означава, че индексът на факти е *предварителен филтър*, а не хранилище за пълноценни съвпадения. Стъпката на съпоставяне все пак анализира изходния код, така че структурната коректност е същата като при нативното търсене в AST; по-малък е само наборът от кандидати.

## Кога да го използвате

Индексираният режим на AST е подходящият инструмент, когато:

- Повтаряте едни и същи структурни заявки върху една и съща кодова база.
- Шаблоните търсят разпознаваеми форми (име на извикване, име на клас, вид декларация), които извличателят на факти съхранява.
- Искате по-ниска латентност от тази при повторно анализиране на всеки файл.

За шаблони, чиято отличителна черта не присъства в набора от факти (например сложни вложени изрази без разпознаваема начална част), [кешираният режим на AST](https://greph.inline0.dev/bg/docs/indexed/cache) обикновено е по-подходящ, защото изцяло пропуска стъпката на анализиране, без да разчита на груб подпис.

## Програмно използване

```php
use Greph\Greph;
use Greph\Ast\AstSearchOptions;
use Greph\Index\IndexLifecycleProfile;

Greph::buildAstIndex('.', lifecycle: IndexLifecycleProfile::OpportunisticRefresh);

$matches = Greph::searchAstIndexed(
    'new $CLASS()',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);
```

`searchAstIndexed` приема същия `AstSearchOptions` като нативното търсене в AST и връща същата структура на `list<AstMatch>`. За работни процеси с няколко индекса или с набори, описани чрез манифест, използвайте `searchAstIndexedMany(...)` и `searchAstIndexedSet(...)`.
