Laravel 8 full text search: Scout

#WebDevelopment   #softwaredevelopment  

1_luRsAtV_Jnz90zQMkY46uQ.png

Full text with TNT

We all know what is the most needed feature in our projects: search for content in our app.
That’s exactly what we’re going to do here using Laravel Scout & Tnt Search.

Laravel Scout

Laravel Scout provides a simple, driver based solution for adding full-text search to your Eloquent models. Using model observers, Scout will automatically keep your search indexes in sync with your Eloquent records.

TNT Search
TNTSearch is a fully-featured full-text search engine written entirely in PHP. It’s simple configuration allows you to add an amazing search experience to your site in just minutes.

Getting Started

Well, now that we know a little bit what we’re talking about, we’re going to put all this to work on a quick and simple Laravel Blog project!

Let's create the project:

                laravel new blog-tntsearch
            

Structuring the data

Create a Database and connect it to our project by setting up the .env file.
Now we need a model, a migration, a controller and a factory to structure our project and play around a bit. Let's create all this with the Artisan command:

                php artisan make:model Article -mcf
            

We'll fill our migration with some simple fields:

                public function up()
{
 Schema::create('articles', function (Blueprint $table) {
  $table->id();
  $table->string('title');
  $table->text('body');
  $table->timestamps();
 });
}
            

Now let's migrate the table:

                php artisan migrate
            

And let's fill our table with some dummy data thanks to the factory we've created! To configure the factory simply write this in our ArticleFactory class:

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

Now just call it in the DatabaseSeeder class:

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

And execute the seeding with:

                php artisan db:seed
            

This will create 1000 rows in our articles table that are going to be a perfect test for our Scout search!

Install and configure Scout & TNTSearch

Now we'll install the required packages for running Scout and TNTSearch.

First, install Scout via the Composer package manager:

                composer require laravel/scout
            

Then, install the TNTSearch Driver:

                composer require teamtnt/laravel-scout-tntsearch-driver
            

After those two are installed in our project, we should publish the Scout configuration file using the vendor:publish Artisan command. This command will publish the scout.php configuration file to your application's config directory:

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

Make sure you have the Scout Service Provider in config/app.php

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

Let's add the TNTSearch Provider too:

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

Now let's add the Laravel\Scout\Searchable trait to our Article model to make it searchable.
This trait will register a model observer that will automatically keep the model in sync with your search driver:

                <?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;
}
            

In our .env file we'll add:

                SCOUT_DRIVER=tntsearch
            

Finally, in config/scout.php let's add this:

                '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),
    ],
            

Model Indexes

First of all, what are indexes?

Laravel Docs tell us that:

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.

Indexing

So now we will create the Index file for the first time and this index will be used to perform searches instead of querying the database, this will let us gain much more speed while doing searches!

                php artisan scout:import App\\Models\\Article
            

We can clearly observe here how Laravel Scout chunks the data and imports it in the index 500 rows at a time, preventing our script from crashing or timing out!

We can change the chunk size if we want in our config/scout.php file:

                /*
    |--------------------------------------------------------------------------
    | 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,
 ],
            

We now have in our storage directory an articles_index.index file which Laravel Scout will use when performing searches on the Article Model.

Be aware, to prevent our search indexes to being committed to our project repository, we’ll add the following line to our .gitignore file.

                /storage/*.index
            

Now your next question might be: well, what happens when I update my articles table, do I need to import the data again and recreate the Index? Well no, Laravel Scout already takes care of updating the Index whenever you are updating your Model. ( i.e when you are creating new records, updating records and deleting records )

Searching using TNT

We can now search in our Article model using the search method provided by the Searchable Trait.

First, let’s decide in which fields we do want to search by writing the toSearchableArray() method in our Article model:

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

Then in the Controller method:

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

If you want you could also paginate the results like this:

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

From this we’ll obtain the search results we wanted and consider this functionality done! Without even using WHERE LIKE %% queries at all and having a boost in our efficiency and performance.

Conclusion

As we've seen Laravel Scout is really easy to use and I suggest you to use it when you need to deal with very large databases.

You can find the code used in this article in this project I've pushed you on GitHub:

https://github.com/AndreaGern/LaravelScout

Take a look at the Laravel Scout official docs I've referenced in the article:

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

And the doc page for TNT Search Driver

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


Only registered users can post comments. Please, login or signup.

Start blogging about your favorite technologies and get more readers

Join other developers and claim your FAUN account now!

Stats
6

Influence

660

Total Hits

1

Posts

Discussed tools