
# Teksta meklēšana ar indeksu

Teksta meklēšana ar indeksu ir [teksta meklēšanas](https://greph.inline0.dev/lv/docs/modes/text) versija ar iesildītu kešatmiņu. Pirmajā izsaukumā diskā tiek izveidota trigrammu un identifikatoru ierakstu krātuve; turpmākajos izsaukumos tā tiek izmantota, lai izlaistu failus, kuros acīmredzami nevar būt meklētais raksts. Tādējādi atkārtotiem vaicājumiem lielās repozitorijās ir daudz mazāka aizkave, turklāt nav vajadzīgs dēmons vai failu vērotāja process.

Iesildītās teksta meklēšanas iespējas tagad ietver:

- meklēšanu vienā indeksā
- atkārtotu `--index-dir` meklēšanu vairākos indeksos
- manifestā balstītu kopu meklēšanu
- novecojušu datu apstrādi, ņemot vērā dzīves ciklu
- plānotāja diagnostiku, izmantojot `--trace-plan`

Indekss pieejams, izmantojot `greph-index` CLI un fasādes metodes `Greph::buildTextIndex()` / `Greph::searchTextIndexed()`.

## Indeksa izveide

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

Pēc noklusējuma indekss tiek glabāts šeit: `<root>/.greph-index/`.

Pēc veiksmīgas izveides tiek parādīts kopsavilkums vienā rindā:

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

Četri skaitītāji rāda pievienoto, atjaunināto, dzēsto un nemainīto failu skaitu. Veidojot indeksu no jauna, pievienoto failu skaits ir vienāds ar failu kopskaitu, bet pārējie skaitītāji ir nulle.

## Indeksa atsvaidzināšana

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

`refresh` atkārtoti pārstaigā indeksēto saknes direktoriju, aprēķina katra faila jaucējvērtību un pārraksta tikai ierakstus, kuru metadati ir mainījušies. Rezultātā tiek izmantoti tie paši četri skaitītāji, lai precīzi redzētu, kas ir mainījies:

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

Pēc izsekoto failu rediģēšanas palaidiet `refresh`, ja izmantojat `manual-refresh`. Indeksiem `opportunistic-refresh` komanda Greph var automātiski atsvaidzināt indeksu meklēšanas laikā, ja izmaiņu apjoms joprojām ir pietiekami mazs.

## Dzīves cikla profili

Greph darbojas bez dēmona. Dzīves cikla profili nosaka, kā iesildīts indekss reaģē uz izmaiņām avota kokā:

- `static`: nekad automātiski nepārbauda, vai dati ir aktuāli, un neveic izmaiņas
- `manual-refresh`: parāda informāciju par novecojušiem datiem laukā `stats`, bet meklēšanas laikā nekad neatsvaidzina
- `opportunistic-refresh`: meklēšanas laikā atsvaidzina tikai tad, ja izmainīto failu skaits nepārsniedz konfigurētos sliekšņus
- `strict-stale-check`: noraida novecojušus meklēšanas pieprasījumus ar iesildītu kešatmiņu, nevis atsvaidzina datus

Izmantojiet `greph-index stats --dry-refresh`, lai pirms iesildītās meklēšanas izpildes pārbaudītu, ko tā darītu:

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

## Vaicājumi indeksā

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

Karodziņu kopa ir tāda pati kā vietējai teksta meklēšanai. Pilnu sarakstu skatiet atsaucē [CLI](https://greph.inline0.dev/lv/docs/cli#greph-index).

Ja indekss neeksistē norādītajā atrašanās vietā, `greph-index search` parāda kļūdu. Šī komanda automātiski nepāriet uz meklēšanu bez indeksa (AST komandām ir izvēles karodziņš `--fallback scan`, bet teksta komandai tāda nav). Vispirms izveidojiet indeksu.

## Nosauktu indeksu kopas

Ja atkārtoti meklējat vienā un tajā pašā izkārtojumā ar iesildītu kešatmiņu, atkārtoti ievadītu karodziņu `--index-dir` vietā izmantojiet manifestu:

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

Saglabājiet to kā `.greph-index-set.json` un pēc tam:

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

## Ko glabā indekss

Teksta indekss ir trigrammu un identifikatoru ierakstu krātuve. Katram indeksētajam failam Greph izgūst:

- **Trigrammu kopa**: faila saturā esošo trīs baitu secību kopa. Izmanto kā aptuvenu sākotnējo filtru gan burtiskajiem, gan regex vaicājumiem.
- **Identifikatoru ieraksti**: failā esošo identifikatoriem līdzīgu elementu kopa (`[A-Za-z_][A-Za-z0-9_]*`). Izmanto, lai paātrinātu pilna vārda vaicājumus.
- **Dzīves cikla metadati**: saglabātie sliekšņi un novecojušu datu pārbaudes darbība.
- **Satura metadati**: lielums un mtime, ko izmanto atsvaidzināšanas lēmumiem un novecojušu datu pārbaudei.

Saņemot vaicājumu, Greph no raksta izvelk tās pašas formas (trigrammas no burtiskajiem apakšvirkņu fragmentiem un identifikatoru elementus no pilna vārda rakstiem), krustojas ar ierakstiem un atkārtoti nolasa tikai atbilstošos failus. Failos, kas paliek pēc krustošanas, meklē ar to pašu dzinēju, ko izmanto vietējā teksta režīmā.

Dažus kopsavilkuma vaicājumus iesildītā režīmā Greph var atbildēt tieši no ierakstiem:

- pilns vārds `-l`
- pilns vārds `-L`
- pilns vārds `-q`

Tādējādi kandidātfaili vispār nav jāatver no jauna, ja ieraksti jau ļauj noteikt atbildi.

Šī ir tā pati ideja, kas izmantota ripgrep izvēles iepriekšējā indeksēšanā un codesearch trigrammu indeksā, taču tā ir veidota īpaši atbilstoši diska datu struktūrai, ko iesildīta PHP var izmantot visātrāk.

## Plānotāja diagnostika

`--trace-plan` nosūta iesildītā teksta plānotāja lēmumu uz `stderr`, nemainot parasto rezultātu plūsmu.

Izsekošanas informācijā ir:

- dzīves cikla profils
- atlasīto failu skaits
- kandidātu avots (`full-scan`, `trigram-postings`, `word-postings` vai `invert-scan`)
- ierakstu terminu skaits
- kandidātfailu un pārbaudīto failu skaits
- piemērotība tiešam kopsavilkumam
- piemērotība vaicājumu kešatmiņai un tās aizpildīšanas lēmums

## Kad to izmantot

Indeksētais režīms ir piemērots, ja:

- Daudzas reizes pēc kārtas vaicājat vienu un to pašu repozitoriju (CI darbos, aģentu ciklos, IDE integrācijās).
- Repozitorija ir pietiekami liela, lai vietējā skenēšana kļūtu par šauro vietu.
- Rakstos ir burtiski apakšvirkņu fragmenti vai identifikatoru elementi, pēc kuriem indekss var veikt sākotnējo filtrēšanu.

Vietējā skenēšana joprojām ir piemērota, ja:

- Meklējat nelielā repozitorijā, kur dominē indeksa izveides izmaksas.
- Meklējat vienreiz vienā ceļā un neplānojat to darīt atkārtoti.
- Vienā ad hoc izsaukumā nepieciešama katra atbilstība un nevēlaties uzturēt indeksu.

Publicētajos etalonmērījumu skaitļos sadaļā [README](https://github.com/inline0/greph#performance) redzams, ka iesildītais indeksētais režīms regulāro izteiksmju vaicājumos, kā arī vaicājumos par skaitu, failiem ar atbilstībām un failiem bez atbilstībām apsteidz gan `rg`, gan `grep`, izmantojot korpusu WordPress. Vienkāršos burtiskos vaicājumos tas pārspēj `grep`, bet nedaudz atpaliek no `rg`.

## Izmantošana programmā

```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` pieņem tādus pašus `TextSearchOptions` kā vietējā teksta meklēšana un atgriež tādas pašas formas `list<TextFileResult>`. Vairāku indeksu vai manifestā balstītām darbplūsmām izmantojiet `searchTextIndexedMany(...)` un `searchTextIndexedSet(...)`.
