آموزش استفاده از Elasticsearch (جستجوی پیشرفته) در لاراول

29 مرداد 1397
Elasticsearch-twitter_(1)

در این آموزش قصد داریم نحوه استفاده از Elasticsearch در لاراول را به شما آموزش بدهیم.

دراین آموزش ما از Elasticquent  که یکی از پکیج های composer است، استفاده می کنیم. این پکیج مخفف عبارت Elasticsearch for Eloquent Laravel Modelsمی باشد.

Elasticquent کار با Elasticsearch و مدل های Eloquent را آسان می کند و این کار را با نگاشت آنها با نوع های Elasticsearch انجام می دهد.

شما می توانید از تنظیمات پیش فرض استفاده کنید یا تعریف کنید که چگونه Elasticsearch باید مدل های Eloquent شما را به درستی شاخص گذاری و جستجو کند.

Elasticquent به شما اجازه می دهد که یک مدل Eloquent را بگیرید و به آسانی محتوای آن را در Elasticsearch شاخص گذاری و جستجو کنید.

سرفصل های این فصل

1- نصب Elasticsearch روی مک

2- نصب لاراول و Elasticsearch env

3- ایجاد یک مدل Article به همراه Migration آن

4- ایجاد داده های آزمایشی

5- نصب Elasticquent داخل مدل Article

6- جستجو با استفاده از متدهای Eloquent لاراول

آموزش Elasticsearch در لاراول

این مثال را با نصب Elasticsearch روی مک شروع می کنیم.

1- نصب Elasticsearch روی مک

در صورتی که قبلاً Elasticsearch را روی مک نصب نکرده اید، این مرحله را مطالعه کنید در غیراینصورت می توانید از این مرحله عبور کرده و مرحله بعد را بخوانید.

ابتدا با استفاده از homebrew (نرم افزار مدیریت پکیج) Elasticsearch را نصب می کنیم.

brew install elasticsearch

سپس با دستور زیر service را اجرا می کنیم

brew services start elasticsearch

راه اندازی لاراول و Elasticsearch env

با دستور زیر لاراول 5.6 را نصب کنید.

laravel new elasticlaravel

سپس وارد پروژه شوید:

cd elasticlaravel

پروژه را با یک ویرایشگر متنی باز کنید

code .

فایل .env را باز کرده و قسمت تنظیمات پایگاه داده آن را ویرایش کنید.

کدهای زیر را به فایل composer.json اضافه کنید. در این فایل ما پکیج Elasticquent را نصب می کنیم.

"require": {
        "php": "^7.1.3",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "5.6.*",
        "laravel/tinker": "^1.0",
        "elasticquent/elasticquent": "dev-master"
    },

سپس کدهای زیر را برای نصب پکیج elasticquent اجرا کنید.

composer update

نصب elasticsearch در لاراول

بعد از اینکه دستور composer update را اجرا کردید، باید service provider آن را در فایل config > app.php ثبت کنید.

// config/app.php

'providers' => [
    ...
    Elasticquent\ElasticquentServiceProvider::class,
],

همچنین یک facade برای کلاینت elasticsearch فراهم می کنیم (که با استفاده از تنظیمات ما متصل می شود) و کدهای زیر را در config > app.php وارد کنید.

// config/app.php

'aliases' => [
    ...
    'Es' => Elasticquent\ElasticquentElasticsearchFacade::class,
]

تنظیمات Elasticsearch

دستور زیر را برای انتشار فایل تنظیمات داخل دایرکتوری تنظیمات برای لاراول 5.6 ، اجرا کنید:

php artisan vendor:publish --provider="Elasticquent\ElasticquentServiceProvider"

حال به فایل تنظیمات در مسیر app > config > elasticquent.php بروید.

در اینجا ما می خواهیم یک اسم شاخص برای برنامه خود اضافه کنیم، پس اسم آن را از default به articles تغییر می دهیم.

<?php

// elastiquent.php

return array(

    /*
    |--------------------------------------------------------------------------
    | Custom Elasticsearch Client Configuration
    |--------------------------------------------------------------------------
    |
    | This array will be passed to the Elasticsearch client.
    | See configuration options here:
    |
    | http://www.elasticsearch.org/guide/en/elasticsearch/client/php-api/current/_configuration.html
    */

    'config' => [
        'hosts'     => ['localhost:9200'],
        'retries'   => 1,
    ],

    /*
    |--------------------------------------------------------------------------
    | Default Index Name
    |--------------------------------------------------------------------------
    |
    | This is the index name that Elasticquent will use for all
    | Elasticquent models.
    */

    'default_index' => 'articles',

);

ایجاد یک مدل Article به همراه migration آن

ما می خواهیم مقالات را با استفاده از elasticsearch جستجو کنیم.

ابتدا با دستور زیر مدل به همراه migration  آن را ایجاد می کنیم:

php artisan make:model Article -m

سپس در فایل <DATETIME>_create_articles_table.php یک Schema اضافه کنید:

// create_articles_table.php

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

سپس با دستور زیر جدول را migrate کنید:

