PHP:Laravel 使用 elasticsearch 組件包


關於MySQL數據同步到ES:

  有一些開源組件可以使用:go-mysql-elasticsearch,logstash,cancel 等...

  然后就是同步雙寫,和異步雙寫(此文使用方式)。

關於Laravel的ES組件:(注意:安裝組件請注意版本和ES相同)

  composer require laravel/scout

  Scout 是 Laravel 官方出的一個讓 Eloquent 模型支持全文搜索的包,這個包封裝好一批方法,通過這些方法就可以將數據索引到全文搜索引擎中、

以及使用關鍵字從搜索引擎搜索文檔。這個包適用於一些簡單的搜索場景,比如博客文章搜索,但無法發揮出全文搜索引擎全部威力。

  composer require elasticsearch/elasticsearch (此文使用組件)

  Elasticsearch 是Elasticsearch官方提供的composer包,它包含更豐富的操作查詢語句,例如 should 語句、

模糊查詢、分片查詢等,根本不是 Scout 幾個簡單的方法能夠覆蓋的

一:安裝elasticsearch 組件及配置

composer require elasticsearch/elasticsearch "elasticsearch/elasticsearch":"7.6.1"

  

  配置.env:

QUEUE_CONNECTION=redis
 ES_HOSTS=192.168.244.100
REDIS_HOST=192.168.244.110
REDIS_PASSWORD=123456
REDIS_PORT=6379

  配置 config/database.php:

'elasticsearch' => [
        // Elasticsearch 支持多台服務器負載均衡,因此這里是一個數組
        'hosts' => explode(',', env('ES_HOSTS')),
    ],

  初始化elasticsearch對象,並注入到 Laravel 容器中:

  修改app/Providers/AppServiceProvider.php:

use Elasticsearch\ClientBuilder as ESClientBuilder;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
        // 注冊一個名為 es 的單例
        $this->app->singleton('es', function () {
            // 從配置文件讀取 Elasticsearch 服務器列表
            $builder = ESClientBuilder::create()->setHosts(config('database.elasticsearch.hosts'));
            // 如果是開發環境
            if (app()->environment() === 'local') {
                // 配置日志,Elasticsearch 的請求和返回數據將打印到日志文件中,方便我們調試
                $builder->setLogger(app('log')->driver());
            }
            return $builder->build();
        });
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

  命令行先測試一下:

  

二:使用

  1,先建立一個索引,我在kibana里面創建的,也可以直接用 curl -XPUT http://192.168.244.100/ylt_drivers?pretty

# 創建一個索引
PUT /ylt_drivers
# 設置索引規則
PUT /ylt_drivers/_mappings?pretty
{
  "properties":{
      "name":{
        "type":"keyword"
      },
      "mobile":{
        "type":"keyword"
      },
      "sex":{
        "type":"integer"
      },
      "driver_age":{
        "type":"integer"
      },
      "is_quit":{
        "type":"boolean"
      },
      "birthday":{
        "type":"date",
        "format":"yyyy-MM-dd"
      },
      "line":{
        "type": "nested",
        "properties":{
          "name":{
            "type":"text",
            "analyzer":"ik_smart"
          },
          "distance":{
            "type":"scaled_float",
            "scaling_factor":100
          }
        }
      }
    }
}

  2,創建一個laravel command命令同步MySQL現有數據

  2.1 先在Model里面創建一個方法用來轉換數據為es需要的格式

use Illuminate\Support\Arr;

 //創建一個導入es的數據格式
    public function toESArray(){
        $arr = Arr::only($this->toArray(),[
            'id','name','mobile','sex','age','driver_age','brithday'
        ]);
      $arr['is_quit'] = $this->is_quit == 'Y' ? True : False
$arr['line'] = Arr::only($this->line->toArray(),['name','distance']);
        // 如果是列表可以用map()
        // $arr['lines'] = $this->line->map(function(Line $line){
        //     return Arr::only($line->toArray(),['name','distance']);
        // });
        return $arr;
    }

  2.2 先用命令行測試一下

  2.3  創建一個artisan command命令同步數據

php artisan make:command Elasticsearch/SyncDrivers

  打開 App\Console\Commands\Elasticsearch\SyncDrivers

namespace App\Console\Commands\Elasticsearch;

use App\Models\Driver;
use Illuminate\Console\Command;

class SyncDrivers extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'es:sync-drivers';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '將drivers數據同步到es';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        // 獲取 Elasticsearch 對象
        $es = app('es');
        Driver::query()
            // 預加載 line
            ->with(['line'])
            // 使用 chunkById 避免一次性加載過多數據
            ->chunkById(100, function ($drivers) use ($es) {
                $this->info(sprintf('正在同步 ID 范圍為 %s 至 %s 的商品', $drivers->first()->id, $drivers->last()->id));
                // 初始化請求體
                $req = ['body' => []];
                // 遍歷數據
                foreach ($drivers as $driver) {
                    // 將數據模型轉為 Elasticsearch 所用的數組
                    $data = $driver->toESArray();
                    $req['body'][] = [
                        'index' => [
                            '_index' => 'ylt_drivers',
                            '_type'  => '_doc',
                            '_id'    => $data['id'],
                        ],
                    ];
                    $req['body'][] = $data;
                }
                try {
                    // 使用 bulk 方法批量創建
                    $es->bulk($req);
                } catch (\Exception $e) {
                    $this->error($e->getMessage());
                }
            });
        $this->info('同步完成');
    }
}

  先刪除之前測試數據,再用命令執行測試。

  3:將數據提交到redis隊列,通過異步任務同步數據到es

  3.1、先創建一個異步任務:

php artisan make:job SyncOneDriverToES

  3.2、打開App\Jobs\SyncOneDriverToES

namespace App\Jobs;

use App\Models\Driver;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class SyncOneDriverToES implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $driver;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(Driver $driver)
    {
        $this->driver = $driver;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $data = $this->driver->toESArray();
        app('es')->index([
            'index' => 'ylt_drivers',
            'type'  => '_doc',
            'id'    => $data['id'],
            'body'  => $data,
        ]);
    }
}

  3.3、在數據編輯和新增的地方加入異步提交代碼,這里使用的是laravel-admin,所以在form()方法里加入:

 $form->saved(function (Form $form) {
            $driver = $form->model();
            dispatch(new SyncOneDriverToES($driver));
        });

  3.4、啟動隊列

php artisan queue:work

  

然后可以通過es-head等工具查看信息否同步成功。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM