一分一毛也是爱

微信

微信

支付宝

支付宝

观海听潮

观海听潮博客

登录
还没有账号?去注册
观海听潮

观海听潮博客

注册
×

我的名片

网名:观海听潮

职业:PHP开发工程师

现居:山东省-青岛市

Email:1256699215@qq.com

网站统计

  • 观海听潮•博客
  • 77篇
  • 149条
  • 119513次
  • 250次
  • 美国弗吉尼亚州

您现在的位置是:首页  > 技术杂谈  > Laravel  > php  > elasticsearch elasticsearch

观海听潮

laravel 引入elasticsearch7.8.1搜索引擎(五)

摘要
本文主要讲查询前的数据准备,创建索引,创建mapping和同步数据到elasticseach

1、数据准备

参考之前的项目,本文用订单商品的数据的做搜索

1)、订单表order_info,主要字段有:

id(主键)、order_no(订单号)、user_name(下单人)、consignee(收货人)、addresses(收货地址)、order_status(订单状态1~6)

created_at(下单时间)、store_id(店铺id)、order_amount(订单总额)

2)、订单商品表order_goods,主要字段有:

id(主键)、order_id(订单id)、goods_name(商品名称)、goods_spec(商品规格)、goods_price(商品价格)

3)、店铺表store,主要字段有:

id(主键)、store_name(店铺名称)

4)、测试数据:

1598839267000355c.zip

5)、构造数据库模型,Order.php文件

<?php

namespace App\Models;


use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Arr;
use App\Models\OrderGoods;

/**
 * @property mixed pay_type 支付方式 1支付宝, 2微信,3余额
 * @property mixed user
 */
class Order extends Model
{

    protected $table = 'order_info';
    public $timestamps = false;
    protected $fillable = ['order_no', 'store_id', 'user_id', 'user_name', 'consignee',
        'phone', 'province', 'district', 'city', 'address', 'addresses', 'leave_msg', 'order_status', 'return_status',
        'is_lock', 'goods_amount', 'order_amount', 'logistics_amount','discount_amount','commission_amount','reward_wheat', 'remark', 'pay_type', 'source',
        'is_show', 'pay_at', 'delivery_at', 'finish_at', 'cancel_at', 'delete_at', 'created_at', 'updated_at'];

    public function goods()
    {
        return $this->hasMany('App\Models\OrderGoods', 'order_id', 'id');
    }

    public function store(){
        return $this->belongsTo('App\Models\Store','store_id','id');
    }

    public function toESArray()
    {
        // 只取出需要的字段
        $arr = Arr::only($this->toArray(), [
            'id',
            'order_no',
            'user_name',
            'consignee',
            'addresses',
            'order_status',
            'order_amount',
            'created_at',
        ]);
        $arr['store_name'] = $this->store->store_name;
        // 只取出需要的 goods 字段
        $arr['goods'] = $this->goods->map(function (OrderGoods $goods){
            return Arr::only($goods->toArray(),['goods_name', 'goods_spec', 'goods_price']);
        });
        //随机生成属性
        $arr['properties'] = collect($this->getProperties())->map(function($properties,$key){
            return array_merge($properties, [
                'search_value' => $properties['name'].':'.$properties['value'],
            ]);
        });
        return $arr;
    }

    //构造商品属性规格数据
    public function getProperties(){
        $params = [];
        $params1 = [
            ["name" => "品牌名称", "value" => "金士顿"],
            ["name" => "品牌名称", "value" => "海盗船"],
            ["name" => "品牌名称", "value" => "三星"],
            ["name" => "品牌名称", "value" => "影驰"],
            ["name" => "品牌名称", "value" => "威刚"],
        ];
        $params2 = [
            ["name" => "内存容量", "value" => "8GB"],
            ["name" => "内存容量", "value" => "4GB"],
            ["name" => "内存容量", "value" => "16GB"],
        ];
        $params3 = [
            ["name" => "传输类型", "value" => "DDR4"],
            ["name" => "传输类型", "value" => "DDR3"],
        ];
        $params[] = $params1[rand(0,4)];
        $randNum = rand(1,3);
        foreach($params2 as $k=> $val){
            if($k<$randNum){
                $params[] = $val;
            }else{
                break;
            }
        }
        $params[] = $params3[rand(0,1)];
        return $params;
    }

}