php artisan migrate

4- ایجاد داده های آزمایشی

با دستور زیر یک ArticleTableSeeder ایجاد کنید.

php artisan make:seeder ArticleTableSeeder

برای تولید داده های ساختگی، از کتابخانه Faker استفاده می کنیم.

البته قبل از آن باید یک فیلد protected $fillable را داخل فایل Article.php ایجاد کنید تا از بروز خطای mass assignment exception جلوگیری شود.

// Article.php

class Article extends Model
{
    protected $fillable = ['title', 'body', 'tags'];
}

حال، کدهای زیر را داخل فایل ArticleTableSeeder.php ایجاد کنید.

<?php

// ArticleTableSeeder.php

use Illuminate\Database\Seeder;
use App\Article;

class ArticleTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $faker = Faker\Factory::create();

        for($i=0; $i<50; $i++) {
          Article::create([
            'title' => $faker->sentence(3),
            'body' => $faker->paragraph(6),
            'tags' => join(',', $faker->words(4))
          ]);
        }
    }
}

کلاس ArticleTableSeeder را داخل فایل DatabaseSeeder.php اضافه کنید

<?php

// DatabaseSeeder.php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(ArticleTableSeeder::class);
    }
}

حالا seeder را اجرا کنید و داده های ساختگی تان را با استفاده از دستور زیر ایجاد کنید

php artisan db:seed

 

افزودن داده های آزمایشی به پایگاه داده لاراول

5-راه اندازی Elasticquent داخل مدل Article

کدهای زیر را داخل فایل Article.php ایجاد کنید.

<?php

// Article.php

namespace App;
use Elasticquent\ElasticquentTrait;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use ElasticquentTrait;

    protected $fillable = ['title', 'body', 'tags'];

    protected $mappingProperties = array(
        'title' => [
          'type' => 'text',
          "analyzer" => "standard",
        ],
        'body' => [
          'type' => 'text',
          "analyzer" => "standard",
        ],
        'tags' => [
          'type' => 'text',
          "analyzer" => "standard",
        ],
      );
}

در کد بالا ما تنظیمات نگاشت مورد نظرمان را برای Elasticsearch اضافه کردیم. جدول پایگاه داده سه فیلد اصلی دارد که ما باید به type و analyzer یک مقدار نسبت بدهیم که در ایجا ما standard را به آن می دهیم. همان طور که به یاد دارید اسم index برابر article بود. آرایه mappingProperties فیلدهایی دارد که باید با نوع (type) های مناسب برای جستجو و گرفتن بهترین نتایج ایندکس گذاری شود.

هر نگاشت (mapping) یک type و analyzer دارد. type ها می توانند شامل انواع مختلف نوع داده ها مثل رشته(string)، اعداد(number) و تاریخ(date) باشد.

ما در اینجا از نوع داده text استفاده کردیم اما شما می توانید از نوع داده های دیگری هم استفاده کنید.

برای کسب اطلاعات بیشتر درباره نوع داده  ها ، مستندات Elasticsearch را مطالعه کنید.

حالا باید پایگاه داده را ایندکس گذاری کنیم. داخل فایل web.php کدهای زیر را بنویسید.

دقت داشته باشید که من کدهای زیر را در فایل web.php نوشتم ، اما در برنامه های واقعی شما باید این کدها را در کنترلر یا هر بخش دیگری که مسئول بخش منطق برنامه است (به جز web.php)  بنویسید.

شاخص گذاری اسناد

برای شاخص گذاری تمام ورودی ها در یک مدل Eloquent از addAllToIndex استفاده کنید.

  Article::addAllToIndex();

همچین می توانید یک مجموعه از مدل ها را شاخص گذاری کنید:

$articles = Article::where('id', '<', 200)->get();
    $articles->addToIndex();

با کد زیر می توانید یک فیلد خاص را شاخص گذاری کنید:

  $articles = Article::find($id);
    $articles->addToIndex();

می توانید یک مدل را شاخص گذاری مجدد کنید.

  Article::reindex()

حالا ما کل مدل را شاخص گذاری می کنیم، پس ما می توانیم کدهای شاخص گذاری را داخل روت ریشه( که با ‘\’ در فایل web.php نمایش می دهیم)

<?php

// web.php

use App\Article;

Route::get('/', function () {
    Article::createIndex($shards = null, $replicas = null);

    Article::putMapping($ignoreConflicts = true);

    Article::addAllToIndex();

    return view('welcome');
});

در اینجا ما صفحه index را ایجاد می کنیم. اسم ایندکس قبلا در فایل config > elasticquent.php تعریف شده بود.

سپس نگاشت هایی که در مدل Article.php تعریف کردیم را در آن قرار می دهیم و در انتها آن را با شاخص خود اضافه می کنیم.

آدرس http://localhost:8000 را در مرورگر وارد کنید.

با اینکار وارد صفحه welcome می شوید، اما داده هایمان شاخص گذاری می شود و برای بررسی صحت کارکرد برنامه، درخواست زیر را با استفاده از cURL ارسال می کنیم.

