
# Indekseret tekstsøgning

Indekseret tekstsøgning er den version af [tekstsøgning](https://greph.inline0.dev/da/docs/modes/text), der udnytter en opvarmet cache. Det første kald opbygger et lager på disken med trigrammer og identifier-posteringer; efterfølgende kald bruger lageret til at springe filer over, som tydeligvis ikke kan indeholde mønsteret. Resultatet er markant lavere latenstid ved gentagne forespørgsler i store repositories uden at indføre en daemon- eller watcher-proces.

Den opvarmede tekstfunktion omfatter nu:

- Søgning i ét indeks
- Gentagen søgning i `--index-dir` flere indeks
- Søgning i sæt baseret på manifest
- Håndtering af forældede data med kendskab til livscyklussen
- Planlægningsdiagnostik via `--trace-plan`

Indekset er tilgængeligt via `greph-index` CLI og facadefunktionerne `Greph::buildTextIndex()` / `Greph::searchTextIndexed()`.

## Oprettelse af indekset

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

Indekset gemmes som standard på `<root>/.greph-index/`.

En vellykket oprettelse udskriver en oversigt på én linje:

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

De fire tællere viser antal tilføjede, opdaterede, slettede og uændrede filer. Ved en ny opbygning svarer tælleren for tilføjede til filantallet, og alle andre tællere er nul.

## Opdatering af indekset

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

`refresh` gennemgår det indekserede rodområde igen, hasher hver fil og omskriver kun poster, hvis metadata er ændret. Resultatet bruger de samme fire tællere, så du kan se præcis, hvad der har ændret sig:

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

Kør `refresh` efter redigering af sporede filer, når du bruger `manual-refresh`. For indeks af typen `opportunistic-refresh` kan Greph opdatere indekset automatisk under søgning, hvis mængden af ændringer stadig er lille nok.

## Livscyklusprofiler

Greph kræver ingen dæmon. Livscyklusprofiler styrer, hvordan et opvarmet indeks opfører sig, når kildetræet ændres:

- `static`: kontrollér aldrig aktualitet, og foretag aldrig automatiske ændringer
- `manual-refresh`: vis oplysninger om forældede data i `stats`, men opdatér aldrig under søgning
- `opportunistic-refresh`: opdatér under søgning, men kun hvis mængden af ændringer er under de konfigurerede tærskler
- `strict-stale-check`: afvis forældede søgninger i det opvarmede indeks i stedet for at opdatere

Brug `greph-index stats --dry-refresh` til at se, hvad opvarmet søgning ville gøre, før du kører den:

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

## Forespørgsler i indekset

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

Flagsættet er det samme som ved indbygget tekstsøgning. Se [CLI-referencen](https://greph.inline0.dev/da/docs/cli#greph-index) for den fulde liste.

Hvis indekset ikke findes på den angivne placering, udløser `greph-index search` en fejl. Denne kommando falder ikke automatisk tilbage til en søgning uden indeks (AST-kommandoerne har et valgfrit `--fallback scan`, men tekstkommandoen har ikke). Byg indekset først.

## Navngivne indekssæt

Hvis du gentagne gange søger i det samme opvarmede layout, kan du bruge et manifest i stedet for at gentage `--index-dir`-flagene:

```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
    }
  ]
}
```

Gem det som `.greph-index-set.json`, og kør derefter:

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

## Hvad indekset gemmer

Tekstindekset er et lager med trigrammer og identifikatorforekomster. For hver indekseret fil udtrækker Greph:

- **Trigrammængde**: mængden af sekvenser på tre byte, der findes i filindholdet. Bruges som et groft forfilter til både bogstavelige forespørgsler og regex-forespørgsler.
- **Identifikatorforekomster**: mængden af identifikatorlignende tokens (`[A-Za-z_][A-Za-z0-9_]*`) i filen. Bruges til at accelerere søgninger efter hele ord.
- **Livscyklusmetadata**: gemte tærskler og adfærd ved kontrol af forældede data.
- **Indholdsmetadata**: størrelse og mtime til beslutninger om opdatering og inspektion af forældede data.

Når en forespørgsel kommer, udtrækker Greph de samme former fra mønsteret (trigrammer fra bogstavelige delstrenge og identifikatortokens fra mønstre for hele ord), skærer forekomsterne ned til fælles resultater og genlæser kun de matchende filer. Filer, der består denne filtrering, søges igennem med samme motor som i den indbyggede teksttilstand.

For nogle opvarmede oversigtsforespørgsler kan Greph svare direkte ud fra forekomsterne:

- `-l` for hele ord
- `-L` for hele ord
- `-q` for hele ord

Så behøver kandidatfilerne slet ikke blive åbnet igen, når forekomsterne allerede beviser svaret.

Det er samme idé som valgfri forindeksering i ripgrep og trigramindekset i codesearch, men bygget specifikt omkring de former på disken, som opvarmet PHP hurtigst kan ramme.

## Planlægningsdiagnostik

`--trace-plan` sender beslutningen fra planlæggeren for opvarmet tekst til `stderr`, mens den normale resultatstrøm forbliver uændret.

Sporet omfatter:

- Livscyklusprofil
- Antal valgte filer
- Kandidatkilde (`full-scan`, `trigram-postings`, `word-postings` eller `invert-scan`)
- Antal forekomsttermer
- Antal kandidatfiler og verificerede filer
- Om direkte oversigtsresultater er mulige
- Om forespørgselscache er mulig, og beslutning om indlæsning

## Hvornår skal den bruges

Indekseret tilstand er det rette værktøj, når:

- Du forespørger i det samme arkiv mange gange i træk (CI-job, agentløkker, IDE-integrationer).
- Arkivet er så stort, at indbygget scanning er flaskehalsen.
- Mønstrene indeholder bogstavelige delstrenge eller identifikatortokens, som indekset kan forfiltrere efter.

Indbygget scanning er stadig det rette værktøj, når:

- Du forespørger i et lille arkiv, hvor omkostningen ved opbygning dominerer.
- Du søger i en enkelt sti, som du ikke vil søge i igen.
- Du har brug for alle match i én enkeltstående forespørgsel og ikke vil vedligeholde et indeks.

De offentliggjorte benchmarktal i [README](https://github.com/inline0/greph#performance) viser, at den opvarmede indekserede tilstand klarer sig bedre end både `rg` og `grep` ved regex-forespørgsler og forespørgsler efter antal, filer med match og filer uden match i WordPress-korpusset. Ved almindelige bogstavelige forespørgsler slår den `grep`, men er stadig en smule langsommere end `rg`.

## Programmatisk brug

```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` accepterer de samme `TextSearchOptions` som indbygget tekstsøgning og returnerer samme `list<TextFileResult>`-struktur. Brug `searchTextIndexedMany(...)` og `searchTextIndexedSet(...)` til forløb med flere indeks eller manifestunderstøttelse.
