Uma biblioteca de pesquisa difusa para PHP
Esta é uma versão PHP do incrível projeto Fuse.js e tem como objetivo fornecer compatibilidade total de API sempre que possível.
Confira a demonstração e os exemplos para ter uma boa ideia do que esta biblioteca é capaz.
Versão Fuse.js compatível mais recente: 7.0.0
Índice:
Este pacote está disponível via Composer. Para adicioná-lo ao seu projeto, basta executar:
composer require loilo/fuse
Observe que é necessário pelo menos PHP 7.4 para usar o Fuse.
Aqui está um exemplo de uso simples:
<?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 ' );
Isso leva aos seguintes resultados (onde cada item
do resultado se refere à própria entrada correspondente e refIndex
fornece a posição do item no $list
original):
[
[
' item ' => [
' title ' => ' The Lock Artist ' ,
' author ' => ' Steve Hamilton ' ,
],
' refIndex ' => 1 ,
],
[
' item ' => [
' title ' => ' HTML5 ' ,
' author ' => ' Remy Sharp ' ,
],
' refIndex ' => 2 ,
],
];
O Fuse tem muitas opções para refinar sua pesquisa:
isCaseSensitive
bool
false
Indica se as comparações devem diferenciar maiúsculas de minúsculas.
includeScore
bool
false
Se a pontuação deve ser incluída no conjunto de resultados. Uma pontuação 0
indica uma correspondência perfeita, enquanto uma pontuação 1
indica uma incompatibilidade completa.
includeMatches
bool
false
Se as correspondências devem ser incluídas no conjunto de resultados. Quando true
, cada registro no conjunto de resultados incluirá os índices dos caracteres correspondentes. Conseqüentemente, eles podem ser usados para fins de destaque.
minMatchCharLength
int
1
Somente as correspondências cujo comprimento exceda esse valor serão retornadas. (Por exemplo, se você quiser ignorar correspondências de caracteres únicos no resultado, defina-o como 2
).
shouldSort
bool
true
Se deve classificar a lista de resultados por pontuação.
findAllMatches
bool
false
Quando verdadeiro, a função de correspondência continuará até o final de um padrão de pesquisa, mesmo que uma correspondência perfeita já tenha sido localizada na string.
keys
array
[]
Lista de chaves que serão pesquisadas. Isso suporta caminhos aninhados, pesquisa ponderada, pesquisa em matrizes de strings e objetos.
location
int
0
Determina aproximadamente onde no texto o padrão que se espera encontrar.
threshold
float
0.6
Em que ponto o algoritmo de correspondência desiste. Um limite de 0.0
requer uma correspondência perfeita (de letras e localização), um limite de 1.0
corresponderia a qualquer coisa.
distance
int
100
Determina o quão próxima a correspondência deve estar do local difuso (especificado por location
). Uma correspondência exata de letras que distance
caracteres do local difuso seria considerada uma incompatibilidade completa. Uma distance
de 0
exige que a correspondência esteja no location
exato especificado. Uma distância de 1000
exigiria que uma correspondência perfeita estivesse dentro de 800
caracteres do location
a ser encontrado, usando um threshold
de 0.8
.
ignoreLocation
bool
false
Quando true
, a pesquisa irá ignorar location
e distance
, portanto não importará onde o padrão aparece na string.
Dica: As opções padrão pesquisam apenas os primeiros 60 caracteres. Isto deve ser suficiente se for razoavelmente esperado que a correspondência esteja dentro deste intervalo. Para modificar esse comportamento, defina a combinação apropriada de
location
,threshold
,distance
(ouignoreLocation
).Para entender melhor como essas opções funcionam juntas, leia sobre a Teoria de Pontuação do Fuse.js.
useExtendedSearch
bool
false
Quando true
, permite o uso de comandos de pesquisa do tipo Unix. Veja exemplo.
getFn
callable
A função a ser usada para recuperar o valor de um objeto no caminho fornecido. O padrão também pesquisará caminhos aninhados.
sortFn
callable
A função a ser usada para classificar todos os resultados. O padrão será classificado por pontuação de relevância crescente, índice crescente.
ignoreFieldNorm
bool
false
Quando true
, o cálculo da pontuação de relevância (usada para classificação) ignorará a norma de comprimento de campo.
Dica: A única vez que faz sentido definir
ignoreFieldNorm
comotrue
é quando não importa quantos termos existem, mas apenas que o termo de consulta existe.
fieldNormWeight
float
1
Determina o quanto a norma de comprimento de campo afeta a pontuação. Um valor 0
equivale a ignorar a norma de comprimento de campo. Um valor de 0.5
reduzirá bastante o efeito da norma de comprimento de campo, enquanto um valor de 2.0
irá aumentá-lo bastante.
Você pode acessar e manipular os valores padrão de todas as opções acima através do 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 );
Os seguintes métodos estão disponíveis em cada instância FuseFuse
:
search
Pesquisa toda a coleção de documentos e retorna uma lista de resultados da pesquisa.
public function search( mixed $ pattern , ? array $ options ): array
O $pattern
pode ser um dos seguintes:
As $options
:
limit
(tipo: int
): indica o número máximo de resultados de pesquisa retornados.setCollection
Configure/substitua todo o acervo de documentos. Se nenhum índice for fornecido, um será gerado.
public function setCollection( array $ docs , ? Fuse Core FuseIndex $ index ): void
Exemplo:
$ fruits = [ ' apple ' , ' orange ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> setCollection ([ ' banana ' , ' pear ' ]);
add
Adiciona um documento à coleção e atualiza o índice de acordo.
public function add( mixed $ doc ): void
Exemplo:
$ fruits = [ ' apple ' , ' orange ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> add ( ' banana ' );
sizeof ( $ fruits ); // => 3
remove
Remove todos os documentos da lista para os quais o predicado retorna verdadeiro e retorna uma matriz dos documentos removidos. O predicado é invocado com dois argumentos: ($doc, $index)
.
public function remove(? callable $ predicate ): array
Exemplo:
$ 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
Remove o documento no índice especificado.
public function removeAt( int $ index ): void
Exemplo:
$ fruits = [ ' apple ' , ' orange ' , ' banana ' , ' pear ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> removeAt ( 1 );
$ fuse -> getCollection (); // => ['apple', 'banana', 'pear']
getIndex
Retorna o índice Fuse gerado.
public function getIndex(): Fuse Core FuseIndex
Exemplo:
$ fruits = [ ' apple ' , ' orange ' , ' banana ' , ' pear ' ];
$ fuse = new Fuse ( $ fruits );
$ fuse -> getIndex ()-> size (); // => 4
Os seguintes métodos estão disponíveis em cada instância FuseFuse
:
Fuse::createIndex
Pré-gere o índice da lista e passe-o diretamente para a instância do Fuse. Se a lista for (consideravelmente) grande, ela acelera a instanciação.
public static function createIndex( array $ keys , array $ docs , array $ options = []): Fuse Core FuseIndex
Exemplo:
$ 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
Analisa um índice Fuse serializado em JSON.
public static function parseIndex( array $ data , array $ options = []): Fuse Core FuseIndex
Exemplo:
// (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 );
Fusível.js | Fusível PHP | |
---|---|---|
Obtenha a versão do fusível | Fuse.version | – |
Acesse a configuração global | Propriedade Fuse.config | Método Fuse::config |
Modificação da lista | Usar fuse.add() etc. modifica a lista original passada para o new Fuse . | Em PHP, arrays são um tipo de dados primitivo, o que significa que sua lista original nunca é modificada pelo Fuse. Para receber a lista atual após adicionar/remover itens, o método $fuse->getCollection() pode ser usado. |
Observe que estou buscando paridade de recursos com o Fuse.js e, portanto, não adicionarei recursos nem correções à lógica de pesquisa que não sejam refletidas no próprio Fuse.js.
Se você tiver algum problema com os resultados da pesquisa que não sejam obviamente bugs nesta porta PHP, e você conhece JavaScript, verifique se o seu caso de uso funciona corretamente na demonstração online do Fuse.js, pois essa é a implementação canônica do Fuse. Se o problema também aparecer lá, abra um problema em seu repositório.
Para iniciar o desenvolvimento no Fuse, você precisa de git, PHP (≥ 7.4) e Composer.
Como o código é formatado usando o Prettier, também é recomendado ter o Node.js/npm instalado, bem como usar um editor que suporte a formatação do Prettier.
Clone o repositório e cd
nele:
git clone https://github.com/loilo/fuse.git
cd fuse
Instale as dependências do Composer:
composer install
Instale dependências npm (opcional, mas recomendado). Isso só é necessário para formatação de código, pois as dependências do npm incluem plug-ins mais bonitos usados por este projeto.
npm ci
Existem diferentes tipos de verificações de código para este projeto. Todos eles são executados quando uma solicitação pull é enviada, mas também podem ser executados localmente:
Comando | Propósito | Descrição |
---|---|---|
vendor/bin/phpcs | verifique o estilo do código | Execute PHP_CodeSniffer para verificar se o código-fonte do Fuse segue o estilo de codificação PSR-12. |
vendor/bin/psalm | análise estática | Execute o Psalm na base de código para evitar erros relacionados ao tipo e padrões de codificação inseguros. |
vendor/bin/phpunit | verifique a lógica do programa | Execute todos os testes do PHPUnit da pasta test . |
Antes de enviar uma solicitação pull, adicione testes relevantes à pasta test
.