yii2 composer安装Es和yii2的Elasticsearch操作类

1.在yii2的项目目录中的composer.json的require中加入:

"elasticsearch/elasticsearch": "~6.0" 

image.png

2.然后执行composer update

3.config/params.php中添加

'elasticsearch' => [
    '192.168.163.128:9200'
],
image.png

4.新建一个EsService.php

<?php
namespace frontend\service;

use yii;
use Elasticsearch\ClientBuilder;
class EsService
{

    public  $index;
    public  $type;
    public  $client;
    public   function __construct($index, $type){
        $this->index = $index;
        $this->type = $type;
        $hosts = yii::$app->params['elasticsearch'];
        $this->client = ClientBuilder::create()->setHosts($hosts)->build();
    }

    /**
     * 创建索引
     */
    public function createIndex(){
        $params = [
            'index' => $this->index,
            'body' => [
                'settings' => [
                    'number_of_shards' => 2,    //分片数
                    'number_of_replicas' => 0   //副本数
                ]
            ]
        ];

        $response = $this->client->indices()->create($params);
        return $response;
    }

    /**
     * 删除索引
     */
    public function deleteIndex(){
        $params = ['index' => $this->index];
        $response = $this->client->indices()->delete($params);
        return $response;

    }

    /**
     * 添加文档
     */
    public function createDocument($id, $data){
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'id' => $id,
            'body' => $data
        ];

        $response = $this->client->index($params);
        return $response;
    }

    /**
     * 批量添加文档
     */
    public function batchCreateDoc($data){
        foreach ($data as  $value){
            $params = [
                'index' => $this->index,
                'type' => $this->type,
                'body' => $value
            ];
            $responses = $this->client->index($params);
        }

        return $responses;

    }

    /**
     * 查询文档
     */
    public function getDocument($id){
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'id' => $id,
            'client' => [ 'ignore' => [400, 404] ],
        ];

        $response = $this->client->get($params);
        return $response;
    }

    /**
     * 搜索文档
     */
    public function searchDocument($param){

        $tmp = [];
        foreach ($param as $key => $value) {
            $tmp[$key] = [
                "query"=> $value,
                "minimum_should_match"=> "50%",
            ];
        }

        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'body' => [
                'query' => [
                    'match' =>  $tmp
                ]
            ]
        ];

        $response = $this->client->search($params);
        return $response;
    }

    /**
     * @param $param
     * @desc 关键词搜索文档
     */
    public function keywordSearch($keyword){
        $params = [
            'index' => $this->index,
            'type' => $this->type,
            'body' => [
                'query' => [
                    'multi_match' =>  [
                        'query'=>$keyword,
                    ],
                ]
            ]
        ];
        $response = $this->client->search($params);
        return $response;
    }
}

//在控制器里面操作
<?php
namespace frontend\controllers;

use yii\web\Controller;
use frontend\service\EsService;

/**
 * Es controller
 */
class EsController extends Controller
{
    /**
     * Displays homepage.
     *
     * @return mixed
     */
    public function actionIndex(){

        $EsService = new EsService('mall', 'product');
        $result = $EsService->createIndex();
        $data = [
            [
                'name' => 'mongodb',
                'nike_name' => 'NoSql',
                'age' => '10',
                'about' => 'this is mongodb and NoSql',
                'interests' => 'sports music 量子专家',
            ],
            [
                'name' => 'MySql',
                'nike_name' => 'Sql',
                'age' => '22',
                'about' => 'this is MySql and Sql',
                'interests' => '作者是茂名量子专家',
            ],
            [
                'name' => '弗南永州锤子帮',
                'nike_name' => '强小妮',
                'age' => '32',
                'about' => 'this is MySql and Sql',
                'interests' => '强小妮是锤子帮大哥',
            ],
            [
                'name' => '弗北热干面',
                'nike_name' => '热干面',
                'age' => '32',
                'about' => 'this is MySql and Sql',
                'interests' => '包子加热干面法力无边',
            ],
        ];

        //$result = $EsService->createDocument('', $ins);
        //$result = $EsService->batchCreateDoc($data);
        //$result = $EsService->keywordSearch('包');

        echo "<pre>";
        print_r($result);
        echo "</pre>";
        exit;
        //return $this->render('index');
    }

}

