文章目录
- 1. 准备工作
- 2. 本地安装elastic search
- 3. laravel安装es依赖
- 4. laravel中使用es
- 参考链接
1. 准备工作
因为我本地php版本是7.3.4,不支持太高的es。
所以使用如下环境:
laravel6 + php7.3.4 + elastic search 7.17.2
2. 本地安装elastic search
1. 下载安装包(这里下载的是7.17.2版本) https://www.elastic.co/cn/downloads/past-releases
2. 解压进入文件夹
3. 修改config/jvm.options文件,
1. 将虚拟机大小
-Xms4g
-Xmx4g
改为:
-Xms256m
-Xmx1g
2. 再文件最后添加以下代码。(防止启动时乱码)
-Dfile.encoding=GBK
4. 双击bin目录下的elasticsearch.bat文件,启动elastic search。
5. 访问http://localhost:9200/ 即可安装成功。
注意事项:
- 如果是8以上版本,初次启动时会生成密码。安装成功以后,访问https://localhost:9200/,会提示输入密码。用户名为elastic,密码就是初始化时的密码。
- 如果是8以上版本,初始化以后,携带密码访问的话,需要访问
https
,而不是http
。- 如果是8以上版本,想要关闭密码的话,需要修改config/elasticsearch.yml文件,修改如下:
xpack.security.enabled: false
3. laravel安装es依赖
composer require elasticsearch/elasticsearch “7.17.2”
配置database.php
'elasticsearch' => [
// Elasticsearch 支持多台服务器负载均衡,因此这里是一个数组
'hosts' => explode(',',env('ES_HOSTS')),
]
.env 配置
ES_HOSTS=127.0.0.1:9200
初始化es对象,注入到容器中。
修改App/Providers/AppServiceProvider.php文件
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
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()
{
//
}
}
测试是否成功,
php artisan tinker
>>>app('es')->info();
会输出和访问http://127.0.0.1:9200
一样的内容。
4. laravel中使用es
创建脚本代码
php artisan make:command Elasticsearch/SyncProducts
修改app/Console/Commands/Elasticsearch/SyncProducts.php
文件
<?php
namespace App\Console\Commands\Elasticsearch;
use App\Models\Product;
use Illuminate\Console\Command;
class SyncProducts extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'es:sync-products';
/**
* The console command description.
*
* @var string
*/
protected $description = '将商品数据同步到 Elastic Search';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// 获取 Elasticsearch 对象
$es = app('es');
$sql = 'id,`name`,`desc`,brand_id,category_id,shop_id,price,sold_count,review_count,status,create_time';
Product::query()
->selectRaw($sql)
// 使用 chunkById 避免一次性加载过多数据
->chunkById(100, function ($products) use ($es) {
$this->info(sprintf('正在同步 ID 范围为 %s 至 %s 的商品', $products->first()->id, $products->last()->id));
// 初始化请求体
$req = ['body' => []];
// 遍历商品
foreach ($products as $product) {
// 将商品模型转为 Elasticsearch 所用的数组
$data = $product->toESArray($product->id, $product->category_id);
$req['body'][] = [
'index' => [
'_index' => 'test',
'_id' => $data['id'],
],
];
$req['body'][] = $data;
}
try {
// 使用 bulk 方法批量创建
$es->bulk($req);
} catch (\Exception $e) {
$this->info($e->getMessage());
}
});
$this->info('同步完成');
}
}
创建Product模型进行数据过滤
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
class Product extends Model
{
//
public $table = "product";
public function toESArray($product_id,$category_id)
{
// 只取出需要的字段
$arr = Arr::only($this->toArray(), [
'id',
'name',
'desc',
'brand_id',
'shop_id',
'price',
'sold_count',
'review_count',
'status',
'create_time'
]);
// $productSkus = ProductSkus::query()->selectRaw('name,price')->where('product_id',$product_id)->get()->toArray();
// skus在索引中是一个二维数组, 这里只取出需要的 SKU 字段
// $arr['skus'] = $productSkus;
$arr['skus'] = rand(111111,999999);
// $sql = "lmrs_at.name as name,lmrs_at_val.name as value";
// $attributes = Attributes::query()->selectRaw($sql)
// ->from('attributes as at')
//
// ->leftJoin('attribute_values as at_val','at.id','at_val.attribute_id')
//
// ->where('at.category_id',$category_id)
//
// ->get()->toArray();
// attributes 在索引中是一个二维数组, 这里只取出需要的商品属性字段
// $arr['attributes'] = $attributes;
$arr['attributes'] = 'attributes';
return $arr;
}
}
我们在写入商品数据的时候用的是 bulk() 方法,这是 Elasticsearch 提供的一个批量操作接口。设想一下假如我们系统里有数百万条商品,如果每条商品都单独请求一次 Elasticsearch 的 API,那就是数百万次的请求,性能肯定是很差的,而 bulk() 方法可以让我们用一次 API 请求完成一批操作,从而减少请求次数的数量级,提高整体性能。
创建表
CREATE TABLE `zlsn_product` (
`id` int(4) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL COMMENT '商品名',
`desc` varchar(255) DEFAULT NULL COMMENT '描述',
`brand_id` int(4) DEFAULT NULL COMMENT '品牌id',
`category_id` int(4) DEFAULT NULL COMMENT '分类id',
`shop_id` int(4) DEFAULT NULL COMMENT '店铺id',
`price` decimal(10,2) DEFAULT NULL COMMENT '价格',
`sold_count` int(4) DEFAULT NULL COMMENT '卖出数量',
`review_count` int(4) DEFAULT NULL COMMENT '回购数量',
`status` tinyint(1) DEFAULT '1' COMMENT '状态 1 正常 2 下架',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8mb4 COMMENT='商品表';
创建执行过程,用来随机插入1000条测试数据
CREATE PROCEDURE p01 ()
BEGIN
declare i int;
set i=1001;
while i<=2000 do
INSERT INTO product ( `name`, `desc`, brand_id, category_id, shop_id, price, sold_count, review_count, `status`, create_time )
VALUES
(
(SELECT
SUBSTRING( MD5( RAND()), 1, 5 )),
(SELECT
SUBSTRING( MD5( RAND()), 1, 10 )),
(SELECT
CEILING( RAND() * 1000 )),
(SELECT
CEILING( RAND() * 1000 )),
(SELECT
CEILING( RAND() * 1000 )),
(SELECT
CEILING( RAND() * 1000 )),
(SELECT
CEILING( RAND() * 1000 )),
(SELECT
CEILING( RAND() * 1000 )),
1,
NOW());
set i=i+1;
end WHILE;
END;
运行以下SQL,执行此执行过程,生成测试数据
CALL p01 ();
此时zlsn_product表中就有测试数据了。
运行php脚本,将生成的SQL数据存入到es
php artisan es:sync-products
参考链接
- laravel使用elasticsearch
- Mysql循环添加1000条数据案列
- MySQL生成随机字符串
- win10下Elasticsearch安装配置完整教程