
# Ricerca di testo indicizzata

La ricerca di testo indicizzata è la versione con cache precaricata della [ricerca di testo](https://greph.inline0.dev/it/docs/modes/text). La prima chiamata crea un archivio su disco di trigrammi e occorrenze di identificatori; le chiamate successive lo usano per saltare i file che chiaramente non possono contenere il pattern. Il risultato è una latenza molto inferiore per le query ripetute su repository di grandi dimensioni, senza introdurre un processo daemon o watcher.

La ricerca di testo precaricata ora include:

- ricerca su un singolo indice
- ricerca ripetuta su `--index-dir`più indici
- ricerca su insiemi basati su manifest
- gestione degli elementi obsoleti consapevole del ciclo di vita
- diagnostica del pianificatore tramite `--trace-plan`

L’indice è esposto tramite `greph-index` CLI e i metodi facade `Greph::buildTextIndex()` / `Greph::searchTextIndexed()`.

## Creazione dell'indice

```bash
# 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
```

Per impostazione predefinita, l’indice viene archiviato in `<root>/.greph-index/`.

Una creazione riuscita stampa un riepilogo su una riga:

```text
Built index for 2547 files in .greph-index (193428 trigrams, +2547 ~0 -0 =0)
```

I quattro contatori indicano il numero di file aggiunti, aggiornati, eliminati e invariati. Alla prima creazione, il contatore degli aggiunti corrisponde al numero di file e tutti gli altri sono a zero.

## Aggiornamento dell'indice

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

`refresh` ripercorre la radice indicizzata, calcola l’hash di ogni file e riscrive solo le voci i cui metadati sono cambiati. L’output usa gli stessi quattro contatori, così potete vedere esattamente cosa è cambiato:

```text
Refreshed index for 2547 files in .greph-index (193428 trigrams, +3 ~7 -1 =2536)
```

Eseguite `refresh` dopo aver modificato i file tracciati quando usate `manual-refresh`. Per gli indici `opportunistic-refresh`, durante la ricerca Greph può aggiornare automaticamente l’indice, se l’insieme dei file modificati è ancora abbastanza contenuto.

## Profili del ciclo di vita

Greph non usa daemon. I profili del ciclo di vita controllano il comportamento di un indice precaricato quando cambia l’albero sorgente:

- `static`: non verificare mai l’attualità né apportare modifiche automaticamente
- `manual-refresh`: mostrare informazioni sui dati obsoleti in `stats`, senza mai aggiornare durante la ricerca
- `opportunistic-refresh`: aggiornare durante la ricerca solo se l’insieme dei file modificati è al di sotto delle soglie configurate
- `strict-stale-check`: rifiutare le ricerche precaricate obsolete invece di aggiornarle

Usate `greph-index stats --dry-refresh` per verificare cosa farebbe la ricerca precaricata prima di eseguirla:

```bash
./vendor/bin/greph-index stats . --dry-refresh
```

## Interrogazione dell'indice

```bash
# 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" .
```

L’insieme dei flag è lo stesso della ricerca di testo nativa. Consultate il [riferimentoCLI per l’elenco completo.](https://greph.inline0.dev/it/docs/cli#greph-index)

Se l’indice non esiste nel percorso richiesto, `greph-index search` genera un errore. Questo comando non esegue automaticamente una scansione senza indice (i comandi AST offrono l’opzione `--fallback scan`, ma il comando di testo no). Create prima l’indice.

## Insiemi di indici con nome

Se cercate ripetutamente nella stessa struttura precaricata, usate un manifest invece di ripetere i flag `--index-dir`:

```json
{
  "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
    }
  ]
}
```

Salvatelo come `.greph-index-set.json`, poi:

```bash
./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" .
```

## Dati salvati nell'indice

L’indice testuale è un archivio di trigrammi e occorrenze di identificatori. Per ogni file indicizzato, Greph estrae:

- **Insieme di trigrammi**: l’insieme delle sequenze di tre byte presenti nel contenuto del file. Usato come filtro preliminare approssimativo per le query letterali e regex.
- **Occorrenze di identificatori**: l’insieme dei token con forma di identificatore (`[A-Za-z_][A-Za-z0-9_]*`) presenti nel file. Usato per accelerare le query a parola intera.
- **Metadati del ciclo di vita**: soglie memorizzate e comportamento di verifica dei dati obsoleti.
- **Metadati del contenuto**: dimensioni e mtime per decidere gli aggiornamenti e rilevare dati obsoleti.

Quando arriva una query, Greph estrae dal pattern le stesse forme (trigrammi dalle sottostringhe letterali, token identificativi dai pattern a parola intera), interseca le occorrenze e rilegge solo i file corrispondenti. I file che superano l’intersezione vengono cercati con lo stesso motore della modalità di testo nativa.

Per alcune query di riepilogo precaricate, Greph può rispondere direttamente in base alle occorrenze:

- `-l`a parola intera
- `-L`a parola intera
- `-q`a parola intera

Così si evita del tutto di riaprire i file candidati quando le occorrenze forniscono già la risposta.

È la stessa idea del preindicizzamento opzionale di ripgrep e dell’indice di trigrammi di codesearch, ma realizzata appositamente in base alle strutture su disco che la PHP precaricata può cercare più rapidamente.

## Diagnostica del pianificatore

`--trace-plan` invia la decisione del pianificatore della ricerca testuale precaricata a `stderr`, lasciando invariato il normale flusso dei risultati.

La traccia include:

- profilo del ciclo di vita
- numero di file selezionati
- origine dei candidati (`full-scan`, `trigram-postings`, `word-postings` o `invert-scan`)
- numero di termini nelle occorrenze
- numero di file candidati e verificati
- idoneità al riepilogo diretto
- idoneità della cache delle query e decisione sul suo popolamento

## Quando usarlo

La modalità indicizzata è lo strumento giusto quando:

- Eseguite molte query di seguito sullo stesso repository (job CI, cicli di agenti, integrazioni con IDE).
- Il repository è abbastanza grande da rendere la scansione nativa un collo di bottiglia.
- I pattern includono sottostringhe letterali o token identificativi che l’indice può usare come filtro preliminare.

La scansione nativa è ancora lo strumento giusto quando:

- Cercate in un repository piccolo, dove il costo di creazione dell’indice prevale.
- Eseguite una ricerca una tantum in un percorso che non interrogherete di nuovo.
- Vi servono tutte le corrispondenze in una singola esecuzione ad hoc e non volete gestire un indice.

I benchmark pubblicati nel [README mostrano che la modalità indicizzata precaricata supera sia `rg` che `grep` nelle query regex e nelle query per conteggio, file con corrispondenze e file senza corrispondenze sul corpus WordPress. Nelle query con soli valori letterali supera `grep`, ma resta leggermente indietro rispetto a `rg`.](https://github.com/inline0/greph#performance)

## Uso programmatico

```php
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` accetta gli stessi `TextSearchOptions` della ricerca testuale nativa e restituisce lo stesso formato `list<TextFileResult>`. Per flussi di lavoro con più indici o basati su manifest, usate `searchTextIndexedMany(...)` e `searchTextIndexedSet(...)`.