5.yii2还提供了一个操作Es的类 yii2-elasticsearch
首先引入 yii2-elasticsearch 操作类
composer.json的require中添加:

"yiisoft/yii2-elasticsearch": "~2.0.0"
image.png

然后执行:composer update
config/web.php的components中添加:

'components' => [
     ...
        'elasticsearch' => [
            'class' => 'yii\elasticsearch\Connection',
            'nodes' => [
                ['http_address' => '127.0.0.1:9200']
            ],
            'autodetectCluster' => false
        ],
    ],

6.参考某个大佬写了一个公共的类 common\Elasticsearch.php

<?php

namespace app\common;

use yii;
use yii\elasticsearch\ActiveRecord;
use yii\data\Pagination;


class Elasticsearch extends ActiveRecord{

    /**
     * 使用的数据库连接
     */
    public static function getDb(){
        return \Yii::$app->get('elasticsearch');
    }

    /**
     * [mapConfig mapping配置]
     * 返回这个模型的映射
     *
     * properties配置说明
     *
     * 属性
     * 数据类型 string(已废弃) byte short integer long float double boolean date binary(二进制) ip(以字符换格式存IPv4地址) token_count(存储索引的字数信息)
     *
     * 公共属性
     * index            -> analyzed(被分析,编入索引,产生的token能被搜索到) not_analyzed(不被分析,使用原始值编入索引,在索引中作为单个词) no(不编入索引,无法搜索该字段)
     * store            -> 指定是否将字段的原始值写入索引,默认值是no,字段值被分析,能够被搜索,但是,字段值不会存储,这意味着,该字段能够被查询,但是不会存储字段的原始值  通常情况字段值已经是_source字段的一部分,可以只检索需要的
     * boost            -> 字段级别的助推,默认值是1,定义了字段在文档中的重要性/权重
     * include_in_all   -> 该属性指定当前字段是否包括在_all字段中,默认值是true
     * copy_to          -> 该属性指定一个字段名称,ElasticSearch引擎将当前字段的值复制到该属性指定的字段中
     * doc_values       -> 文档值是存储在硬盘上的索引时(indexing time)数据结构,对于not_analyzed字段,默认值是true,analyzed string字段不支持文档值;如果您确定不需要对字段进行排序或聚合,或者从脚本访问字段值,则可以禁用doc值以节省磁盘空间
     * fielddata        -> 字段数据是存储在内存中的查询时(querying time)数据结构,只支持analyzed string字段
     * null_value       -> 该属性指定一个值,当字段的值为NULL时,该字段使用null_value代替NULL值;在ElasticSearch中,NULL 值不能被索引和搜索,当一个字段设置为NULL值,ElasticSearch引擎认为该字段没有任何值,使用该属性为NULL字段设置一个指定的值,使该字段能够被索引和搜索。
     *
     * 常用其他属性
     * analyzer         -> 该属性定义用于建立索引和搜索的分析器名称,默认值是全局定义的分析器名称,该属性可以引用在配置结点(settings)中自定义的分析器
     * search_analyzer  -> 该属性定义的分析器,用于处理发送到特定字段的查询字符串
     * ignore_above     -> 该属性指定一个整数值,当字符串字段(analyzed string field)的字节数量大于该数值之后,超过长度的部分字符数据将不能被analyzer处理,不能被编入索引;对于 not analyzed string字段,超过长度的部分字符将被忽略,不会被编入索引。默认值是0,禁用该属性;
     * position_increment_gap   -> 该属性指定在相同词的位置上增加的gap,默认值是100;
     * index_options    -> 索引选项控制添加到倒排索引(Inverted Index)的信息
     * [
     *      docs        -> 只索引文档编号(Doc Number)
     *      freqs       -> 索引文档编号和词频率(term frequency)
     *      positions   -> 索引文档编号,词频率和词位置(序号)
     *      offsets     -> 索引文档编号,词频率,词偏移量(开始和结束位置)和词位置(序号)
     *      默认情况下,被分析的字符串(analyzed string)字段使用positions,其他字段使用docs
     * ]
     *
     * 数值类型的其他属性
     * precision_step   -> 该属性指定为数值字段每个值生成的term数量,值越低,产生的term数量越高,范围查询越快,索引越大,默认值是4
     * ignore_malformed -> 忽略格式错误的数值,默认值是false,不忽略错误格式,对整个文档不处理,并且抛出异常
     * coerce           -> 默认值是true,尝试将字符串转换为数值,如果字段类型是整数,那么将小数取整
     *
     * 日期类型的其他属性
     * format           -> 指定日期的格式,例如:“yyyy-MM-dd hh:mm:ss”
     * ignore_malformed -> 忽略错误格式,默认值是false,不忽略错误格式
     *
     * fields           -> 在fields属性中定义一个或多个字段,该字段的值和当前字段值相同,可以设置一个字段用于搜索,一个字段用于排序等
     *      "properties":
     *      {
     *          "id":{
     *              "type":"long",
     *              "fields":{
     *                  "id2":{"type":"long","index":"not_analyzed"}
     *              }
     *          }
     *      }
     * _all             -> 表示存储其他字段的数据以便搜索,默认情况下,_all字段是启用的,包含了索引中所有字段的数据,然而这一字段使索引变大,如果不需要,请禁用该字段,或排除某些字段
     * "_all":{"enabled":false}
     * _source          -> 表示在生成索引的过程中,存储发送到ElasticSearch的原始JSON文档,默认情况下,该字段会被启用,因为索引的局部更新功能依赖该字段。
     * _routing         -> 路由字段 公式:shard_num = hash(_routing) % num_primary_shards  使用的默认字段是_id,设置required为true,表示路由字段在进行索引的CRUD操作时必需显式赋值。
     *
     * 不可配置的元字段
     * _index           -> 返回文档所属的索引
     * _uid             -> 返回文档的type和id
     * _type            -> 返回文档类型(type)
     * _id              -> 返回文档的ID;
     * _size            -> 返回文档的_source字段中函数的字节数量;
     * _field_names     -> 返回文档中不包含null值的字段名称;
     *
     */
    public static function mapConfig(){
        return [
            // 根据type来获取model->attributes
            'member' => [
                'properties' => [
                    'user_id'    => ['type' => 'integer'],
                    'user_name'     => ['type' => 'text'],
                    'email'         => ['type' => 'keyword'],
                    'qq'            => ['type' => 'keyword'],
                    'edit_time'     => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss||yyyy-MM-dd']
                ]
            ],
            // 根据type来获取model->attributes
            'member2' => [
                'properties' => [
                     'user_id'      => ['type' => 'integer'],
                     'user_name'        => ['type' => 'text'],                'edit_time'        => ['type' => 'date', 'format' => 'yyyy-MM-dd HH:mm:ss||yyyy-MM-dd']
                ]
            ]
        ];
    }

