Pereiti prie turinio

Indeksuota teksto paieška

Indeksuota teksto paieška – tai talpyklos įšilimu pagrįsta teksto paieškos versija. Pirmasis iškvietimas diske sukuria trigramų ir identifikatorių pasikartojimų saugyklą; vėlesni iškvietimai ją naudoja, kad praleistų failus, kuriuose akivaizdžiai negali būti šablono. Taip smarkiai sumažinama pasikartojančių užklausų delsa didelėse saugyklose, nereikalaujant demono ar stebėtojo proceso.

Įšilusi teksto paieška dabar apima:

  • paiešką viename indekse
  • pasikartojančią --index-dir paiešką keliuose indeksuose
  • manifestu pagrįstą rinkinio paiešką
  • gyvavimo ciklą atpažįstantį pasenusios informacijos tvarkymą
  • planavimo diagnostiką per --trace-plan

Indeksas pasiekiamas per greph-index CLI ir Greph::buildTextIndex() / Greph::searchTextIndexed() sąsajos metodus.

Indekso kūrimas

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

Pagal numatytuosius nustatymus indeksas saugomas adresu <root>/.greph-index/.

Sėkmingai sukūrus indeksą, išvedama vienos eilutės suvestinė:

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

Keturi skaitikliai rodo pridėtų, atnaujintų, ištrintų ir nepakeistų failų skaičių. Kuriant indeksą pirmą kartą, pridėtų failų skaitiklis sutampa su failų skaičiumi, o visi kiti skaitikliai lygūs nuliui.

Indekso atnaujinimas

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

refresh iš naujo pereina indeksuotą šakninį katalogą, apskaičiuoja kiekvieno failo maišą ir perrašo tik įrašus, kurių metaduomenys pasikeitė. Išvestyje naudojami tie patys keturi skaitikliai, kad tiksliai matytumėte, kas pasikeitė:

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

Paleiskite refresh po sekamų failų pakeitimų, kai naudojate manual-refresh. Jei indeksai yra opportunistic-refresh tipo, Greph gali automatiškai atnaujinti indeksą paieškos metu, jei pasikeitimų rinkinys nėra per didelis.

Gyvavimo ciklo profiliai

Greph veikia be demono. Gyvavimo ciklo profiliai valdo įšilusio indekso elgseną pasikeitus šaltinio medžiui:

  • static: niekada automatiškai netikrinti aktualumo ir nekeisti duomenų
  • manual-refresh: rodyti pasenusią informaciją stats, bet niekada neatnaujinti per paiešką
  • opportunistic-refresh: atnaujinti per paiešką tik tada, kai pasikeitimų rinkinys neviršija sukonfigūruotų ribų
  • strict-stale-check: atmesti pasenusias paieškas įšilusiame indekse, užuot jį atnaujinus

Naudokite greph-index stats --dry-refresh, kad prieš vykdydami paiešką pamatytumėte, ką darytų paieška įšilusiame indekse:

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

Užklausos indeksui

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

Vėliavų rinkinys yra toks pats kaip savosios teksto paieškos. Visą sąrašą rasite CLInuorodos žinyne.

Jei indeksas nurodytoje vietoje neegzistuoja, greph-index search pateikia klaidą. Ši komanda automatiškai nepereina prie neindeksuotos paieškos (AST komandos turi pasirenkamą --fallback scan, bet teksto komanda – ne). Pirmiausia sukurkite indeksą.

Pavadinti indeksų rinkiniai

Jei dažnai ieškote tame pačiame įšilusiame išdėstyme, naudokite manifestą, užuot kaskart kartoję --index-dir vėliavas:

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

Išsaugokite jį kaip .greph-index-set.json, tada:

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

Kas saugoma indekse

Teksto indeksas yra trigramų ir identifikatorių pasikartojimų saugykla. Kiekvienam indeksuotam failui Greph išgauna:

  • Trigramų rinkinys: faile esančių trijų baitų sekų rinkinys. Naudojamas kaip pirminis filtras pažodinėms ir reguliariųjų išraiškų užklausoms.
  • Identifikatorių pasikartojimai: faile esančių identifikatorių formos žetonų ([A-Za-z_][A-Za-z0-9_]*) rinkinys. Naudojamas viso žodžio užklausoms paspartinti.
  • Gyvavimo ciklo metaduomenys: saugomos ribos ir pasenusios informacijos tikrinimo elgsena.
  • Turinio metaduomenys: dydis ir mtime, naudojami atnaujinant ir tikrinant pasenusius duomenis.

Gavęs užklausą, Greph iš šablono išgauna tokias pačias struktūras (trigramas iš pažodinių pojuosčių, identifikatorių žetonus iš viso žodžio šablonų), sankirtos būdu atrenka įrašus ir iš naujo nuskaito tik atitinkančius failus. Sankirtą praėję failai tikrinami tuo pačiu varikliu kaip ir savuoju teksto režimu.

Kai kurias suvestinės užklausas įšilusiame indekse Greph gali atsakyti tiesiogiai iš pasikartojimų:

  • viso žodžio -l
  • viso žodžio -L
  • viso žodžio -q

Taip išvengiama kandidatų failų atidarymo iš naujo, kai pasikartojimų duomenys jau leidžia nustatyti atsakymą.

Tai ta pati idėja kaip pasirenkamas ripgrep išankstinis indeksavimas ir codesearch trigramų indeksas, tačiau pritaikyta diske saugomoms struktūroms, kurias įšilęs PHP gali pasiekti greičiausiai.

Planavimo diagnostika

--trace-plan siunčia įšilusios teksto paieškos planavimo sprendimą į stderr, nepakeisdama įprasto rezultatų srauto.

Sekimo įraše pateikiama:

  • gyvavimo ciklo profilis
  • pasirinktų failų skaičius
  • kandidatų šaltinis (full-scan, trigram-postings, word-postings arba invert-scan)
  • pasikartojimų sąlygų skaičius
  • kandidatų ir patikrintų failų skaičius
  • tinkamumas atsakyti tiesiogiai iš suvestinės
  • užklausų talpyklos tinkamumas ir jos užpildymo sprendimas

Kada naudoti

Indeksuotas režimas tinka, kai:

  • Tą pačią saugyklą užklausiate daug kartų iš eilės (CI užduotys, agentų ciklai, IDE integracijos).
  • Saugykla pakankamai didelė, kad siaurąja vieta taptų savoji paieška.
  • Šablonuose yra pažodinių pojuosčių arba identifikatorių žetonų, kuriuos indeksas gali iš anksto filtruoti.

Savoji paieška vis dar tinka, kai:

  • Užklausiate nedidelę saugyklą, kurioje vyrauja indekso kūrimo sąnaudos.
  • Ieškote vienkartiniame kelyje, kuriame daugiau nebeieškosite.
  • Vienu ad hoc iškvietimu reikia visų atitikmenų ir nenorite prižiūrėti indekso.

Paskelbti lyginamųjų testų skaičiai README rodo, kad įšilęs indeksuotas režimas lenkia ir rg, ir grep, kai ieškoma reguliariųjų išraiškų bei skaičiuojami atitikmenys, failai su atitikmenimis ir failai be atitikmenų WordPress korpuse. Atliekant paprastų pažodinių eilučių paiešką, jis lenkia grep, bet šiek tiek nusileidžia rg.

Naudojimas programoje

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 priima tuos pačius TextSearchOptions kaip ir savoji teksto paieška bei grąžina tokios pačios formos list<TextFileResult>. Kelių indeksų ar manifestu pagrįstoms eigoms naudokite searchTextIndexedMany(...) ir searchTextIndexedSet(...).