Elasticsearch Driver для Laravel Scout с силой запросов Elasticsearch.
Через композитор
composer require hilsonxhero/elasticvisionВам понадобится файл конфигурации для определения ваших индексов:
php artisan vendor:publish --tag=elasticvision-config Также не забудьте следовать инструкциям по установке для Laravel Scout, а в конфигурации Laravel Scout установите драйвер на elastic .
Вы можете либо определить отображение для вашего индекса в файле конфигурации Elasticvision:
return [
' indexes ' => [
App Models Product ::class,
],
];php artisan scout:index productsphp artisan scout:import " AppModelsProduct " В последнем случае вы можете реализовать Explored интерфейс и перезаписать отображение функцией mappableAs() .
По сути, это означает, что это зависит от вас, нравится ли вам все это вместе в модели или отдельно в файле конфигурации.
Возвращает документы, которые содержат точный термин в предоставленном поле.
Вы можете использовать термин «запрос», чтобы найти документы на основе точной стоимости, таких как цена, идентификатор продукта или имя пользователя.
use App Models Post ;
$ posts = Post :: search ( ' lorem ' )
-> filter ( new Term ( ' published ' , true ))
-> get ();Возвращает документы, которые содержат один или несколько точных терминов в предоставленном поле.
Условия запроса такие же, как и запрос термина, за исключением того, что вы можете искать несколько значений. Документ будет соответствовать, если он содержит хотя бы один из терминов. Для поиска документов, которые содержат более одного соответствующего термина.
use App Models Post ;
$ posts = Post :: search ( ' lorem ' )
-> should ( new Terms ( ' tags ' , [ ' featured ' ], 2 ))
-> get (); field
(Необязательно, объект) Поле, которое вы хотите найти.
boost
(Необязательно, плавающая) Номер плавающей запятой, используемое для уменьшения или увеличения показателей релевантности запроса. По умолчанию до 1,0.
По умолчанию ваши результаты поиска будут отсортированы по их счету в соответствии с Elasticsearch. Если вы хотите вмешаться и повлиять на сортировку, вы можете сделать это, используя функцию orderBy() по умолчанию от Laravel Scout.
use App Models Post ;
$ results = Post :: search ( ' Self-steering ' )
-> orderBy ( ' published_at ' , ' desc ' )
-> get ();Возвращает документы, которые содержат термины в рамках предоставленного диапазона.
use App Models User ;
$ results = User :: search ( ' fugiat ' )-> must ( new Range ( ' age ' ,[ ' gte ' => 18 , ' lte ' => 35 ]))-> get ();Возвращает документы, которые содержат термины, соответствующие регулярному выражению.
Регулярное выражение - это способ соответствовать шаблонам в данных с использованием символов -заполнителей, называемых операторами. Список операторов, поддерживаемых запросом Regexp, см. Синтаксис регулярного выражения.
use App Models User ;
$ results = User :: search ( ' fugiat ' )-> must ( new RegExp ( ' username ' , ' k.*y ' , ' ALL ' , false ))-> get (); field
(Необязательно, объект) Поле, которое вы хотите найти.
value
(Требуется, строка) Регулярное выражение для условий, которые вы хотите найти в предоставленном <field> . Список поддерживаемых операторов см. Синтаксис регулярного выражения.
flags
(Необязательно, строка) позволяет дополнительным операторам для регулярного выражения. Допустимые значения и дополнительную информацию см. Синтаксис регулярного выражения.
case_insensitive
(Необязательно, логическое) позволяет нечувствительно к случаю сопоставления значения регулярного выражения со значениями индексированного поля при установлении true. По умолчанию является ложным, что означает, что чувствительность к случаю сопоставления зависит от картирования базового поля.
boost
(Необязательно, плавающая) Номер плавающей запятой, используемое для уменьшения или увеличения показателей релевантности запроса. По умолчанию до 1,0.
Возвращает документы, которые содержат термины, соответствующие схеме подстановочного знака.
Оператор подстановочного знака - это заполнитель, который соответствует одному или нескольким персонажам. Например, оператор * подстановочного знака соответствует нулю или более символам. Вы можете объединить операторы подстановочных знаков с другими персонажами, чтобы создать схему подстановочного знака.
use App Models User ;
$ users = User :: search ()
-> should ( new Wildcard ( ' username ' , ' ki*y ' ))
-> get ();Возвращает документы, которые соответствуют предоставленному тексту, номеру, дате или логическому значению. Предоставленный текст анализируется до сопоставления.
Запрос соответствия-это стандартный запрос для выполнения полнотекстового поиска, включая параметры нечеткого соответствия.
use App Models Article ;
$ articles = Article :: search ()
-> must ( new Matching ( ' title ' , ' ipsum ' ))
-> get ();Возвращает документы, которые содержат слова предоставленного текста, в том же порядке, что и предусмотрено. Последний термин предоставленного текста рассматривается как префикс, соответствующий любым словам, которые начинаются с этого термина.
use App Models User ;
$ users = User :: search ()
-> should ( new MatchPhrasePrefix ( ' message ' , ' quick brown f ' ))
-> get (); Запрос match_phrase анализирует текст и создает phrase запрос из проанализированного текста. Например:
use App Models User ;
$ users = User :: search ()
-> should ( new MatchPhrase ( ' message ' , ' this is a test ' ))
-> get ();Завершает еще один запрос на поиск вложенных полей.
nested запросы ищут вложенные полевые объекты, как если бы они были проиндексированы как отдельные документы. Если объект соответствует поиску, nested запрос возвращает корневой родительский документ.
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 );Фразовый запрос соответствует терминам с настраиваемой шпилькой (который по умолчанию 0) в любом порядке. Транспонированные термины имеют плитку 2.
Анализатор может быть установлен для контроля, какой анализатор выполнит процесс анализа в тексте. По умолчанию поля в поле явного определения отображения или анализатора поиска по умолчанию, например:
Большая часть конфигурации, которую вы будете делать с помощью картирования вашего индекса. Однако, если, например, вы хотите определить более продвинутые настройки Elasticsearch, такие как анализаторы или токенизаторы, вам необходимо сделать это, используя настройки индекса.
Имейте в виду, что в любое время, когда вы меняете настройки индекса, вам необходимо воссоздать индекс.
Чтобы начать использовать настройки индекса, мы расширим модель POST с помощью функции indexSettings для установки анализатора.
<?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 ' ],
],
],
],
];
}
}Анализ текста установлен как часть настройки индекса.
Следующий пример создает анализатор синонимов, конечный результат будет заключаться в том, что при поиске «Vue» вы (также) получаете результаты для «React». Чтобы убедиться, что синонимы совпадают со всеми случаями, фильтр lowercase также работает.
<?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 ();
}
}Агрегации являются частью вашего поискового запроса и могут суммировать ваши данные. Вы можете прочитать больше о агрегациях в Elasticsearch в официальной документации. В этот момент не все типы агрегации встроены, но создание пропавших должно быть выполнимым (и эти дополнения к пакету очень приветствуются).
Добавление агрегаций делает ваш поисковый запрос более продвинутым. Вот пример из демонстрационного приложения:
$ search = Cartographer :: search ();
$ search -> aggregation ( ' places ' , new TermsAggregation ( ' place ' ));
$ results = $ search -> raw ();
$ aggregations = $ results -> aggregations ();Это вернет массив метрик о том, сколько раз каждое место присутствует в индексе Elasticsearch.
Очень легко создать синонимы фильтров и анализаторов, но имейте в виду, что они «дорого» для работы для Elasticsearch. Прежде чем обратиться к синонимам, посмотрите, можете ли вы использовать подстановочные знаки или нечеткие запросы.
В документации «Скаута Ларавела» говорится, что «более продвинутые», где «положения в настоящее время не поддерживаются». Только простая проверка для идентификатора возможна, помимо стандартного поиска нечеткого термина:
$ categories = Category :: search ( ' lorem ipsum ' )-> filter ( new MatchPhrase ( ' status ' , ' enable ' ))-> take ( 15 )-> get ();Elasticvision расширяет ваши возможности, используя строители запросов для написания более сложных запросов.
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
);
}
}
Например, чтобы получить все сообщения, которые:
Вы можете выполнить этот поисковый запрос:
$ 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 ;Иногда вы можете задаться вопросом, почему определенные результаты не возвращаются или не возвращаются.
Вот пример из демонстрационного приложения Elasticvision, хотя и не со сложным запросом:
class SearchController
{
public function __invoke ( SearchFormRequest $ request )
{
$ people = Cartographer :: search ( $ request -> get ( ' keywords ' ))-> get ();
return view ( ' search ' , [
' people ' => $ people ,
]);
}
} Чтобы отлаживать этот поисковый запрос, вы можете позвонить в метод статической debug на Elastic Engine для Laravel Scout:
use Hilsonxhero ElasticVision Infrastructure Scout ElasticEngine ;
$ debug = ElasticEngine :: debug ();Класс отладки, который возвращает этот метод, может дать вам последний выполненный запрос в качестве массива или как JSON. Вы должны быть в состоянии скопировать JSON в качестве прямого запроса Elasticsearch.
$ lastQueryAsArray = ElasticEngine :: debug ()-> array ();
$ lastQueryAsJson = ElasticEngine :: debug ()-> json ();Используйте команду импорта Laravel Scout для создания и обновления индексов.
php artisan scout:import <model>
Например, если ваша модель является «App Models post», то команда была бы подобной:
php artisan scout:import "AppModelsPost"
Если вы хотите воссоздать индекс, сначала убедитесь, что он удален, а затем создайте его. Продолжайте импорт разведчика, чтобы пополнить индекс.
Если вы используете псевдоним, вы должны использовать эту команду вместо scout:import
php artisan elastic:update <index?>
Вы можете указать индекс или выбрать его, и команда обновит все ваши индексы. Например, если ваша модель - «App Model post», а индекс - «Посты»:
php artisan elastic:update posts
php artisan scout:delete-index <model>
Используйте команду Laravel Scount Delete-Index, чтобы удалить индексы.
Убедитесь, что вы сначала настроили свои индексы в config/elasticvision.php и запустите команды скаутов.