为什么要用?
由于mysql自带的like并不是很优秀,而且有可能要根据一定的”分词” 去匹配,所以才需要使用 elastic search。
安装扩展
composer require --prefer-dist yiisoft/yii2-elasticsearch -vvv
配置
<?php// ......'components' => ['elasticsearch' => ['class' => 'yii\elasticsearch\Connection','nodes' => [['http_address' => '127.0.0.1:9200']// configure more hosts if you have a cluster],// set autodetectCluster to false if you don't want to auto detect nodes// 'autodetectCluster' => false,'dslVersion' => 7 // default is 5],]
模拟场景
现在有一个文章表,需要做一个搜索功能,搜索的内容可能包含在博客标题和博客内容中。
博客sql
CREATE TABLE `post` (`id` int(11) NOT NULL AUTO_INCREMENT,`title` varchar(100) NOT NULL COMMENT '文章标题',`content` text COMMENT '文章内容',`view_num` int(11) NOT NULL COMMENT '预览数',`thumb` varchar(255) NOT NULL COMMENT '缩略图',`add_time` int(11) NOT NULL COMMENT '添加时间',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
文章model
此 model 管理 数据库中的数据
在文章增删改查的时候对应操作elastic search的增删改查,可以使得mysql数据实时同步给elastic search,未全字段都交给 elastic search 管理,所以 es model 仅定义部分内容。
<?phpnamespace app\models;use yii\behaviors\TimestampBehavior;/*** This is the model class for table "{{%post}}".** @property int $id* @property string $title 文章标题* @property string $content 文章内容* @property int $view_num 预览数* @property string $thumb 缩略图* @property int $add_time 添加时间*/class Post extends \yii\db\ActiveRecord{public function behaviors (){return [['class' => TimestampBehavior::class,'createdAtAttribute' => 'add_time','updatedAtAttribute' => false]];}// 添加或者修改索引public function afterSave ($insert, $changedAttributes){// 需要加入索引的内容// 新增数据if($insert){// 将新增数据写入到 elastic search$esPost = new EsPost();$esPost->_id = $this->id;$esPost->title = $this->title;$esPost->content = $this->content;$esPost->insert();}else{// 更新数据$changeFields = array_keys($changedAttributes);$fields = ['title','content','add_time'];// 是否修改了es需要的字段内容$interFields = array_intersect($changeFields, $fields);if(! empty($interFields)){$esPost = EsPost::findOne($this->id);if(! empty($esPost)){$attrs = [];foreach($interFields as $field){// 此方法修改最佳,比之 ->setAttributes 或者 ->attributes$esPost->{$field} = $this->{$field};}$esPost->update(false);}}}}// 删除数据public function afterDelete (){$esPost = EsPost::findOne($this->id);if(! empty($esPost)){$esPost->delete();}}/*** @inheritdoc*/public static function tableName (){return '{{%post}}';}/*** @inheritdoc*/public function rules (){return [[['title','content','thumb'],'required'],[['content'],'string'],[['title'],'string','max' => 100],[['thumb'],'string','max' => 255]];}/*** @inheritdoc*/public function attributeLabels (){return ['title' => '文章标题','content' => '文章内容','thumb' => '缩略图'];}}
es的对应model
此model管理elastic search的内容
<?phpnamespace app\models;use yii\elasticsearch\ActiveRecord;/*** elastic search 文章** @author vogin* @property string title* @property string content* @property integer add_time*/class EsPost extends ActiveRecord{public static function index (){// 名字不能以 _或者 - 或者 + 开始return 'e_post';}public function attributes (){return ['title','content','add_time'];}public static function mapping (){return [// Field types: https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html#field-datatypes'properties' => ['title' => ['type' => 'text'],// text类型在存储数据的时候会默认进行分词,并生成索引。而keyword存储数据的时候,不会分词建立索引,显然,这样划分数据更加节省内存。'content' => ['type' => 'text'],'add_time' => ['type' => 'integer']]];}/*** Set (update) mappings for this model*/public static function updateMapping (){$db = static::getDb();$command = $db->createCommand();$command->setMapping(static::index(), static::type(), static::mapping());}/*** Create this model's index*/public static function createIndex (){$db = static::getDb();$command = $db->createCommand();$command->createIndex(static::index(), [// 'aliases' => [ /* ... */ ],'mappings' => static::mapping()// 'settings' => [ /* ... */ ],]);}/*** Delete this model's index*/public static function deleteIndex (){$db = static::getDb();$command = $db->createCommand();$command->deleteIndex(static::index(), static::type());}public static function title ($title){return ['match' => ['title' => $title]];}public static function content ($content){return ['match' => ['content' => $content]];}}
基本使用
<?phpclass PostController extends Controller{public function actionAdd(){// 增加数据,会触发 Post 中 afterSave钩子函数,进行数据增加$post = new Post();$post->title = '今天天气挺好的';$post->content = '今天看到日出东方,天朗气清,捕捉一屋晨风,看来是个赶海的日子';$post->thumb = 'http://www.aaa.com/a.jpg';$post->insert();// 修改数据,会触发 Post 中 afterSave钩子函数,进行数据修改$post = Post::findOne(5);$post->title = '修改了标题5';$post->update(false);// 删除数据,会触发 Post 中 afterDelete 钩子函数,进行数据删除$post = Post::findOne(5);$post->delete();// 查找es数据EsPost::findOne(6);// 分页$query = EsPost::find();$provider = new \yii\elasticsearch\ActiveDataProvider(['query' => $query,'pagination' => ['pageSize' => 10]]);$models = $provider->getModels();var_dump($models);// 类mysql like %%$posts = EsPost::find()->query([// match相当于like查询'match' => ['title' => '今天天气挺好']])->all();// 类似mysql =// 【注】:精准查找中,term => 内容是中文可能不好使$posts = EsPost::find()->query(['term' => 'zhangsan'])->all();}}
