
# Кеширано търсене в AST

Кешираното търсене в AST е допълващ режим с предварително зареден кеш към [индекса на факти](https://greph.inline0.dev/bg/docs/indexed/ast). Вместо да съхранява извлечени факти и да анализира повторно съвпадналите файлове, кешът съхранява сериализирани анализирани дървета на диска. При следващите заявки дърветата се десериализират и съпоставителят се изпълнява директно, като изцяло се пропуска конвейерът PHP-Parser.

Кешът е достъпен чрез подкомандата `greph-index ast-cache` CLI и методите на фасада `Greph::buildAstCache()` / `Greph::searchAstCached()`. Поддържа и търсене в няколко индекса, както и в набори, описани чрез манифест.

## Създаване на кеша

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

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

# Build a cache that may refresh automatically for small changes
./vendor/bin/greph-index ast-cache build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576
```

По подразбиране кешът се съхранява в `<root>/.greph-ast-cache/`. Създаването на кеш обикновено е най-бавният от трите режима за индексиране, защото всеки файл трябва да бъде анализиран веднъж.

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

```text
Built AST cache for 2547 files in .greph-ast-cache (2541 cached trees, +2541 ~0 -0 =0)
```

Броят на кешираните дървета обикновено е малко по-нисък от броя на файловете, защото файловете, които не могат да бъдат анализирани (и се пропускат без предупреждение), не създават запис в кеша. Подайте `--strict-parse` към командата за търсене, ако искате грешките при анализиране да се показват.

## Обновяване на кеша

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

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

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

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

## Заявки към кеша

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

Наборът от флагове е идентичен с този за [`ast-index search`](https://greph.inline0.dev/bg/docs/indexed/ast#querying-the-index), включително `--fallback scan` за липсващи кешове.

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

Повторете `--index-dir`, за да търсите в няколко предварително заредени кеша с едно извикване:

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

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

Ако вече поддържате наименувани предварително заредени набори, същият манифест може да управлява търсенето в кеширания AST:

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

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

`--trace-plan` извежда решенията на планировчика за кеширания AST в `stderr`, включително:

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

## Кеш или индекс на факти

И двата режима ускоряват търсенето в AST, но са оптимизирани за различни видове работа.

| Аспект | Индекс на факти (`ast-index`) | Кеш (`ast-cache`) |
|---|---|---|
| Какво се съхранява | Извлечени факти (имена на извиквания, имена на класове, декларации) | Сериализирани анализирани дървета |
| Цена на изграждане | По-ниска | По-висока (анализира всичко) |
| Размер на изграждане | По-малък | По-голям |
| Път за заявка | Филтриране по факти, след това анализиране и съпоставяне на кандидатите | Десериализиране на дървото, след това съпоставяне |
| Най-подходящо за | Шаблони с разпознаваема начална част (име на извикване, име на клас) | Шаблони, чиито отличителен белег е структурен, а не номинален |
| Най-неподходящо за | Шаблони, чиято начална част е метапроменлива | Студени заявки към дърво, което вече не се побира в кеша на страниците на ОС |

На практика индексът на факти осигурява най-бързата студена заявка, а кешът — най-бързата топла заявка. Използвайте този, който е подходящ за вашето натоварване, или изградете и двата и оставете инструментите ви да изберат.

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

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

Greph::buildAstCache('.', lifecycle: IndexLifecycleProfile::Static);

$matches = Greph::searchAstCached(
    'array($$$ITEMS)',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);
```

`searchAstCached` приема същия `AstSearchOptions` като нативното AST търсене и връща същата форма на `list<AstMatch>`. Единствената разлика е, че конвейерът за анализиране се заобикаля за файловете, които вече са в кеша. За потоци с множество индекси или с манифест използвайте `searchAstCachedMany(...)` и `searchAstCachedSet(...)`.

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

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

- Изпълнявате многократни структурни заявки към една и съща кодова база.
- Тесното място при предишните ви изпълнения е било PHP-Parser (в профилите се вижда като време, прекарано в лексикалния анализатор и анализатора).
- Разполагате с достатъчно дисково пространство за хранилището със сериализирани дървета.

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