İçeriğe geç

Dizinlenmiş Metin Araması

Dizinlenmiş metin araması, metin aramasının ısıtılmış önbellekli sürümüdür. İlk çağrı, trigramlardan ve tanımlayıcı gönderimlerinden oluşan bir disk deposu oluşturur; sonraki çağrılar, örüntüyü içermesi açıkça mümkün olmayan dosyaları atlamak için bu depoyu kullanır. Böylece arka plan hizmeti veya izleyici süreci çalıştırmadan, büyük depolardaki yinelenen sorguların gecikmesi önemli ölçüde azalır.

Isıtılmış metin özellikleri artık şunları içeriyor:

  • Tek dizinde arama
  • Tekrarlanan --index-dir çoklu dizin araması
  • Bildirim dosyası destekli küme araması
  • Yaşam döngüsünü dikkate alan eskilik yönetimi
  • --trace-plan üzerinden planlayıcı tanılamaları

Dizine greph-index CLI alt komutundan ve Greph::buildTextIndex() / Greph::searchTextIndexed() arayüz yöntemlerinden erişilir.

Dizini oluşturma

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

Dizin varsayılan olarak <root>/.greph-index/ konumunda saklanır.

Başarılı bir oluşturma işlemi tek satırlık bir özet yazdırır:

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

Dört sayaç, eklenen, güncellenen, silinen ve değişmeden kalan dosyaların sayısını gösterir. Yeni bir dizin oluşturulduğunda eklenen sayacı dosya sayısına eşit, diğerleri ise sıfırdır.

Dizini yenileme

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

refresh dizinlenen kökü yeniden tarar, her dosyanın karmasını hesaplar ve yalnızca üst verisi değişen girdileri yeniden yazar. Çıktıda, nelerin değiştiğini tam olarak görebilmeniz için aynı dört sayaç kullanılır:

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

manual-refresh kullanırken izlenen dosyaları düzenledikten sonra refresh komutunu çalıştırın. opportunistic-refresh dizinlerinde, değişen küme hâlâ yeterince küçükse Greph arama sırasında dizini otomatik olarak yenileyebilir.

Yaşam döngüsü profilleri

Greph arka plan hizmeti çalıştırmaz. Yaşam döngüsü profilleri, kaynak ağacı değiştiğinde ısıtılmış dizinin nasıl davranacağını belirler:

  • static: güncelliği hiçbir zaman denetleme veya otomatik olarak değiştirme
  • manual-refresh: eski bilgileri stats içinde göster, ancak arama sırasında hiçbir zaman yenileme
  • opportunistic-refresh: yalnızca değişen küme yapılandırılan eşiklerin altındaysa arama sırasında yenile
  • strict-stale-check: eski ısıtılmış aramaları yenilemek yerine reddet

Isıtılmış aramanın çalıştırılmadan önce ne yapacağını incelemek için greph-index stats --dry-refresh kullanın:

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

Dizinde sorgu yapma

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

Seçenek kümesi yerel metin aramasıyla aynıdır. Tüm seçenekler için CLIbaşvuru bölümüne bakın.

İstenen konumda dizin yoksa greph-index search hata verir. Bu komut, dizinlenmemiş bir taramaya otomatik olarak geçmez (AST komutlarında isteğe bağlı bir --fallback scan vardır, ancak metin komutunda yoktur). Önce dizini oluşturun.

Adlandırılmış dizin kümeleri

Aynı ısıtılmış düzende tekrar tekrar arama yapıyorsanız, --index-dir seçeneklerini yinelemek yerine bir bildirim dosyası kullanın:

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

Dosyayı .greph-index-set.json adıyla kaydedin, ardından:

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

Dizinin sakladıkları

Metin dizini, trigram + tanımlayıcı gönderimlerinden oluşan bir depodur. Greph, dizinlenen her dosya için şunları çıkarır:

  • Trigram kümesi: Dosya içeriğinde bulunan üç baytlık dizilerin kümesi. Hem düz metin hem de regex sorguları için genel bir ön filtre olarak kullanılır.
  • Tanımlayıcı gönderimleri: Dosyada bulunan tanımlayıcı biçimindeki belirteçlerin ([A-Za-z_][A-Za-z0-9_]*) kümesi. Tam sözcük sorgularını hızlandırmak için kullanılır.
  • Yaşam döngüsü üst verileri: Saklanan eşikler ve eski veri denetimi davranışı.
  • İçerik üst verileri: Yenileme kararları ve eskilik incelemesi için boyut ve mtime.

Bir sorgu geldiğinde Greph, örüntüdeki aynı yapıları çıkarır (düz metin alt dizelerinden trigramları, tam sözcük örüntülerinden tanımlayıcı belirteçlerini), gönderimlerin kesişimini alır ve yalnızca eşleşen dosyaları yeniden okur. Kesişimden geçen dosyalarda, yerel metin moduyla aynı altyapı kullanılarak arama yapılır.

Bazı ısıtılmış özet sorgularında Greph yanıtı doğrudan gönderimlerden verebilir:

  • Tam sözcük -l
  • Tam sözcük -L
  • Tam sözcük -q

Gönderimler yanıtı zaten kanıtlıyorsa bu sayede aday dosyaları yeniden açmak gerekmez.

Bu, ripgrep için isteğe bağlı ön dizinleme ve codesearch'ün trigram diziniyle aynı fikirdir; ancak özellikle ısıtılmış PHP aramalarının en hızlı kullanabildiği disk yapıları için oluşturulmuştur.

Planlayıcı tanılamaları

--trace-plan, normal sonuç akışını değiştirmeden ısıtılmış metin planlayıcısının kararını stderr konumuna yazar.

İz şunları içerir:

  • Yaşam döngüsü profili
  • Seçilen dosya sayısı
  • Aday kaynağı (full-scan, trigram-postings, word-postings veya invert-scan)
  • Gönderim terimi sayısı
  • Aday ve doğrulanan dosya sayıları
  • Doğrudan özet için uygunluk
  • Sorgu önbelleği için uygunluk ve doldurma kararı

Ne zaman kullanılır?

Dizinli mod şu durumlarda doğru araçtır:

  • Aynı depoda art arda birçok kez sorgu çalıştırıyorsanız (CI işleri, ajan döngüleri, IDE entegrasyonları).
  • Depo, yerel taramanın darboğaz oluşturacağı kadar büyükse.
  • Desenler, dizinin ön eleme yapabileceği sabit alt dizeler veya tanımlayıcı belirteçleri içeriyorsa.

Yerel tarama şu durumlarda hâlâ doğru araçtır:

  • Derleme maliyetinin baskın olduğu küçük bir depoda sorgu çalıştırıyorsanız.
  • Yeniden sorgulamayacağınız tek seferlik bir yolu arıyorsanız.
  • Tek bir özel çağrıda tüm eşleşmelere ihtiyaç duyuyor ve dizin tutmak istemiyorsanız.

README içinde yayımlanan kıyaslama sonuçları, ısıtılmış dizinli modun regex sorgularında ve WordPress derlemi üzerinde sayım, eşleşme içeren dosyalar ve eşleşme içermeyen dosyalar sorgularında hem rg hem de grep'ten daha iyi olduğunu gösteriyor. Düz sabit dizeli sorgularda grep'i geçiyor, ancak rg'nin biraz gerisinde kalıyor.

Programatik kullanım

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, yerel metin aramayla aynı TextSearchOptions değerlerini kabul eder ve aynı list<TextFileResult> yapısını döndürür. Çok dizinli veya bildirim destekli iş akışlarında searchTextIndexedMany(...) ve searchTextIndexedSet(...) kullanın.