OrderGoods.php文件

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class OrderGoods extends Model
{

    protected $table = 'order_goods';
    protected $fillable = ['order_id','goods_id','sku_id','goods_name','goods_image',
    'goods_num','original_price','goods_price','goods_spec','logistics_amount','receive_amount','goods_amount','is_after_sale','status'];

}

Store.php文件

<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class Store extends Model
{
    protected $table = 'store'; // 指定表
    protected $fillable = ['id', 'phone_number', 'store_name', 'password', 'store_logo', 'store_domain_name', 'store_grade', 'store_duration', 'store_type', 'passed', 'refuse_reason', 'is_usable', 'remark', 'reason', 'invoice', 'payment_voucher', 'remember_token', 'submit_time', 'first_trial_time', 'upload_documents_time', 'pass_time', 'open_time'];

    public function orders(){
        $this->hasMany('App\Models\Order','store_id','id');
    }
}

2、创建索引orders

通过创建一个 Artisan 命令来实现,创建Elasticsearch目录,执行命令

php artisan make:command Elasticsearch/CreateIndex

CreateIndex.php文件内容

<?php

namespace App\Console\Commands\Elasticsearch;
use Illuminate\Console\Command;

class CreateIndex extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'es:create-index {index}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '创建Elasticsearch索引';
    protected $index;
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //删除之前创建的索引
        $this->index = $this->argument('index');
        if ($this->existIndex()) {
            $this->deleteIndex();
            $this->info('已删除索引:'.$this->index);
        }
        //创建索引
        app('es')->indices()->create([
            'index' => $this->index,
            'body' => [
                'settings' => [
                      'analysis' => [
                          'analyzer' => [
                              'ik_smart_synonym' => [
                                  'type'      => 'custom',
                                  'tokenizer' => 'ik_max_word',
                                  'filter'    => ['synonym_filter'],
                              ],
                          ],
                          'filter'   => [
                              'synonym_filter' => [
                                  'type'          => 'synonym',
                                  'synonyms_path' => 'analysis/synonyms.txt',
                              ],
                          ],
                      ],
                ],
            ]
        ]);
        $this->info('已创建索引:'.$this->index);
    }

    /**
     * @desc 检测索引
     * @method existIndex
     * @return bool
     * @time 2020/8/7 17:05
     */
    public function existIndex(){
        return app('es')->indices()->exists(['index' => $this->index]);
    }

    /**
     * @desc 删除索引
     * @method deleteIndex
     * @return array
     * @time 2020/8/7 17:05
     */
    public function deleteIndex(){
        return app('es')->indices()->delete(['index' => $this->index]);
    }
}

创建索引时要先判断之前是否已创建,如果已创建就先删除后在重新创建,创建所以时settings设置了同义词配置,关于同义词的安装之前已经讲过,这里就不再叙述了。

执行命令创建orders索引

php artisan es:create_index orders

3、创建mappings

通过创建一个 Artisan 命令来实现,执行命令

php artisan make:command Elasticsearch/CreateMapping

CreateMapping.php文件内容

<?php

namespace App\Console\Commands\Elasticsearch;