همچنین می توانیم از برنامه postman برای اینکار استفاده کنیم. اما من کد زیر را در ترمینال وارد میکنیم.

curl 'localhost:9200/articles/_mapping?pretty'

دریافت داده به صورت json از پایگاه داده در لاراول

همچنین با دستور زیر می توانید یک جستجوی ساده روی آن انجام دهید:

curl 'localhost:9200/articles/articles/_search?q=title:Sed&pretty'

در اینجا ما کلمه sed را برای جستجو در قسمت عنوان مقالات ارسال می کنیم و برنامه به عنوان نتیجه جستجو رکوردهایی را که کلمه sed را دارند، بر می گرداند.

همچنین می توانیم نتایج رادر محیط ترمینال مانند زیر ببینیم:

دریافت داده های آزمایشی توسط elasticsearch

6- جستجو با استفاده از متدهای eloquent

ما تا اینجا از cURL برای جستجوی داده ها استفاده می کردیم. اما در اینجا می خواهیم از متدهای eloquent برای جستجوی داده ها بهره ببریم.

ابتدا یک روت در فایل web.php ایجاد کنید و کدهای زیر را در آن قرار دهید:

<?php

// Article.php

use App\Article;

Route::get('/', function () {
    Article::createIndex($shards = null, $replicas = null);

    Article::putMapping($ignoreConflicts = true);

    Article::addAllToIndex();

    return view('welcome');
});

Route::get('/search', function() {

    $articles = Article::searchByQuery(['match' => ['title' => 'Sed']]);

    return $articles;
});

من کلمه sed را به صورت دستی به آن پاس دادم، اما در برنام های واقعی، عبارتی که میخواهیم جستجو کنیم را از یک فیلد input جستجو، دریافت می کنیم. آدرس http://localhost:8000/search را در مرورگر وارد کنید، همان طور که می بینید مرورگر کدهای json زیر را به ما بر می گرداند

کدهای json دریافتی از پایگاه داده در لاراول

البته شما ممکن است داده های متفاوت به شکل بالا دریافت کنید چون داده ها به صورت تصادفی تولید می شوند.

کلمه مورد نظرمان را به موتور جستجو پاس می دهیم و این موتور این عنوان را در پایگاه داده جستجو کرده و نتایجی مانند زیر را تولید می کند.

ما توانستیم با موفقیت داده ها را شاخص گذاری کرده و آنها را از موتور جستجوی Elasticsearch برگردانیم.

در این مثال ما در عنوان مقالات جستجو کردیم، اما شما می توانید برای محتوای پست ها و یا تگ های پست ها هم جستجو را  انجام دهید.

$articles = Article::searchByQuery(['match' => ['body' => 'eligendi']]);
    
return $articles;

همچنین می توانید برای تگ ها هم مانند بالا عمل جستجو را انجام دهید.

مجموعه های جستجو

می توانیم تعداد نتایجی که با کلمه مورد جستجوی ما مطابقت داشت را بر گردانیم

$articles = Article::searchByQuery(['match' => ['title' => 'Heleium']]);
    
 return $articles->totalHits();

برای دسترسی به آرایه shards:

 $articles->shards();

برای دسترسی به بیشترین امتیاز:

 $articles->maxScore();

دسترسی به پروپرتی بولین time out:

 $articles->timedOut();

دسترسی به پروپرتی took

$articles->took();

دسترسی به مجموعه (aggregation)های جستجو

 $articles->getAggregations();

تقسیم نتایج جستجو به مجموعه های کوچکتر با استفاده از Elasticquent

در صورتی که تعداد نتایج جستجوی شما زیاد باشد می توانید از تابع chunk() برای تقسیم آن به مجموعه های کوچکتر استفاده کنید.

$articles = Article::searchByQuery(['match' => ['title' => 'Similique']]);
    
return $articles->chunk(2);
نویسنده شوید
دیدگاه‌های شما (2 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

reza
26 تیر 1398
امکانش هست برای ویندوز هم آموزش نصب قرار بدید. اکثر افراد از ویندوز استفاده می کنند

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

ارام
26 خرداد 1398
سلام خب مابقیه مدل ها چطوری ایندکس گذاری میشه الان شما فقط یک نام "آرتیکل" انتخاب کردید من 10 تا مدل دارم که برای هر کدوم باید ایندکس مخصوص بذارم چطوری امکان پذیره؟ تشکر

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مسعود
28 اسفند 1400
بهترین راه حل اینه که مسقیم از دستورات الاستیک از طریق php استفاده کنی اگر نشد یه راه حل اینه که با ایگر لودینگ پیش فرض برای مدل مادر ایجاد کنی و بعد فقط همان مدل رو ایندکس کنی. با دستور with داخل مدل میتونی به صورت پیشفرض رابطه رو لود کنی.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مسعود
28 اسفند 1400
همیشه هم داک این پکیج ها رو با حوصله مخونیم میتونیم به راه حل هایی برسیم نمونه: function getIndexName() { return 'custom_index_name'; } با این کد میشه ایندکس جدید تعریف کرد

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.