關於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
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['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等工具查看信息否同步成功。