use Illuminate\Console\Command;
class CreateMapping extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'es:create-mapping {index}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '创建Elasticsearch映射';
    protected $index;
    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $this->index = $this->argument('index');
        $params = $this->getParams();
        app('es')->indices()->putMapping($params);
        $this->info('已创建映射:'.$this->index);
    }

    public function getParams(){
        $params = [
            'index'=>$this->index,
            'type'=>'_doc',
            'custom'=>['include_type_name'=>true],
            'body'=>[
                '_doc'=>[
                    'properties'=>[

                    ]
                ]
            ]
        ];
        switch ($this->index){
            case 'orders':
                $params['body']['_doc']['properties'] = [
                    'id'=>['type'=>'integer'],
                    'order_no'=>['type'=>'keyword'],
                    'order_amount'=>['type'=>'scaled_float','scaling_factor'=>100],
                    'order_status'=>['type'=>'byte'],
                    'created_at'=>['type'=>'keyword'],
                    'user_name'=>['type'=>'text',"analyzer"=>"ik_max_word", "search_analyzer"=>"ik_smart_synonym"],
                    'consignee'=>['type'=>'text',"analyzer"=>"ik_max_word", "search_analyzer"=>"ik_smart_synonym"],
                    'store_name'=>['type'=>'text',"analyzer"=>"ik_max_word", "search_analyzer"=>"ik_smart_synonym"],
                    'addresses'=>['type'=>'text',"analyzer"=>"ik_max_word", "search_analyzer"=>"ik_smart_synonym"],
                    'goods'=>[
                        'type'=>'nested',
                        'properties'=>[
                            'goods_name'=>['type'=>'text',"analyzer"=>"ik_max_word", "search_analyzer"=>"ik_smart_synonym",'copy_to'=>'goodsName'],
                            'goods_spec'=>['type'=>'text',"analyzer"=>"ik_max_word", "search_analyzer"=>"ik_smart_synonym",'copy_to'=>'goodsSpec'],
                            'goods_price'=>['type'=>'scaled_float','scaling_factor'=>100]
                        ]
                    ],
                    'properties'=>[
                        'type'=>'nested',
                        'properties'=>[
                            'name'=>['type'=>'keyword','copy_to'=>'properties_name'],
                            'value'=>['type'=>'keyword','copy_to'=>'properties_value'],
                            'search_value'=>['type'=>'keyword']
                        ]
                    ]
                ];
                break;
        }
        return $params;
    }
}

创建mapping要指定索引名称

Elasticsearch 的多字段匹配查询是不支持查询 Nested 对象的字段,如果不设置copy_to是查询不到数据的,所以这里加了copy_to参数,查询的时候可以通过copy_to参数值来查询数据

search_analyzer在搜索查询时,使用了自定义的ik_smart_synonym,可以同义词查询

执行命令

php artisan es:create_mapping orders

4、同步订单数据到Elasticsearch中

通过创建一个 Artisan 命令来实现,执行命令

php artisan make:command Elasticsearch/SyncOrders

SyncOrders.php文件内容

<?php
namespace App\Console\Commands\Elasticsearch;

use App\Models\Order;
use Illuminate\Console\Command;

class SyncOrders extends Command
{
    protected $signature = 'es:sync-orders';

    protected $description = '将订单数据同步到 Elasticsearch';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {
        // 获取 Elasticsearch 对象
        $es = app('es');

        Order::with(['goods'])
            // 使用 chunkById 避免一次性加载过多数据
            ->chunkById(100, function ($orders) use ($es) {
                $this->info(sprintf('正在同步 ID 范围为 %s 至 %s 的订单', $orders->first()->id, $orders->last()->id));
                // 初始化请求体
                $req = ['body' => []];
                // 遍历订单
                foreach ($orders as $order) {
                    // 将订单模型转为 Elasticsearch 所用的数组
                    $data = $order->toESArray();

                    $req['body'][] = [
                        'index' => [
                            '_index' => 'orders',
                            '_id'    => $data['id'],
                        ],
                    ];
                    $req['body'][] = $data;
                }
                try {
                    // 使用 bulk 方法批量创建
                    $es->bulk($req);
                } catch (\Exception $e) {
                    $this->error($e->getMessage());
                }
            });
        $this->info('同步完成');
    }
}

执行命令

php artisan es:sync-orders


讨厌 (0)
微博logo QQ空间logo QQlogo 豆瓣logo 人人logo 百度贴吧logo 有道云笔记logo

文章评论

表情表情
×
图片图片

评论列表