Treci la conținut

Căutare text indexată

Căutarea textului indexat este versiunea cu cache încălzit a căutării în text. Primul apel creează pe disc o stocare de trigramă și apariții de identificatori; apelurile ulterioare folosesc această stocare pentru a omite fișierele care în mod evident nu pot conține tiparul. Rezultatul este o latență mult mai mică pentru interogările repetate în depozite mari, fără a introduce un proces demon sau de monitorizare.

Suprafața de text încălzită include acum:

  • căutare într-un singur index
  • căutare repetată --index-dir în mai mulți indici
  • căutare în seturi bazate pe manifest
  • gestionarea datelor învechite în funcție de ciclul de viață
  • diagnostice ale planificatorului prin --trace-plan

Indexul este expus prin greph-index CLI și prin metodele facade Greph::buildTextIndex() / Greph::searchTextIndexed().

Construirea indexului

Shell
# 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

În mod implicit, indexul este stocat la <root>/.greph-index/.

O construire reușită afișează un rezumat pe o singură linie:

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

Cei patru contori indică numărul de fișiere adăugate, actualizate, șterse și nemodificate. La o construire nouă, contorul fișierelor adăugate este egal cu numărul de fișiere, iar toate celelalte valori sunt zero.

Reîmprospătarea indexului

Shell
./vendor/bin/greph-index refresh .

refresh parcurge din nou rădăcina indexată, calculează hash-ul fiecărui fișier și rescrie doar intrările ale căror metadate s-au schimbat. Rezultatul folosește aceiași patru contori, astfel încât să vedeți exact ce s-a modificat:

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

Rulați refresh după editarea fișierelor urmărite când folosiți manual-refresh. Pentru indicii opportunistic-refresh, Greph poate reîmprospăta automat indexul în timpul căutării dacă setul de fișiere modificate este suficient de mic.

Profiluri ale ciclului de viață

Greph nu folosește un proces demon. Profilurile ciclului de viață controlează comportamentul unui index încălzit când se modifică arborele sursă:

  • static: nu verifică niciodată actualitatea și nu modifică automat datele
  • manual-refresh: semnalează informațiile învechite în stats, dar nu reîmprospătează niciodată în timpul căutării
  • opportunistic-refresh: reîmprospătează în timpul căutării numai când setul de fișiere modificate este sub pragurile configurate
  • strict-stale-check: respinge căutările cu date încălzite învechite, în loc să le reîmprospăteze

Folosiți greph-index stats --dry-refresh pentru a inspecta ce ar face căutarea încălzită înainte de a o rula:

Shell
./vendor/bin/greph-index stats . --dry-refresh

Interogarea indexului

Shell
# 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" .

Setul de fanioane este același ca pentru căutarea nativă în text. Consultați CLIreferința pentru lista completă.

Dacă indexul nu există în locația solicitată, greph-index search generează o eroare. Această comandă nu revine automat la o scanare fără index (comenzile AST au opțiunea --fallback scan, dar comanda text nu o are). Construiți mai întâi indexul.

Seturi de indici cu nume

Dacă căutați în mod repetat în aceeași structură încălzită, folosiți un manifest în loc să repetați opțiunile --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
    }
  ]
}

Salvați-l ca .greph-index-set.json, apoi:

Shell
./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" .

Ce stochează indexul

Indexul de text este o stocare de trigramă și apariții de identificatori. Pentru fiecare fișier indexat, Greph extrage:

  • Set de trigramă: setul secvențelor de trei octeți prezente în conținutul fișierului. Folosit ca prefiltru grosier atât pentru interogări literale, cât și pentru interogări regex.
  • Apariții de identificatori: setul de tokenuri cu formă de identificator ([A-Za-z_][A-Za-z0-9_]*) prezente în fișier. Folosit pentru a accelera interogările după cuvinte întregi.
  • Metadate ale ciclului de viață: praguri stocate și comportamentul verificării datelor învechite.
  • Metadate ale conținutului: dimensiunea și mtime-ul, folosite pentru deciziile de reîmprospătare și inspectarea datelor învechite.

Când primește o interogare, Greph extrage aceleași tipuri de informații din tipar (trigrame din subșirurile literale, tokenuri de identificator din tiparele pentru cuvinte întregi), intersectează listele de apariții și recitește doar fișierele potrivite. Fișierele care trec de intersecție sunt căutate cu același motor ca în modul text nativ.

Pentru unele interogări rezumative cu index încălzit, Greph poate răspunde direct din listele de apariții:

  • -l pentru cuvânt întreg
  • -L pentru cuvânt întreg
  • -q pentru cuvânt întreg

Astfel, fișierele candidate nu trebuie redeschise atunci când listele de apariții demonstrează deja răspunsul.

Este aceeași idee ca preindexarea opțională din ripgrep și indexul de trigramă din codesearch, dar construită special în jurul structurilor de pe disc pe care căutarea text încălzită PHP le poate accesa cel mai rapid.

Diagnostice ale planificatorului

--trace-plan trimite decizia planificatorului pentru textul încălzit către stderr, lăsând neschimbat fluxul normal al rezultatelor.

Urmărirea include:

  • profilul ciclului de viață
  • numărul de fișiere selectate
  • sursa candidaților (full-scan, trigram-postings, word-postings sau invert-scan)
  • numărul de termeni din listele de apariții
  • numărul de fișiere candidate și verificate
  • eligibilitatea pentru rezumat direct
  • eligibilitatea cache-ului de interogări și decizia de populare

Când să îl folosiți

Modul indexat este potrivit când:

  • Interogați același depozit de multe ori la rând (în joburi CI, bucle de agenți și integrări IDE).
  • Depozitul este suficient de mare încât scanarea nativă să devină un blocaj.
  • Tiparele includ subșiruri literale sau tokenuri de identificator pe care indexul le poate prefiltra.

Scanarea nativă este potrivită în continuare când:

  • Interogați un depozit mic, unde costul construirii indexului este dominant.
  • Căutați într-o cale pe care nu o veți mai interoga.
  • Aveți nevoie de toate potrivirile într-o singură invocare ad-hoc și nu doriți să întrețineți un index.

Cifrele benchmark-ului publicat în README arată că modul indexat încălzit depășește atât rg, cât și grep la interogări regex și la interogările de numărare, de fișiere cu potriviri și de fișiere fără potriviri, pe corpusul WordPress. La interogările cu literali simpli, este mai rapid decât grep, dar rămâne puțin în urma lui rg.

Utilizare programatică

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 acceptă aceleași TextSearchOptions ca și căutarea text nativă și returnează aceeași structură list<TextFileResult>. Pentru fluxuri cu mai mulți indici sau bazate pe manifest, folosiți searchTextIndexedMany(...) și searchTextIndexedSet(...).