Preskoči na vsebino

Indeksirano iskanje besedila

Indeksirano iskanje besedila je različica iskanja besedila z ogretim predpomnilnikom. Prvi klic zgradi shrambo na disku s trigrami in pojavitvami identifikatorjev; nadaljnji klici uporabijo shrambo za preskakovanje datotek, ki očitno ne morejo vsebovati vzorca. Tako se zakasnitev pri ponavljajočih se poizvedbah v velikih repozitorijih močno zmanjša, ne da bi bilo treba uvesti demon ali proces za spremljanje sprememb.

Ogreti vmesnik za besedilo zdaj vključuje:

  • iskanje po enem indeksu
  • ponavljajoče se --index-dir iskanje po več indeksih
  • iskanje po naboru na podlagi manifesta
  • obravnavo zastarelosti, ki upošteva življenjski cikel
  • diagnostiko načrtovalnika prek --trace-plan

Indeks je na voljo prek greph-index CLI in fasadnih metod Greph::buildTextIndex() / Greph::searchTextIndexed().

Izdelava indeksa

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

Indeks je privzeto shranjen na mestu <root>/.greph-index/.

Uspešna izdelava izpiše enovrstični povzetek:

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

Štirje števci prikazujejo število dodanih, posodobljenih, izbrisanih in nespremenjenih datotek. Pri sveži gradnji je vrednost števca dodanih datotek enaka številu datotek, vsi drugi števci pa so nič.

Osveževanje indeksa

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

refresh znova pregleda indeksirano korensko mapo, izračuna zgoščene vrednosti vseh datotek in prepiše samo vnose, katerih metapodatki so se spremenili. Izhod uporablja iste štiri števce, zato lahko natančno vidite, kaj se je spremenilo:

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

Zaženite refresh po urejanju sledenih datotek, kadar uporabljate manual-refresh. Pri indeksih opportunistic-refresh lahko Greph samodejno osveži indeks med iskanjem, če je nabor spremenjenih datotek še dovolj majhen.

Profili življenjskega cikla

Greph ne uporablja demona. Profili življenjskega cikla določajo, kako se ogreti indeks obnaša ob spremembah izvornega drevesa:

  • static: nikoli samodejno ne preveri aktualnosti ali spreminja podatkov
  • manual-refresh: prikaže podatke o zastarelosti v stats, vendar med iskanjem nikoli ne osveži indeksa
  • opportunistic-refresh: osveži indeks med iskanjem samo, kadar je nabor spremenjenih datotek pod nastavljenimi pragovi
  • strict-stale-check: zavrne zastarela iskanja z ogretim indeksom, namesto da bi indeks osvežil

Uporabite greph-index stats --dry-refresh za pregled dejanj ogretega iskanja, preden ga zaženete:

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

Poizvedovanje po indeksu

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

Nabor zastavic je enak kot pri izvornem iskanju besedila. Celoten seznam je v referenčnem priročniku CLIreferenca.

Če indeks ne obstaja na zahtevani lokaciji, greph-index search sproži napako. Ta ukaz se ne vrne samodejno k pregledu brez indeksa (ukazi AST omogočajo neobvezni --fallback scan, besedilni ukaz pa ne). Najprej zgradite indeks.

Poimenovani nabori indeksov

Če pogosto iščete po isti ogreti postavitvi, uporabite manifest, namesto da ponavljate zastavice --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
    }
  ]
}

Shranite ga kot .greph-index-set.json, nato:

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

Kaj indeks shranjuje

Besedilni indeks je shramba trigramov in pojavitev identifikatorjev. Za vsako indeksirano datoteko Greph izlušči:

  • Nabor trigramov: nabor trimestnih zaporedij bajtov v vsebini datoteke. Uporablja se kot grobi predfilter pri dobesednih poizvedbah in poizvedbah z regularnimi izrazi.
  • Pojavitve identifikatorjev: nabor žetonov v obliki identifikatorjev ([A-Za-z_][A-Za-z0-9_]*) v datoteki. Uporablja se za pospešitev iskanja celih besed.
  • Metapodatki življenjskega cikla: shranjeni pragovi in vedenje pri preverjanju zastarelosti.
  • Metapodatki vsebine: velikost in čas zadnje spremembe za odločanje o osveževanju in pregled zastarelosti.

Ko prispe poizvedba, Greph iz vzorca izlušči enake oblike (trigrame iz dobesednih podnizov, žetone identifikatorjev iz vzorcev za iskanje celih besed), preseká pojavitve in znova prebere samo datoteke, ki se ujemajo. Datoteke, ki prestanejo presek, preišče isti mehanizem kot izvorni besedilni način.

Pri nekaterih ogretih poizvedbah za povzetke lahko Greph odgovori neposredno iz pojavitev:

  • iskanje cele besede -l
  • iskanje cele besede -L
  • iskanje cele besede -q

Tako se kandidatnih datotek sploh ni treba znova odpreti, kadar pojavitve že dokazujejo odgovor.

To je enaka zamisel kot neobvezno predindeksiranje v ripgrep in indeks trigramov v codesearch, vendar je zasnovana posebej za oblike na disku, po katerih lahko ogreti PHP išče najhitreje.

Diagnostika načrtovalnika

--trace-plan izpiše odločitev načrtovalnika ogretega besedilnega iskanja v stderr, pri tem pa običajni tok rezultatov ostane nespremenjen.

Sled vključuje:

  • profil življenjskega cikla
  • število izbranih datotek
  • vir kandidatov (full-scan, trigram-postings, word-postings ali invert-scan)
  • število izrazov v pojavitvah
  • število kandidatnih in preverjenih datotek
  • primernost za neposredni povzetek
  • primernost predpomnilnika poizvedb in odločitev o njegovi zapolnitvi

Kdaj jo uporabiti

Indeksirani način je prava izbira, kadar:

  • Večkrat zapored poizvedujete po istem repozitoriju (opravila CI, zanke agentov, integracije IDE).
  • Repozitorij je dovolj velik, da je izvorno pregledovanje ozko grlo.
  • Vzorci vsebujejo dobesedne podnize ali žetone identifikatorjev, ki jih indeks lahko uporabi za predfiltriranje.

Izvorno pregledovanje je še vedno prava izbira, kadar:

  • Poizvedujete po majhnem repozitoriju, kjer prevlada strošek gradnje.
  • Iščete po poti, ki jo boste uporabili samo enkrat.
  • Pri enkratnem iskanju potrebujete vsa ujemanja in ne želite vzdrževati indeksa.

Objavljene primerjalne vrednosti v README kažejo, da je ogreti indeksirani način hitrejši od rg in grep pri poizvedbah z regularnimi izrazi ter poizvedbah za štetje, datoteke z ujemanji in datoteke brez ujemanj v korpusu WordPress. Pri poizvedbah z navadnimi dobesednimi nizi je hitrejši od grep, vendar nekoliko počasnejši od rg.

Uporaba v kodi

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 sprejema enak TextSearchOptions kot izvorno iskanje besedila in vrne enako obliko list<TextFileResult>. Za poteke z več indeksi ali z manifestom uporabite searchTextIndexedMany(...) in searchTextIndexedSet(...).