    /**
     * 获取群集中所有索引映射
     */
    public static function getMapping(){
        $db = self::getDb();
        $command = $db->createCommand();
        return $command->getMapping();
    }

    /**
     * 根据索引主键获取相关信息
     * 支持单个或多个
     */
    public function getByKey($id){
        if(is_array($id)){
            $res = self::mget($id);
        }else{
            $res = self::get($id);
        }
        return $res;
    }

    /**
     * 单个
     * 默认返回object对象 返回数组 添加->asArray()
     */
    public function getOne($query = []){
        $es_query = self::find();

        // 匹配查询
        if($query && !empty($query)){
            $es_query->query($query);
        }
        // 分组
        $res = $es_query->one();

        return $res;
    }

    /**
     * 列表
     * 默认返回object对象 返回数组 添加->asArray()
     * search 与 all 区别在于 all是在search基础上处理再拿出结果
     */
    public function getList($query = [], $order = [], $offset = 0, $limit = 20){
        $es_query = self::find();

        // 匹配查询
        if($query && !empty($query)){
            $es_query->query($query);
        }
        // 排序
        if($order && !empty($order)){
            $es_query->orderby($order);
        }
        // 分组
        $res = $es_query->offset($offset)->limit($limit)->asArray()->all();
        $list = array_column($res, '_source');

        return $list;
    }

