Búsqueda de texto indexada
La búsqueda de texto indexada es la versión con caché precargada de la búsqueda de texto. La primera llamada crea un almacén en disco de trigramas y publicaciones de identificadores; las llamadas posteriores lo usan para omitir archivos que claramente no pueden contener el patrón. Así se reduce mucho la latencia de las consultas repetidas en repositorios grandes, sin incorporar un proceso daemon ni un observador.
La búsqueda de texto precargada ahora incluye:
- búsqueda con un solo índice
- búsqueda repetida
--index-dircon varios índices - búsqueda de conjuntos basados en manifiestos
- gestión de datos obsoletos según el ciclo de vida
- diagnósticos del planificador mediante
--trace-plan
El índice está disponible mediante greph-index CLI y los métodos de fachada Greph::buildTextIndex() / Greph::searchTextIndexed().
Creación del índice
# 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
De forma predeterminada, el índice se almacena en <root>/.greph-index/.
Si la creación finaliza correctamente, se muestra un resumen de una línea:
Built index for 2547 files in .greph-index (193428 trigrams, +2547 ~0 -0 =0)
Los cuatro contadores indican los archivos añadidos, actualizados, eliminados y sin cambios. En una compilación nueva, el contador de añadidos coincide con el número de archivos y los demás son cero.
Actualización del índice
./vendor/bin/greph-index refresh .
refresh vuelve a recorrer la raíz indexada, calcula el hash de cada archivo y reescribe solo las entradas cuyos metadatos han cambiado. El resultado usa los mismos cuatro contadores para que puedas ver exactamente qué ha cambiado:
Refreshed index for 2547 files in .greph-index (193428 trigrams, +3 ~7 -1 =2536)
Ejecuta refresh después de editar archivos de seguimiento si usas manual-refresh. En los índices opportunistic-refresh, Greph puede actualizar el índice automáticamente durante la búsqueda si el conjunto de cambios sigue siendo lo bastante pequeño.
Perfiles del ciclo de vida
Greph no necesita un proceso daemon. Los perfiles del ciclo de vida controlan cómo se comporta un índice precargado cuando cambia el árbol de origen:
static: nunca comprobar la actualidad ni modificar automáticamentemanual-refresh: mostrar información obsoleta enstats, pero nunca actualizar durante la búsquedaopportunistic-refresh: actualizar durante la búsqueda solo si el conjunto de cambios está por debajo de los umbrales configuradosstrict-stale-check: rechazar búsquedas con datos obsoletos en caché en vez de actualizarlos
Usa greph-index stats --dry-refresh para inspeccionar qué haría la búsqueda precargada antes de ejecutarla:
./vendor/bin/greph-index stats . --dry-refresh
Consulta del índice
# 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" .
El conjunto de opciones es el mismo que para la búsqueda de texto nativa. Consulta la referencia de CLI para ver la lista completa.
Si el índice no existe en la ubicación solicitada, greph-index search genera un error. Este comando no recurre automáticamente a un análisis sin índice (los comandos AST tienen una opción --fallback scan, pero el comando de texto no). Primero crea el índice.
Conjuntos de índices con nombre
Si buscas repetidamente en la misma estructura precargada, usa un manifiesto en vez de repetir las opciones --index-dir:
{
"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
}
]
}
Guárdalo como .greph-index-set.json y luego:
./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" .
Datos que almacena el índice
El índice de texto es un almacén de trigramas y publicaciones de identificadores. Para cada archivo indexado, Greph extrae:
- Conjunto de trigramas: el conjunto de secuencias de tres bytes presentes en el contenido del archivo. Se usa como prefiltro general para consultas literales y de expresiones regulares.
- Publicaciones de identificadores: el conjunto de tokens con forma de identificador (
[A-Za-z_][A-Za-z0-9_]*) presentes en el archivo. Se usa para acelerar consultas de palabras completas. - Metadatos del ciclo de vida: umbrales almacenados y comportamiento de comprobación de datos obsoletos.
- Metadatos del contenido: tamaño y fecha de modificación para decidir cuándo actualizar y revisar datos obsoletos.
Cuando llega una consulta, Greph extrae las mismas formas del patrón (trigramas de subcadenas literales y tokens identificadores de patrones de palabras completas), intersecta las publicaciones y vuelve a leer solo los archivos coincidentes. Los archivos que superan la intersección se buscan con el mismo motor que el modo de texto nativo.
Para algunas consultas de resumen con la caché precargada, Greph puede responder directamente a partir de las publicaciones:
-lde palabra completa-Lde palabra completa-qde palabra completa
Así se evita volver a abrir los archivos candidatos cuando las publicaciones ya demuestran la respuesta.
Es la misma idea que el preindexado opcional de ripgrep y el índice de trigramas de codesearch, pero diseñado específicamente para las estructuras en disco que la búsqueda precargada de PHP puede consultar más rápido.
Diagnósticos del planificador
--trace-plan envía la decisión del planificador de búsqueda de texto precargada a stderr sin modificar el flujo normal de resultados.
El registro incluye:
- perfil del ciclo de vida
- número de archivos seleccionados
- fuente de candidatos (
full-scan,trigram-postings,word-postingsoinvert-scan) - número de términos de publicación
- número de archivos candidatos y verificados
- elegibilidad para el resumen directo
- elegibilidad para la caché de consultas y decisión de poblarla
Cuándo usarlo
El modo indexado es la opción adecuada cuando:
- Consultas el mismo repositorio muchas veces seguidas (trabajos de CI, bucles de agentes, integraciones con IDE).
- El repositorio es lo bastante grande como para que el análisis nativo sea el cuello de botella.
- Los patrones incluyen subcadenas literales o tokens identificadores que el índice pueda usar como prefiltro.
El análisis nativo sigue siendo la opción adecuada cuando:
- Consultas un repositorio pequeño donde el coste de compilación es predominante.
- Buscas en una ruta puntual que no volverás a consultar.
- Necesitas todas las coincidencias en una única ejecución puntual y no quieres mantener un índice.
Las cifras de referencia publicadas en README muestran que el modo indexado precargado supera a rg y grep en consultas con expresiones regulares y en consultas de recuento, de archivos con coincidencias y de archivos sin coincidencias, sobre el corpus WordPress. En consultas literales simples supera a grep, pero sigue ligeramente por detrás de rg.
Uso programático
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 acepta las mismas TextSearchOptions que la búsqueda de texto nativa y devuelve la misma estructura de list<TextFileResult>. Para flujos con varios índices o basados en manifiestos, usa searchTextIndexedMany(...) y searchTextIndexedSet(...).