Yii ElasticSearch实战以及优化点

前面分享了Xunserch 和 ElasticSearch的安装,本来是要用Xunserch 的因为官网项目部需要太强大的插件,但是安装不给力,各种错误,最后用ElasticSearch。。。其实ElasticSearch并不太难,,, 不说了 直接上代码

先说下我的设计模式:

后台添加数据的同时王es里面插入索引, es6.0版本后一个索引只能插入一个type,所以es每个索引对应数据表, es存放前端要显示的字段即可,没必要全部字段都存在里面。 插入或者更新是调用一个公共方法。。。 搜索调用搜索接口

优化点 如果你的集群只有一个节点,这不要设置副本数,不然健康值会变成yellow,设置为0即可
在这里插入图片描述

阿里云的dts可以自动把mysql数据库的数据添加和更新索引到ES 但是需要付费。。。这个不做过多的说明

1.在 项目配置文件 web.php (高级模板main.php) 中的components中添加配置:

		//现使用 es
        'elasticsearch' => [
            'class' => 'yii\elasticsearch\Connection',
            //默认为true   如果单节点  设为false 不然会连接错误
            'autodetectCluster' => false,
            'nodes' => [
                ['http_address' => '127.0.0.1:9200'],
            ],
        ],

2.搜索接口

/**
     *  auth - rk
     *  获取全站搜索数据
     *  支持分词搜索和 多条件+多字段搜索
     */
 public function actionSearch(){

        if(Yii::$app->request->isPost){
            $searchData = Yii::$app->request->post('name','');
            $pageSize = Yii::$app->request->post('pageSize',5);
            $page = Yii::$app->request->post('page',1);
            $cate = Yii::$app->request->post('cate','');
            $offset = ($page-1)*$pageSize;
            $searchData =trim($searchData);
//            $searchData = str_replace(" ","",$searchData);
            if(empty($searchData)){
                $data['res_code']='200';
                $data['res_msg']='success';
                $data['res_data']=[];
                return $data;
            }
            //ElasticSearch
            $es = new ElasticSearch();
            //高亮数据
            $highlight = [
             #左标签,配合前端.highlight这个类来实现高亮
            "pre_tags"=>['<span class="highlight">'],
            "post_tags"=>['</span>'],
            #在原生api中写的是{}表示空对象,因此使用php的stdClass来表示空对象
            "fields"=>[
                "title"=>new \stdClass(),
                "subtitle"=>new \stdClass(),
                 ]
            ];

            $cat = ['product','cases','news','about_us'];
            if(!empty($cate)){
                if(in_array($cate,$cat)){
                    $cat = [$cate];
                }
            }
            $resArr = [];
            foreach ($cat as $val){
                $es::$index_db_name = $val;
                $es::$type_tb_name = $val;
                $where = ["is_delete"=>0,"status"=>1];
                if($val == 'about_us'){
                    $where = ["is_delete"=>0];
                }
                $must[] = [
                    "multi_match" => [//分词多字段搜索
                        'query' => $searchData,//['fuzzy'=>$searchData]
                        'fields' => ['title','subtitle'],//搜索的字段
                    ],
                ];

                $query = [
                    'bool'=>[
                        'must' => $must,
                        'should' => [
                            ['match'=> ['is_delete' => 0]]
                        ],
                        'minimum_should_match' => 1,
                    ]
                ];

                $sort = ['sort' => ['order' => 'desc']];
                //->query($query)->orderBy($sort)->asArray()->all()   'terms'=> $where

                $esQuery = $es::find()->query($query);//->offset($offset)->limit($pageSize)->orderBy($sort)->highlight($highlight)->asArray()->all()
                $count = $es::find()->query($query)->search();
                $res = $esQuery->offset($offset)->limit($pageSize)->orderBy($sort)->highlight($highlight)->asArray()->all();
                $resArr[$val]['count'] = $count['hits']['total']['value'] ??0;
                $resArr[$val]['pageSize'] = $pageSize;
                $resArr[$val]['data'] = $res??[];
            }
            //搜索数据存储到后台
            $searchModel  = new Search();
            //先判断是否存在搜索数据  存在更新次数
            $querySql = $searchModel::find()->where(['like','content',$searchData]);
            $count = $querySql->count();
            if($count !==0){
                $queryData = $querySql->asArray()->all();
                foreach ($queryData as $key => &$val){
                    $num = $val['num'] +=1;
                    $searchModel->updateAll(['num'=>$num],['id'=>$val['id']]);
                }
            }else{
                $searchModel->ip = Yii::$app->request->getUserIP();
                $searchModel->content  = $searchData;
                $searchModel->save();
            }

             //xunsearch
//            $db = \Yii::$app->xunsearch->getDatabase('mmc_uav',true);
//            $xs = $db->xs;
//            $search = $db->getSearch();
//            $index = $db->getIndex();
//            var_dump($search);die;
            $data['res_code']='200';
            $data['res_msg']='success';
            $data['host'] = Yii::$app->request->hostInfo;
            $data['res_data']=$resArr;
            return $data;
        }
        $data['res_code']='400';
        $data['res_msg']='请求方式错误';
        return $data;
    }

3.ElasticSearch模型

<?php
/**
 * Created by PhpStorm.
 * User: renkun
 * Date: 2020/4/9
 * Time: 10:09
 */

namespace app\models;


use yii\elasticsearch\ActiveRecord;

class ElasticSearch  extends ActiveRecord
{

    public static $index_db_name = '';
    public static $type_tb_name = '';
//    # 定义db链接
    public static function getDb()
    {
        return \Yii::$app->get('elasticsearch');
    }

