Laravel 8 Búsqueda Full Text: Scout

Full Text con TNT

Nicola Milella
5 min readNov 30, 2021

Intro

Hola amig@s,

todos sabemos cuál es la característica más necesaria en nuestros proyectos: buscar contenido en nuestra aplicación.

Eso es exactamente lo que vamos a hacer aquí usando Laravel Scout & Tnt Search.

Laravel Scout

Laravel Scout proporciona una solución simple basada en drivers para agregar búsqueda full text a sus modelos Eloquent. Utilizando observers de modelos, Scout mantendrá automáticamente sus índices de búsqueda sincronizados con sus registros de Eloquent.

TNT Search

TNTSearch es un motor de búsqueda full text con muchas funcionalidades escrito íntegramente en PHP. Su configuración simple le permite agregar una experiencia de búsqueda asombrosa a su sitio en solo minutos.

Empecemos

Bueno, ahora que sabemos un poco de lo que estamos hablando, ¡vamos a poner todo esto en marcha en un proyecto de Blog con Laravel, rápido y simple!

Creemos el proyecto:

laravel new blog-tntsearch

Estructurando los datos

Cree una base de datos y conéctela a nuestro proyecto configurando el archivo .env. Ahora necesitamos un modelo, una migración, un controlador y una factory para estructurar nuestro proyecto y jugar un poco.

Creemos todo esto con el comando Artisan:

php artisan make:model Article -mcf

Completaremos nuestra migración con algunos campos simples:

public function up(){ Schema::create('articles', function (Blueprint $table) {  $table->id();

$table->string('title');

$table->text('body');
$table->timestamps(); });}

Ahora migremos la tabla:

php artisan migrate

Y llenemos nuestra tabla con algunos datos ficticios gracias a la factory que hemos creado. Para configurar la factory, simplemente escribimos esto en nuestra clase ArticleFactory:

public function definition(){ return [  'title' => $this->faker->sentence(2),  'body' => $this->faker->sentence(500), ];}

Ahora simplemente lo llamamos en la clase DatabaseSeeder:

public function run()
{
\App\Models\Article::factory(1000)->create();
}

Y ejecutamos el seeding con:

php artisan db:seed

¡Esto creará 1000 filas en nuestra tabla articles que serán una prueba perfecta para nuestra búsqueda with Scout!

Instalar y configurar Scout y TNTSearch

Ahora vamos a instalar los paquetes necesarios para ejecutar Scout y TNTSearch.

Primero, instalamos Scout a través del administrador de paquetes Composer:

composer require laravel/scout

Luego, instalamos el driver TNTSearch:

composer require teamtnt/laravel-scout-tntsearch-driver

Después de que estos dos paquetes estén instalados en nuestro proyecto, deberíamos publicar el archivo de configuración de Scout usando el comando Artisanvendor:publish .

Este comando publicará el archivo de configuración scout.php en el directorio de configuración de su aplicación:

php artisan vendor:publish --provider=”Laravel\Scout\ScoutServiceProvider”

Asegúrese de tener el ScoutServiceProvider en config/app.php

// config/app.php
‘providers’ => [
// …
Laravel\Scout\ScoutServiceProvider::class,
],

Agreguemos también el proveedor de TNTSearch:

// config/app.php
‘providers’ => [
// …
TeamTNT\Scout\TNTSearchScoutServiceProvider::class,
],

Ahora agreguemos el trait Laravel\Scout\Searchable a nuestro modelo Article para que pueda ser “buscable”.

Este trait registrará un model observer que mantendrá automáticamente el modelo sincronizado con su driver de búsqueda:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Scout\Searchable;
class Article extends Model
{
use HasFactory, Searchable;
}

En nuestro archivo .env agregaremos:

SCOUT_DRIVER=tntsearch

Finalmente, en config/scout.php agreguemos esto:

'tntsearch' => [
'storage' => storage_path(),
'fuzziness' => env('TNTSEARCH_FUZZINESS', false),
'fuzzy' => [
'prefix_length' => 2,
'max_expansions' => 2,
'distance' => 2
],
'asYouType' => false,
'searchBoolean' => env('TNTSEARCH_BOOLEAN', true),
'maxDocs' => env('TNTSEARCH_MAX_DOCS', 500),
],

Índices de modelos

En primer lugar, ¿qué son los índices?

Laravel Docs nos dice que:

Each Eloquent model is synced with a given search “index”, which contains all of the searchable records for that model. In other words, you can think of each index like a MySQL table. By default, each model will be persisted to an index matching the model’s typical “table” name. Typically, this is the plural form of the model name.

Indexación

Así que ahora creamos el archivo de índice por primera vez y este índice se usará para realizar búsquedas en lugar de consultar la base de datos, ¡por lo tanto, ganamos mucha más velocidad al hacer búsquedas!

Podemos notar claramente aquí cómo Laravel Scout fragmenta los datos y los importa en el índice 500 filas a la vez, ¡evitando que nuestro script se bloquee o se agote el tiempo de espera!

Podemos cambiar el tamaño del fragmento, si queremos, en nuestro archivo config/scout.php:

/*
|--------------------------------------------------------------------------
| Chunk Sizes
|--------------------------------------------------------------------------
|
| These options allow you to control the maximum chunk size when you are
| mass importing data into the search engine. This allows you to fine
| tune each of these chunk sizes based on the power of the servers.
|
*/'chunk' => [
'searchable' => 500,
'unsearchable' => 500,
],

Ahora tenemos en nuestro directorio storage un archivo articles_index.index que utilizará Laravel Scout al realizar búsquedas en el modelo Article.

Tenga en cuenta que para evitar que nuestros índices de búsqueda se suban a nuestro repositorio de proyecto, agregaremos la siguiente línea a nuestro archivo .gitignore.

/storage/*.index

Ahora puede que te estés preguntando: ¿qué sucede cuando actualizo mi tabla articles? ¿Necesito importar los datos nuevamente y volver a crear el índice? Bueno, no, Laravel Scout ya se encarga de actualizar el Índice cada vez que actualizas tu Modelo. (es decir, cuando estás creando nuevos registros, actualizando registros y eliminando registros).

Buscando con TNT

Ahora podemos buscar en nuestro modelo Article utilizando el método search proporcionado por el Trait Searchable.

Primero, decidamos en qué campos queremos buscar escribiendo el método toSearchableArray () en nuestro modelo Article:

public function toSearchableArray()
{
$array = [
'id' => $this->id,
'title'=>$this->title
]; return $array;
}

Luego, en el método del Controller:

Article::search($request->search)->get();

Si queremos, también podemos paginar los resultados de esta manera:

Article::search($request->search)->paginate(6);

A partir de esto, obtendremos los resultados de la búsqueda y podremos considerar que esta funcionalidad está terminada. Además sin hacer queries WHERE LIKE %% en absoluto y aumentando el rendimiento de la aplicación.

Conclusión

Como hemos visto, Laravel Scout es realmente fácil de usar y es útil cuando necesitamos trabajar con bases de datos muy grandes.

El código utilizado para el proyecto de este artículo lo podéis encontrar en GitHub:

https://github.com/AndreaGern/LaravelScout

De todas formas aquí está la documentación oficial de Laravel Scout que he utilizado en este articulo:

https://laravel.com/docs/8.x/scout

Y la documentación de TNT Search Driver

https://github.com/teamtnt/laravel-scout-tntsearch-driver

--

--