Elasticsearch Driver para Laravel Scout com o poder das consultas do Elasticsearch.
Via compositor
composer require hilsonxhero/elasticvisionVocê precisará do arquivo de configuração para definir seus índices:
php artisan vendor:publish --tag=elasticvision-config Também não se esqueça de seguir as instruções de instalação para o Laravel Scout e, na sua configuração de escoteiros Laravel, defina o driver como elastic .
Você pode definir o mapeamento para seu índice no arquivo de configuração ElasticVision:
return [
' indexes ' => [
App Models Product ::class,
],
];php artisan scout:index productsphp artisan scout:import " AppModelsProduct " No último caso, você pode implementar a interface Explored e substituir o mapeamento com a função mappableAs() .
Essencialmente, isso significa que cabe a você se você gosta de ter tudo junto no modelo ou separadamente no arquivo de configuração.
Retorna documentos que contêm um termo exato em um campo fornecido.
Você pode usar o termo consulta para encontrar documentos com base em um valor preciso, como um preço, um ID do produto ou um nome de usuário.
use App Models Post ;
$ posts = Post :: search ( ' lorem ' )
-> filter ( new Term ( ' published ' , true ))
-> get ();Retorna documentos que contêm um ou mais termos exatos em um campo fornecido.
A consulta dos termos é a mesma que a consulta do termo, exceto que você pode procurar vários valores. Um documento corresponderá se contiver pelo menos um dos termos. Para procurar documentos que contêm mais de um termo correspondente.
use App Models Post ;
$ posts = Post :: search ( ' lorem ' )
-> should ( new Terms ( ' tags ' , [ ' featured ' ], 2 ))
-> get (); field
(Opcional, objeto) Campo que você deseja pesquisar.
boost
(Opcional, flutuação) Número do ponto flutuante usado para diminuir ou aumentar as pontuações de relevância de uma consulta. Padrões para 1.0.
Por padrão, seus resultados de pesquisa serão classificados pela pontuação de acordo com o Elasticsearch. Se você deseja intervir e influenciar a classificação, poderá fazê -lo usando a função orderBy() padrão do Laravel Scout.
use App Models Post ;
$ results = Post :: search ( ' Self-steering ' )
-> orderBy ( ' published_at ' , ' desc ' )
-> get ();Retorna documentos que contêm termos dentro de um intervalo fornecido.
use App Models User ;
$ results = User :: search ( ' fugiat ' )-> must ( new Range ( ' age ' ,[ ' gte ' => 18 , ' lte ' => 35 ]))-> get ();Retorna documentos que contêm termos correspondentes a uma expressão regular.
Uma expressão regular é uma maneira de corresponder aos padrões em dados usando caracteres de espaço reservado, chamados operadores. Para uma lista de operadores suportados pela consulta REGEXP, consulte Sintaxe de expressão regular.
use App Models User ;
$ results = User :: search ( ' fugiat ' )-> must ( new RegExp ( ' username ' , ' k.*y ' , ' ALL ' , false ))-> get (); field
(Opcional, objeto) Campo que você deseja pesquisar.
value
(Necessário, string) Expressão regular para termos que você deseja encontrar no <field> fornecido. Para uma lista de operadores suportados, consulte Sintaxe de expressão regular.
flags
(Opcional, string) permite operadores opcionais para a expressão regular. Para valores válidos e mais informações, consulte Sintaxe de expressão regular.
case_insensitive
(Opcional, booleano) permite a correspondência insensível do caso do valor de expressão regular com os valores de campo indexado quando definido como true. O padrão é falso, o que significa que a sensibilidade do caso da correspondência depende do mapeamento do campo subjacente.
boost
(Opcional, flutuação) Número do ponto flutuante usado para diminuir ou aumentar as pontuações de relevância de uma consulta. Padrões para 1.0.
Retorna documentos que contêm termos correspondentes a um padrão curinga.
Um operador curinga é um espaço reservado que corresponde a um ou mais caracteres. Por exemplo, o * operador curinga corresponde a zero ou mais caracteres. Você pode combinar operadores curinga com outros personagens para criar um padrão curinga.
use App Models User ;
$ users = User :: search ()
-> should ( new Wildcard ( ' username ' , ' ki*y ' ))
-> get ();Retorna documentos que correspondem a um texto, número, data ou valor booleano fornecido. O texto fornecido é analisado antes da correspondência.
A consulta Match é a consulta padrão para realizar uma pesquisa de texto completo, incluindo opções de correspondência difusa.
use App Models Article ;
$ articles = Article :: search ()
-> must ( new Matching ( ' title ' , ' ipsum ' ))
-> get ();Retorna documentos que contêm as palavras de um texto fornecido, na mesma ordem fornecida. O último termo do texto fornecido é tratado como um prefixo, correspondendo a todas as palavras que começam com esse termo.
use App Models User ;
$ users = User :: search ()
-> should ( new MatchPhrasePrefix ( ' message ' , ' quick brown f ' ))
-> get (); A consulta match_phrase analisa o texto e cria uma consulta phrase a partir do texto analisado. Por exemplo:
use App Models User ;
$ users = User :: search ()
-> should ( new MatchPhrase ( ' message ' , ' this is a test ' ))
-> get ();Envolva outra consulta para pesquisar campos aninhados.
A consulta nested pesquisa objetos de campo aninhados como se fossem indexados como documentos separados. Se um objeto corresponde à pesquisa, a consulta nested retorna o documento dos pais raiz.
use App Models Product ;
$ products = Product :: search ()
-> must ( new Nested ( ' category ' , new Term ( ' category.id ' , 2 )))
-> get (); use App Models Product ;
$ search = Product :: search ( " lorem " );
// $feature_ids = array([4 => [1,2], 5 => [1,2]])
foreach ( request ()-> feature_id as $ key => $ value ) {
$ query = new BoolQuery ();
$ query -> must ( new Term ( ' features.feature_id ' , $ key ));
$ query -> must ( new Terms ( ' features.feature_value_id ' , $ value ));
$ boolQuery -> add ( ' must ' , new Nested ( ' features ' , $ query ));
}
$ search -> newCompound ( $ boolQuery );
$ products = $ search -> paginate ( 15 );Uma frase de consulta corresponde aos termos até um slop configurável (que padrão é 0) em qualquer ordem. Termos transpostos têm uma inclinação de 2.
O analisador pode ser definido para controlar qual analisador executará o processo de análise no texto. Padrives da definição de mapeamento explícito do campo, ou o analisador de pesquisa padrão, por exemplo:
A maior parte da configuração que você fará com o mapeamento do seu índice. No entanto, se, por exemplo, você deseja definir configurações mais avançadas de pesquisa de pesquisa avançada, como analisadores ou tokenizadores, você precisa fazer isso usando as configurações de índice.
Esteja ciente de que sempre que você altera as configurações do índice, você precisa recriar o índice.
Para começar a usar as configurações de índice, expandiremos o modelo de postagem com uma função indexSettings para definir um analisador.
<?php
namespace App Models ;
use Illuminate Database Eloquent Factories HasFactory ;
use Illuminate Database Eloquent Model ;
use Hilsonxhero ElasticVision Application Explored ;
use Hilsonxhero ElasticVision Application IndexSettings ;
use Laravel Scout Searchable ;
class Post extends Model implements Explored , IndexSettings
{
use HasFactory ;
use Searchable ;
protected $ fillable = [ ' title ' , ' published ' ];
public function mappableAs (): array
{
return [
' id ' => ' keyword ' ,
' title ' => ' text ' ,
' published ' => ' boolean ' ,
' created_at ' => ' date ' ,
];
}
public function indexSettings (): array
{
return [
' analysis ' => [
' analyzer ' => [
' standard_lowercase ' => [
' type ' => ' custom ' ,
' tokenizer ' => ' standard ' ,
' filter ' => [ ' lowercase ' ],
],
],
],
];
}
}A análise de texto é definida como parte das configurações de índice.
O exemplo a seguir cria um analisador de sinônimos, o resultado final seria que, quando você procure por 'vue' (também) obtém os resultados para 'reação'. Para garantir que os sinônimos correspondam a todos os casos, o filtro lowercase também está executado.
<?php
namespace App Models ;
use Illuminate Database Eloquent Factories HasFactory ;
use Illuminate Database Eloquent Model ;
use Hilsonxhero ElasticVision Application Explored ;
use Hilsonxhero ElasticVision Application IndexSettings ;
use Hilsonxhero ElasticVision Domain Analysis Analysis ;
use Hilsonxhero ElasticVision Domain Analysis Analyzer StandardAnalyzer ;
use Hilsonxhero ElasticVision Domain Analysis Filter SynonymFilter ;
use Laravel Scout Searchable ;
class Post extends Model implements Explored , IndexSettings
{
use HasFactory ;
use Searchable ;
protected $ fillable = [ ' title ' , ' published ' ];
public function mappableAs (): array
{
return [
' id ' => ' keyword ' ,
' title ' => [
' type ' => ' text ' ,
' analyzer ' => ' frameworks ' ,
],
' published ' => ' boolean ' ,
' created_at ' => ' date ' ,
];
}
public function indexSettings (): array
{
$ synonymFilter = new SynonymFilter ();
$ synonymFilter -> setSynonyms ([ ' vue => react ' ]);
$ synonymAnalyzer = new StandardAnalyzer ( ' frameworks ' );
$ synonymAnalyzer -> setFilters ([ ' lowercase ' , $ synonymFilter ]);
return ( new Analysis ())
-> addAnalyzer ( $ synonymAnalyzer )
-> addFilter ( $ synonymFilter )
-> build ();
}
}As agregações fazem parte da sua consulta de pesquisa e podem resumir seus dados. Você pode ler mais sobre agregações no Elasticsearch na documentação oficial. Nesse momento, nem todos os tipos de agregação são construídos, mas criar os que faltavam devem ser factíveis (e essas adições ao pacote são muito bem -vindas).
A adição de agregações torna sua consulta de pesquisa mais avançada. Aqui está um exemplo do aplicativo de demonstração:
$ search = Cartographer :: search ();
$ search -> aggregation ( ' places ' , new TermsAggregation ( ' place ' ));
$ results = $ search -> raw ();
$ aggregations = $ results -> aggregations ();Isso retornará uma variedade de métricas sobre quantas vezes todos os lugares estão presentes no índice Elasticsearch.
É muito fácil criar filtros e analisadores de sinônimos, mas lembre -se de que eles são "caros" para executar o Elasticsearch. Antes de recorrer aos sinônimos, veja se você pode usar curingas ou consultas difusas.
A documentação do Laravel Scout afirma que "mais avançado" onde "as cláusulas não são suportadas no momento". Somente uma verificação simples para ID é possível, além da pesquisa de termos difusos padrão:
$ categories = Category :: search ( ' lorem ipsum ' )-> filter ( new MatchPhrase ( ' status ' , ' enable ' ))-> take ( 15 )-> get ();A ElasticVision expande suas possibilidades usando construtores de consultas para escrever consultas mais complexas.
class Product extends Model implements Explored
{
public function mappableAs (): array
{
return [
' id ' => ' keyword ' ,
' title_fa ' => [
' type ' => ' text ' ,
' analyzer ' => ' my_analyzer ' ,
],
' title_en ' => [
' type ' => ' text ' ,
],
' status ' => [
' type ' => ' text ' ,
],
' category ' => ' nested ' ,
' features ' => ' nested ' ,
' variants ' => ' nested ' ,
' has_stock ' => ' boolean ' ,
];
}
public function toSearchableArray (): array
{
return [
' id ' => $ this -> id ,
' title ' => $ this -> title ,
' status ' => $ this -> status ,
' category ' => $ this -> category ,
' features ' => $ this -> features ,
' variants ' => ProductVariantResource :: collection ( $ this -> variants )-> toArray ( true ),
' has_stock ' => $ this -> has_stock ,
];
}
public function indexSettings (): array
{
return [
" analysis " => [
" analyzer " => [
" my_analyzer " => [
" type " => " custom " ,
" tokenizer " => " standard " ,
" filter " => [ " lowercase " , " my_filter " ]
]
],
" filter " => [
" my_filter " => [
" type " => " ngram " ,
" min_gram " => 2 ,
]
]
],
" index " => [
" max_ngram_diff " => 13
]
];
}
/**
* Get the name of the index associated with the model.
*
* @return string
*/
public function searchableAs ()
{
return ' products ' ;
}
public function category ()
{
return $ this -> belongsTo ( Category ::class);
}
public function variants ()
{
return $ this -> hasMany ( ProductVariant ::class);
}
public function features ()
{
return $ this -> hasMany ( ProductFeature ::class);
}
/**
* check inventory of product variations
*
* @return IlluminateDatabaseEloquentCastsAttribute
*/
protected function hasStock (): Attribute
{
return Attribute :: make (
get: fn ( $ value ) => $ this -> variants ()-> sum ( ' stock ' ) > 0 ? true : false
);
}
}
Por exemplo, para obter todas as postagens que:
Você pode executar esta consulta de pesquisa:
$ boolQuery = new BoolQuery ();
$ search = Product :: search ( " ipsum " )
-> field ( ' title ' )
-> field ( ' description ' )
-> filter ( new MatchPhrase ( ' status ' , ' enable ' ))
-> must ( new Nested ( ' category ' , new MatchPhrase ( ' category.id ' , 2 )));
if ( request ()-> filled ( ' available_stock ' )) {
$ search -> filter ( new Term ( ' has_stock ' , true ));
}
// request feature_ids value
// $feature_ids = array([4 => [1,2], 5 => [1,2]])
if ( request ()-> filled ( ' feature_ids ' )) {
foreach ( request ()-> feature_ids as $ key => $ value ) {
$ query = new BoolQuery ();
$ query -> must ( new MatchPhrase ( ' features.feature_id ' , $ key ));
$ query -> must ( new Terms ( ' features.feature_value_id ' , $ value ));
$ boolQuery -> add ( ' must ' , new Nested ( ' features ' , $ query ));
}
}
if ( request ()-> filled ( ' max_price ' ) && request ()-> filled ( ' min_price ' )) {
$ boolQuery -> add ( ' must ' , new Nested ( ' variants ' , new Range (
' variants.selling_price ' ,
[ ' gte ' => request ()-> min_price ]
)));
$ boolQuery -> add ( ' must ' , new Nested ( ' variants ' , new Range (
' variants.selling_price ' ,
[ ' lte ' => request ()-> max_price ]
)));
$ boolQuery -> add ( ' must_not ' , new Nested ( ' variants ' , new Range (
' variants.selling_price ' ,
[ ' lt ' => request ()-> min_price ]
)));
$ boolQuery -> add ( ' must_not ' , new Nested ( ' variants ' , new Range (
' variants.selling_price ' ,
[ ' gt ' => request ()-> max_price ]
)));
}
$ search -> newCompound ( $ boolQuery );
$ products = $ search -> paginate ( 15 );
return $ products ;Às vezes, você pode se perguntar por que certos resultados são ou não são devolvidos.
Aqui está um exemplo do aplicativo de demonstração ElasticVision, embora não com uma consulta complexa:
class SearchController
{
public function __invoke ( SearchFormRequest $ request )
{
$ people = Cartographer :: search ( $ request -> get ( ' keywords ' ))-> get ();
return view ( ' search ' , [
' people ' => $ people ,
]);
}
} Para depurar esta consulta de pesquisa, você pode chamar o método debug estática no Elastic Engine for Laravel Scout:
use Hilsonxhero ElasticVision Infrastructure Scout ElasticEngine ;
$ debug = ElasticEngine :: debug ();A classe Debug que esse método retorna pode fornecer a última consulta executada como uma matriz ou como JSON. Você deve copiar-se de colas do JSON como uma consulta direta para o Elasticsearch.
$ lastQueryAsArray = ElasticEngine :: debug ()-> array ();
$ lastQueryAsJson = ElasticEngine :: debug ()-> json ();Use o comando de importação do Laravel Scout para criar e atualizar índices.
php artisan scout:import <model>
Por exemplo, se o seu modelo for "App Models Post", o comando seria assim:
php artisan scout:import "AppModelsPost"
Se você deseja recriar um índice, primeiro verifique se ele é excluído e depois criá -lo. Acompanhe com uma importação de escoteira para reabastecer o índice também.
Se você estiver usando índices com alias, deve usar este comando em vez de scout:import
php artisan elastic:update <index?>
Você pode especificar um índice ou optar por omiti -lo e o comando atualizará todos os seus índices. Por exemplo, se o seu modelo for "App Model Post" e o índice é "postagens":
php artisan elastic:update posts
php artisan scout:delete-index <model>
Use o comando Laravel Scount Delete-Index para excluir os índices.
Certifique -se de configurar seus índices primeiro em config/elasticvision.php e execute os comandos de escoteiros.