Una biblioteca de búsqueda difusa para PHP
Este es un puerto PHP del increíble proyecto Fuse.js y tiene como objetivo proporcionar compatibilidad API total siempre que sea posible.
Consulte su demostración y ejemplos para tener una idea de lo que esta biblioteca es capaz de hacer.
Última versión compatible de Fuse.js: 7.0.0
Tabla de contenido:
Este paquete está disponible a través de Composer. Para agregarlo a su proyecto, simplemente ejecute:
composer require loilo/fuse
Tenga en cuenta que se necesita al menos PHP 7.4 para utilizar Fuse.
Aquí hay un ejemplo de uso simple:
<?php
require_once ' vendor/autoload.php ' ;
$ list = [
[
' title ' => " Old Man's War " ,
' author ' => ' John Scalzi ' ,
],
[
' title ' => ' The Lock Artist ' ,
' author ' => ' Steve Hamilton ' ,
],
[
' title ' => ' HTML5 ' ,
' author ' => ' Remy Sharp ' ,
],
[
' title ' => ' Right Ho Jeeves ' ,
' author ' => ' P.D Woodhouse ' ,
],
];
$ options = [
' keys ' => [ ' title ' , ' author ' ],
];
$ fuse = new Fuse Fuse ( $ list , $ options );
$ fuse -> search ( ' hamil ' );
Esto conduce a los siguientes resultados (donde item
de cada resultado se refiere a la entrada coincidente y refIndex
proporciona la posición del elemento en la $list
original):
[
[
' item ' => [
' title ' => ' The Lock Artist ' ,
' author ' => ' Steve Hamilton ' ,
],
' refIndex ' => 1 ,
],
[
' item ' => [
' title ' => ' HTML5 ' ,
' author ' => ' Remy Sharp ' ,
],
' refIndex ' => 2 ,
],
];
Fuse tiene muchas opciones para refinar su búsqueda:
isCaseSensitive
bool
false
Indica si las comparaciones deben distinguir entre mayúsculas y minúsculas.
includeScore
bool
false
Si la puntuación debe incluirse en el conjunto de resultados. Una puntuación de 0
indica una coincidencia perfecta, mientras que una puntuación de 1
indica una total discrepancia.
includeMatches
bool
false
Si las coincidencias deben incluirse en el conjunto de resultados. Cuando true
, cada registro del conjunto de resultados incluirá los índices de los caracteres coincidentes. En consecuencia, estos pueden utilizarse con fines de resaltado.
minMatchCharLength
int
1
Sólo se devolverán las coincidencias cuya longitud exceda este valor. (Por ejemplo, si desea ignorar las coincidencias de un solo carácter en el resultado, configúrelo en 2
).
shouldSort
bool
true
Si se debe ordenar la lista de resultados por puntuación.
findAllMatches
bool
false
Cuando es verdadero, la función de coincidencia continuará hasta el final de un patrón de búsqueda incluso si ya se ha localizado una coincidencia perfecta en la cadena.
keys
array
[]
Lista de claves que se buscarán. Esto admite rutas anidadas, búsqueda ponderada y búsqueda en matrices de cadenas y objetos.
location
int
0
Determina aproximadamente en qué parte del texto se espera encontrar el patrón.
threshold
float
0.6
¿En qué momento se da por vencido el algoritmo de coincidencia? Un umbral de 0.0
requiere una coincidencia perfecta (tanto de letras como de ubicación), un umbral de 1.0
coincidiría con cualquier cosa.
distance
int
100
Determina qué tan cerca debe estar la coincidencia de la ubicación difusa (especificada por location
). Una coincidencia de letras exacta que esté distance
de caracteres de la ubicación difusa se calificaría como una falta total de coincidencia. Una distance
de 0
requiere que la coincidencia se realice en la location
exacta especificada. Una distancia de 1000
requeriría que una coincidencia perfecta estuviera dentro de 800
caracteres de la location
que se va a encontrar utilizando un threshold
de 0.8
.
ignoreLocation
bool
false
Cuando true
, la búsqueda ignorará location
y distance
, por lo que no importará en qué parte de la cadena aparezca el patrón.
Consejo: Las opciones predeterminadas solo buscan los primeros 60 caracteres. Esto debería ser suficiente si se espera razonablemente que la coincidencia esté dentro de este rango. Para modificar este comportamiento, establezca la combinación adecuada de
location
,threshold
,distance
(oignoreLocation
).Para comprender mejor cómo funcionan juntas estas opciones, lea sobre la teoría de puntuación de Fuse.js.
useExtendedSearch
bool
false
Cuando true
, permite el uso de comandos de búsqueda similares a Unix. Ver ejemplo.
getFn
callable
La función que se utilizará para recuperar el valor de un objeto en la ruta proporcionada. El valor predeterminado también buscará rutas anidadas.
sortFn
callable
La función que se utilizará para ordenar todos los resultados. De forma predeterminada, se ordenará por puntuación de relevancia ascendente e índice ascendente.
ignoreFieldNorm
bool
false
Cuando true
, el cálculo de la puntuación de relevancia (utilizada para ordenar) ignorará la norma de longitud de campo.
Consejo: El único momento en el que tiene sentido establecer
ignoreFieldNorm
entrue
es cuando no importa cuántos términos haya, sino sólo que el término de consulta exista.
fieldNormWeight
float
1
Determina en qué medida la norma de longitud del campo afecta la puntuación. Un valor de 0
equivale a ignorar la norma de longitud de campo. Un valor de 0.5
reducirá en gran medida el efecto de la norma de longitud de campo, mientras que un valor de 2.0
lo aumentará considerablemente.
Puede acceder y manipular los valores predeterminados de todas las opciones anteriores a través del método config
:
// Get an associative array of all options listed above
Fuse :: config ();
// Merge associative array of options into default config
Fuse :: config ([ ' shouldSort ' => false ]);
// Get single default option
Fuse :: config ( ' shouldSort ' );
// Set single default option
Fuse :: config ( ' shouldSort ' , false );
Los siguientes métodos están disponibles en cada instancia FuseFuse
:
search
Busca en toda la colección de documentos y devuelve una lista de resultados de búsqueda.
public function search( mixed $ pattern , ? array $ options ): array
El $pattern
puede ser uno de:
Las $options
:
limit
(tipo: int
): indica el número máximo de resultados de búsqueda devueltos.setCollection
Establecer/reemplazar toda la colección de documentos. Si no se proporciona ningún índice, se generará uno.
public function setCollection( array $ docs , ? Fuse Core FuseIndex $ index ): void
Ejemplo:
$ fruits = [ ' apple ' , ' orange ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> setCollection ([ ' banana ' , ' pear ' ]);
add
Agrega un documento a la colección y actualiza el índice en consecuencia.
public function add( mixed $ doc ): void
Ejemplo:
$ fruits = [ ' apple ' , ' orange ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> add ( ' banana ' );
sizeof ( $ fruits ); // => 3
remove
Elimina todos los documentos de la lista para los cuales el predicado devuelve verdadero y devuelve una matriz de los documentos eliminados. El predicado se invoca con dos argumentos: ($doc, $index)
.
public function remove(? callable $ predicate ): array
Ejemplo:
$ fruits = [ ' apple ' , ' orange ' , ' banana ' , ' pear ' ];
$ fuse = new Fuse ( $ fruits );
$ results = $ fuse -> remove (fn( $ doc ) => $ doc === ' banana ' || $ doc === ' pear ' );
sizeof ( $ fuse -> getCollection ()); // => 2
$ results ; // => ['banana', 'pear']
removeAt
Elimina el documento en el índice especificado.
public function removeAt( int $ index ): void
Ejemplo:
$ fruits = [ ' apple ' , ' orange ' , ' banana ' , ' pear ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> removeAt ( 1 );
$ fuse -> getCollection (); // => ['apple', 'banana', 'pear']
getIndex
Devuelve el índice Fuse generado.
public function getIndex(): Fuse Core FuseIndex
Ejemplo:
$ fruits = [ ' apple ' , ' orange ' , ' banana ' , ' pear ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> getIndex ()-> size (); // => 4
Los siguientes métodos están disponibles en cada instancia FuseFuse
:
Fuse::createIndex
Genere previamente el índice a partir de la lista y páselo directamente a la instancia de Fuse. Si la lista es (considerablemente) grande, se acelera la creación de instancias.
public static function createIndex( array $ keys , array $ docs , array $ options = []): Fuse Core FuseIndex
Ejemplo:
$ list = [ ... ]; // See the example from the 'Usage' section
$ options = [ ' keys ' => [ ' title ' , ' author.firstName ' ] ];
// Create the Fuse index
$ myIndex = Fuse :: createIndex ( $ options [ ' keys ' ], $ list );
// Initialize Fuse with the index
$ fuse = new Fuse ( $ list , $ options , $ myIndex );
Fuse::parseIndex
Analiza un índice Fuse serializado en JSON.
public static function parseIndex( array $ data , array $ options = []): Fuse Core FuseIndex
Ejemplo:
// (1) When the data is collected
$ list = [ ... ]; // See the example from the 'Usage' section
$ options = [ ' keys ' => [ ' title ' , ' author.firstName ' ] ];
// Create the Fuse index
$ myIndex = Fuse :: createIndex ( $ options [ ' keys ' ], $ list );
// Serialize and save it
file_put_contents ( ' fuse-index.json ' , json_encode ( $ myIndex ));
// (2) When the search is needed
// Load and deserialize index to an array
$ fuseIndex = json_decode ( file_get_contents ( ' fuse-index.json ' ), true );
$ myIndex = Fuse :: parseIndex ( $ fuseIndex );
// Initialize Fuse with the index
$ fuse = new Fuse ( $ list , $ options , $ myIndex );
Fusible.js | Fusible PHP | |
---|---|---|
Obtener la versión del fusible | Fuse.version | – |
Acceder a la configuración global | Propiedad Fuse.config | Fuse::config |
Modificación de lista | El uso de fuse.add() etc. modifica la lista original pasada al new Fuse . | En PHP, las matrices son un tipo de datos primitivo, lo que significa que Fuse nunca modifica su lista original. Para recibir la lista actual después de agregar/eliminar elementos, se puede utilizar el método $fuse->getCollection() . |
Tenga en cuenta que me estoy esforzando por lograr la paridad de funciones con Fuse.js y, por lo tanto, no agregaré funciones ni correcciones a la lógica de búsqueda que no se reflejen en el propio Fuse.js.
Si tiene algún problema con los resultados de búsqueda que no son obviamente errores en este puerto PHP y conoce JavaScript, verifique si su caso de uso funciona correctamente en la demostración en línea de Fuse.js, ya que esa es la implementación canónica de Fuse. Si el problema también aparece allí, abra un problema en su repositorio.
Para comenzar el desarrollo en Fuse, necesita git, PHP (≥ 7.4) y Composer.
Dado que el código está formateado con Prettier, también se recomienda tener instalado Node.js/npm y utilizar un editor que admita el formato Prettier.
Clona el repositorio y cd
en él:
git clone https://github.com/loilo/fuse.git
cd fuse
Instalar dependencias de Composer:
composer install
Instale las dependencias de npm (opcional pero recomendado). Esto solo es necesario para formatear el código, ya que las dependencias de npm incluyen complementos de Prettier utilizados en este proyecto.
npm ci
Existen diferentes tipos de comprobaciones de código para este proyecto. Todos estos se ejecutan cuando se envía una solicitud de extracción, pero también se pueden ejecutar localmente:
Dominio | Objetivo | Descripción |
---|---|---|
vendor/bin/phpcs | comprobar el estilo del código | Ejecute PHP_CodeSniffer para verificar que el código fuente de Fuse cumpla con el estilo de codificación PSR-12. |
vendor/bin/psalm | análisis estático | Ejecute Psalm en el código base para evitar errores relacionados con tipos y patrones de codificación inseguros. |
vendor/bin/phpunit | comprobar la lógica del programa | Ejecute todas las pruebas de PHPUnit desde la carpeta test . |
Antes de enviar una solicitud de extracción, agregue pruebas relevantes a la carpeta test
.