    // 索引名相当于库名
    public static function index(){
        return self::$index_db_name;
    }

    // 类别名相当于表名
     public static function type(){
        return self::$type_tb_name;
     }

    # 属性
    public function attributes()
    {
        $mapConfig = self::mapConfig();
        return array_keys($mapConfig[self::$type_tb_name]);
    }
    # mapping配置
    public static function mapConfig(){
        return [
            'news' => [
                'id'  => ['type' => 'int'],
                'userId'  => ['type' => 'int'],
                'categoryId'  => ['type' => 'int'],
                'title'  => ['type' => 'string'],//默认分词
                'subtitle'  => ['type' => 'string'],
                'content'      => ['type' => 'string'],
                'recommend'  => ['type' => 'int'],
                'publishTime'  => ['type' => 'int'],
                'auth'  => ['type' => 'string'],
                'cover_img'  => ['type' => 'string'],
                'origin'  => ['type' => 'string'],
                'origin_url'  => ['type' => 'string'],
                'status'  => ['type' => 'int'],
                'sort'  => ['type' => 'int'],
                'is_delete'  => ['type' => 'int'],
            ],
            'about_us' => [
                'id'  => ['type' => 'int'],
                'content'      => ['type' => 'string'],
                'addtime'  => ['type' => 'int'],
                'title'  => ['type' => 'string'],//默认分词
                'description'  => ['type' => 'string'],
                'type'  => ['type' => 'int'],
                'sort'  => ['type' => 'int'],
                'is_delete'  => ['type' => 'int'],
            ],
            'cases' => [
                'id'  => ['type' => 'int'],
                'userId'  => ['type' => 'int'],
                'categoryId'  => ['type' => 'int'],
                'title'  => ['type' => 'string'],//默认分词
                'subtitle'  => ['type' => 'string'],
                'auth'  => ['type' => 'string'],
                'device'  => ['type' => 'string'],
                'content'      => ['type' => 'string'],
                'recommend'  => ['type' => 'int'],
                'status'  => ['type' => 'int'],
                'cover_img'  => ['type' => 'string'],
                'create_at'  => ['type' => 'int'],
                'sort'  => ['type' => 'int'],
                'is_delete'  => ['type' => 'int'],
            ],
            'product' => [
                'id' => ['type' => 'int'],
                'product_type_id'  => ['type' => 'int'],
                'title'  => ['type' => 'string'],//默认分词
                'description'  => ['type' => 'string'],
                'cover_img_url'  => ['type' => 'string'],
                'product_introduction'  => ['type' => 'string'],
                'extension'  => ['type' => 'string'],
                'images'  => ['type' => 'long'],
                'recommend'  => ['type' => 'string'],
                'addtime'  => ['type' => 'int'],
                'is_recommend'  => ['type' => 'int'],
                'user_id'      => ['type' => 'int'],
                'status'  => ['type' => 'int'],
                'sort'  => ['type' => 'int'],
                'is_delete'  => ['type' => 'int'],
            ]
        ];
    }

     // 映射
     public static function mapping(){
        $mapConfig = self::mapConfig();
        return [
            static::type() => $mapConfig[self::$type_tb_name]
        ];
    }
    // 更新映射
     public static function updateMapping(){
         $db = self::getDb();
         $command = $db->createCommand();
         if(!$command->indexExists(self::index())){
             $command->createIndex(self::index());
         }
         $res = $command->setMapping(self::index(), self::type(), self::mapping());
        return $res;
     }
     // 创建索引
     public static function createIndex(){
         $db = static::getDb();
         $command = $db->createCommand();
         if(!$command->indexExists(self::index())){
             $command->createIndex(static::index(), [
                 'settings' => [
                     'index' => [
                         // 指定新索引的时候不会立即生效,1s之后刷新生效  默认是1s
                         'refresh_interval'      => '1s',
                         // 索引分片个数  默认5片
                         'number_of_shards'      => 5,
                         // 每个分片副本个数  默认1个       单节点集群如果副本不设置为0   集群健康值会变成黄色  因为单点集群无法存放副本
                         'number_of_replicas'    => 0,
                     ]
                 ],
//             'mappings' => static::mapping(),
                 //'warmers' => [ /* ... */ ],
                 //'aliases' => [ /* ... */ ],
                 //'creation_date' => '...'
             ]);
         }
     }

    // 删除索引   (谨慎使用)
     public static function deleteIndex(){
         $db = static::getDb();
         $command = $db->createCommand();
         $res = $command->deleteIndex(static::index(), static::type());
         return $res;
     }


    //创建es索引 并赋值
    public static function es($index,$data=[],$action = 0){   //0 添加  1 创建
        $es = new self();
        $es::$index_db_name = $index;
        $es::$type_tb_name = $index;
        $attr = $es::mapping();

        $indexKey = array_keys($attr[$index]);
//        var_dump($data);die;
        $tmpData = $data;
        //只获取主要字段
        if(!empty($data)){
            if($action == 1){
                $es = $es::findOne($data['id']); //更新
                if(empty($es)){
                    self::es($index,$tmpData,0);
                }
            }else{
                $es::createIndex();
                $es->primaryKey = $data['id'];
            }
            foreach ($data as $key => $val){
//                var_dump($indexKey);
//                var_dump($data);die;
                if(in_array($key,$indexKey)){
                    $es->$key = $val;
                }
            }
            if ($es->save() == false) {
                die("es数据出现错误,请联系管理员");
            }

        }
    }

}

  1. 手动添加索引和更新
		 if( $model->save()){
	              //同步到es
	              ElasticSearch::es('product',$model->attributes);
	              return $this->redirect(['view', 'id' => $model->id]);
	      }

//最终效果
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值