
# Pencarian Teks Terindeks

Pencarian teks terindeks adalah versi [pencarian teks](https://greph.inline0.dev/id/docs/modes/text) dengan cache hangat. Pemanggilan pertama membuat penyimpanan di disk untuk trigram dan posting pengenal; pemanggilan berikutnya menggunakan penyimpanan tersebut untuk melewati file yang jelas tidak mungkin memuat pola. Hasilnya, latensi jauh lebih rendah untuk kueri berulang pada repositori besar tanpa menambahkan proses daemon atau watcher.

Permukaan teks hangat kini mencakup:

- pencarian indeks tunggal
- `--index-dir` pencarian multiindeks berulang
- pencarian set berbasis manifes
- penanganan data usang yang memperhatikan siklus hidup
- diagnostik perencana melalui `--trace-plan`

Indeks ini tersedia melalui `greph-index` CLI dan metode facade `Greph::buildTextIndex()` / `Greph::searchTextIndexed()`.

## Membangun indeks

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

Secara default, indeks disimpan di `<root>/.greph-index/`.

Build yang berhasil mencetak ringkasan satu baris:

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

Keempat penghitung tersebut adalah jumlah file yang ditambahkan, diperbarui, dihapus, dan tidak berubah. Pada pembuatan baru, nilai penghitung file yang ditambahkan sama dengan jumlah file, sementara semua penghitung lainnya bernilai nol.

## Menyegarkan indeks

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

`refresh` menelusuri ulang root yang diindeks, menghitung hash setiap file, dan hanya menulis ulang entri yang metadatanya berubah. Output menggunakan empat penghitung yang sama agar Anda dapat melihat dengan tepat apa yang berubah:

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

Jalankan `refresh` setelah mengedit file yang dilacak saat Anda menggunakan `manual-refresh`. Untuk indeks `opportunistic-refresh`, Greph dapat menyegarkan indeks secara otomatis selama pencarian jika kumpulan perubahan masih cukup kecil.

## Profil siklus hidup

Greph tetap tanpa daemon. Profil siklus hidup mengatur perilaku indeks hangat saat pohon sumber berubah:

- `static`: jangan pernah memeriksa kebaruan atau mengubah apa pun secara otomatis
- `manual-refresh`: tampilkan informasi usang di `stats`, tetapi jangan pernah menyegarkan saat pencarian
- `opportunistic-refresh`: segarkan saat pencarian hanya jika kumpulan perubahan berada di bawah ambang yang dikonfigurasi
- `strict-stale-check`: tolak pencarian hangat yang usang alih-alih menyegarkannya

Gunakan `greph-index stats --dry-refresh` untuk memeriksa tindakan pencarian hangat sebelum menjalankannya:

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

## Membuat kueri pada 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" .
```

Set flag-nya sama dengan pencarian teks native. Lihat referensi [CLI](https://greph.inline0.dev/id/docs/cli#greph-index) untuk daftar lengkapnya.

Jika indeks tidak ada di lokasi yang diminta, `greph-index search` akan menghasilkan error. Perintah ini tidak secara otomatis beralih ke pemindaian nonindeks (perintah AST memiliki opsi `--fallback scan`, tetapi perintah teks tidak). Buat indeks terlebih dahulu.

## Set indeks bernama

Jika Anda berulang kali mencari tata letak hangat yang sama, gunakan manifes alih-alih mengulang flag `--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
    }
  ]
}
```

Simpan sebagai `.greph-index-set.json`, lalu:

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

## Data yang disimpan indeks

Indeks teks adalah penyimpanan trigram + posting pengenal. Untuk setiap file yang diindeks, Greph mengekstrak:

- **Kumpulan trigram**: kumpulan urutan tiga byte yang ada dalam konten file. Digunakan sebagai prafilter kasar untuk kueri literal maupun regex.
- **Posting pengenal**: kumpulan token berbentuk pengenal (`[A-Za-z_][A-Za-z0-9_]*`) yang ada dalam file. Digunakan untuk mempercepat kueri kata utuh.
- **Metadata siklus hidup**: ambang dan perilaku pemeriksaan data usang yang disimpan.
- **Metadata konten**: ukuran dan mtime untuk keputusan penyegaran dan pemeriksaan data usang.

Saat kueri diterima, Greph mengekstrak bentuk yang sama dari pola (trigram dari substring literal, token pengenal dari pola kata utuh), mengiriskan posting, lalu hanya membaca ulang file yang cocok. File yang lolos dari irisan dicari dengan mesin yang sama seperti mode teks native.

Untuk beberapa kueri ringkasan hangat, Greph dapat menjawab langsung dari posting:

- `-l` kata utuh
- `-L` kata utuh
- `-q` kata utuh

Dengan begitu, file kandidat tidak perlu dibuka kembali sama sekali jika posting sudah membuktikan jawabannya.

Gagasannya sama dengan prapengindeksan opsional milik ripgrep dan indeks trigram codesearch, tetapi dibuat khusus untuk bentuk di disk yang dapat dicari paling cepat oleh PHP hangat.

## Diagnostik perencana

`--trace-plan` mengirimkan keputusan perencana teks hangat ke `stderr` tanpa mengubah aliran hasil normal.

Jejaknya mencakup:

- profil siklus hidup
- jumlah file yang dipilih
- sumber kandidat (`full-scan`, `trigram-postings`, `word-postings`, atau `invert-scan`)
- jumlah istilah posting
- jumlah file kandidat dan yang diverifikasi
- kelayakan ringkasan langsung
- kelayakan cache kueri dan keputusan pengisiannya

## Kapan menggunakannya

Mode terindeks adalah pilihan tepat saat:

- Anda mengueri repositori yang sama berkali-kali berturut-turut (pekerjaan CI, loop agen, integrasi IDE).
- Repositori cukup besar sehingga pemindaian native menjadi hambatan.
- Pola mencakup substring literal atau token pengenal yang dapat digunakan indeks untuk melakukan prafilter.

Pemindaian native tetap menjadi pilihan tepat saat:

- Anda mengueri repositori kecil yang biaya pembuatannya lebih besar.
- Anda mencari jalur satu kali yang tidak akan diku eri lagi.
- Anda membutuhkan setiap kecocokan dalam satu pemanggilan ad hoc dan tidak ingin memelihara indeks.

Angka tolok ukur yang dipublikasikan di [README](https://github.com/inline0/greph#performance) menunjukkan mode terindeks hangat unggul atas `rg` dan `grep` pada kueri regex serta kueri hitungan, file dengan kecocokan, dan file tanpa kecocokan pada korpus WordPress. Pada kueri literal biasa, kinerjanya lebih baik daripada `grep`, tetapi masih sedikit di bawah `rg`.

## Penggunaan secara terprogram

```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` menerima `TextSearchOptions` yang sama dengan pencarian teks native dan mengembalikan bentuk `list<TextFileResult>` yang sama. Untuk alur dengan beberapa indeks atau yang didukung manifes, gunakan `searchTextIndexedMany(...)` dan `searchTextIndexedSet(...)`.
