创建商品的索引
http://localhost:9200/goods/
然后添加文档
“analyzer”: “ik_smart” 代表这个字段需要使用 IK 中文分词器分词
还有有一些字段的类型是 keyword,这是字符串类型的一种,这种类型是告诉 Elasticsearch 不需要对这个字段做分词,通常用于邮箱、标签、属性等字段。
skus的字段类型是 nested,代表这个字段是一个复杂对象,由下一级的 properties 字段定义这个对象的字段。我们的『商品 SKU』明明是对象数组,为什么这里可以定义成对象?这是 Elasticsearch 的另外一个特性,每个字段都可以保存多个值,这也是 Elasticsearch 的类型没有数组的原因,因为不需要,每个字段都可以是数组
然后测试
注意需要重新打开tinker
$goods = App\Models\Goods::find(78)->toESArray();
然后把这条数据存储到elasticsearch
app(‘es’)->index([‘id’ => $goods[‘id’], ‘index’ => ‘goods’, ‘type’ => ‘_doc’, ‘body’ => $goods]);
然后就可以从elasticsearch中获取出来
app(‘es’)->get([‘index’ => ‘goods’, ‘type’ => ‘_doc’, ‘id’ => 78]);
给索引添加以存在的数据
关于数据的添加来源有两个点,一已经有的数据,而是后续添加的数据
- 同步已有的数据
同步已有的数据的方式建议采用命令;也就是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('同步完成');
}
}
执行命令:
php artisan es:sync-goods
然候使用head就可以查到
同步添加数据
接下来同步新增和修改的商品,因为是同步于商品的新增和修改所以最好的是创建一个事件或者队列完成。
这里可以使用异步操作
php artisan make:job SyncGoodsToEs
<?php
namespace App\Jobs;
use App\Models\Goods;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class SyncGoodsToEs implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $goods;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Goods $goods)
{
$this->goods = $goods;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$data = $this->goods->toEsArray();
app('es')->index([
'index' => 'goods',
'type' => '_doc',
'id' => $data['id'],
'body' => $data,
]);
}
}
该事件的触发可以放在保存数据后执行,也就是点击添加商品的提交时触发