创建商品的索引
http://localhost:9200/goods/
然后添加文档
“analyzer”: “ik_smart” 代表这个字段需要使用 IK 中文分词器分词
还有有一些字段的类型是 keyword,这是字符串类型的一种,这种类型是告诉 Elasticsearch 不需要对这个字段做分词,通常用于邮箱、标签、属性等字段。
skus的字段类型是 nested,代表这个字段是一个复杂对象,由下一级的 properties 字段定义这个对象的字段。我们的『商品 SKU』明明是对象数组,为什么这里可以定义成对象?这是 Elasticsearch 的另外一个特性,每个字段都可以保存多个值,这也是 Elasticsearch 的类型没有数组的原因,因为不需要,每个字段都可以是数组
给索引添加以存在的数据
关于数据的添加来源有两个点,一已经有的数据,而是后续添加的数据
- 同步已有的数据
- 同步已有的数据的方式建议采用命令;也就是artisan命令来实现;
现在虽然是在本地执行,但是项目会部署到服务器上,这个时候如果凭访问去控制器填充数据这很显然并是不一个很好地方式。
通常来说通过执行命令来实现我数据的同步会显得更加的快速。
php artisan make:command Elasticsearch/SyncGoods
在这个里边写上处理把已经存在的数据同步到elasticsearch
我们在写入商品数据的时候用的是 bulk() 方法,这是 Elasticsearch 提供的一个批量操作接口。设想一下假如我们系统里有数百万条商品,如果每条商品都单独请求一次 Elasticsearch 的 API,那就是数百万次 的请求,性能肯定是很差的,而 bulk() 方法可以让我们用一次 API 请求完成一批操作,从而减少请求次数的数量级,提高整体性能。
bulk() 方法的参数是一个数组,数组的第一维描述了我们要做的操作,第二行则代表这个操作所需要的数据,第三行操作描述,第四行数据,依次类推,当然如果是删除操作则没有数据行。我们这个代码里只有创建数据,因此都是每两行一组操作。
<?php namespace App\Console\Commands\Elasticsearch; use Illuminate\Console\Command; use App\Models\Goods; class SyncGoods extends Command { protected $signature = 'es:sync-goods'; protected $description = '将商品数据同步到 Elasticsearch'; public function __construct() { parent::__construct(); } public function handle() { $this->info('正在导入商品数据....'); // 使用 chunkById 避免一次性加载过多数据 Goods::query()->with('skus')->chunkById(100, function ($goods) { // 初始化请求体 $req = ['body' => []]; // 遍历商品 foreach ($goods as $value) { // 将商品模型转为 Elasticsearch 所用的数组 $data = $value->toESArray(); $req['body'][] = [ 'index' => [ '_index' => 'goods',// 指定es 的索引 '_type' => '_doc', '_id' => $data['id'], ], ]; $req['body'][] = $data; } try { // 使用 bulk 方法批量创建 app('es')->bulk($req); } catch (\Exception $e) { $this->error($e->getMessage()); } }); $this->info('同步完成'); } }