    /**
     * 分页列表
     * 默认返回object对象 返回数组 添加->asArray()
     * search 与 all 区别在于 all是在search基础上处理再拿出结果
     */
    public function getPageList($query = [], $order = []){
        $es_query = self::find();

        // 匹配查询
        if($query && !empty($query)){
            $es_query->query($query);
        }
        // 排序
        if($order && !empty($order)){
            $es_query->orderby($order);
        }

        // 分组
        $count = $es_query->search();
        // 分页
        $pages = new Pagination(['totalCount' => $count['hits']['total']]);
        // 分组
        $res = $es_query->offset($pages->offset)->limit($pages->limit)->asArray()->all();
        $list = array_column($res, '_source');

        return ['list' => $list, 'pages' => $pages];
    }

    /**
     * 列表
     * 默认返回object对象 返回数组 添加->asArray()
     * search 与 all 区别在于 all是在search基础上处理再拿出结果
     */
    public function getFilterList($filter_arr = [], $query = [], $order = [], $offset = 0, $limit = 20){
        $es_query = self::find();

        // 过滤器
        if($filter_arr && !empty($filter_arr)){
            $es_query->postFilter($filter_arr);
        }
        // 匹配查询
        if($query && !empty($query)){
            $es_query->query($query);
        }
        // 排序
        if($order && !empty($order)){
            $es_query->orderby($order);
        }
        // 分组
        $res = $es_query->offset($offset)->limit($limit)->all();

        return $res;
    }

    /**
     * 获取高亮列表
     * 默认返回object对象 返回数组 添加->asArray()
     * search 与 all 区别在于 all是在search基础上处理再拿出结果
     * 循环使用$v->highlight获取高亮列表
     */
    public function getHighLightList($highlight_arr = [], $query = [], $offset = 0, $limit = 20){
        $es_query = self::find();

        // 高亮
        if($highlight_arr && !empty($highlight_arr)){
            $es_query->highlight($highlight_arr);
        }
        // 匹配查询
        if($query && !empty($query)){
            $es_query->query($query);
        }
        // 分组
        $res = $es_query->offset($offset)->limit($limit)->all();

        return $res;
    }

    /**
     * 获取聚合列表
     * 默认返回object对象 返回数组 添加->asArray()
     * search 与 all 区别在于 all是在search基础上处理再拿出结果
     */
    public function getAggList($aggregate_name, $addAggregate_arr = [], $query = [], $offset = 0, $limit = 20){
        $es_query = self::find();

        // 聚合
        if($addAggregate_arr && !empty($addAggregate_arr)){
            $es_query->addAggregate($aggregate_name, $addAggregate_arr);
        }
        // 匹配查询
        if($query && !empty($query)){
            $es_query->query($query);
        }
        // 分组
        $res = $es_query->offset($offset)->limit($limit)->search();

        return ['list' => $res['hits']['hits'], $aggregate_name => $res['aggregations'][$aggregate_name]];
    }
}

7.新建一个model model/EsModel

<?php

namespace app\models;

use app\common\Elasticsearch;

class EsModel extends Elasticsearch{

    // _index _type _id 定义
    // https://www.elastic.co/guide/cn/elasticsearch/guide/current/_Document_Metadata.html
    public static $index_db_name = '';
    public static $type_tb_name = '';

    // 索引名相当于库名
    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]['properties']);
    }

    // 映射
    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();
        $command->createIndex(static::index(), [
            'settings' => [
                'index' => [
                    // 指定新索引的时候不会立即生效,1s之后刷新生效  默认是1s
                    'refresh_interval'      => '1s',
                    // 索引分片个数  默认5片
                    'number_of_shards'      => 5,
                    // 每个分片副本个数  默认1个
                    'number_of_replicas'    => 1
                ]
            ],
            '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;
    }
}

8.controller调用

$model = new \app\models\EsModel();
$model::$index_db_name = 'index_name';
$model::$type_tb_name = 'type_name';
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容