关于laravel使用Elastic Search的一些记录

文章目录

      • 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/   即可安装成功。

注意事项:

  1. 如果是8以上版本,初次启动时会生成密码。安装成功以后,访问https://localhost:9200/,会提示输入密码。用户名为elastic,密码就是初始化时的密码。
  2. 如果是8以上版本,初始化以后,携带密码访问的话,需要访问https,而不是http
  3. 如果是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文件



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一样的内容。
关于laravel使用Elastic Search的一些记录_第1张图片

4. laravel中使用es

创建脚本代码

php artisan make:command Elasticsearch/SyncProducts

修改app/Console/Commands/Elasticsearch/SyncProducts.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模型进行数据过滤



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

参考链接

  1. laravel使用elasticsearch
  2. Mysql循环添加1000条数据案列
  3. MySQL生成随机字符串
  4. win10下Elasticsearch安装配置完整教程

你可能感兴趣的:(laravel,elasticsearch,php)