elasticsearch服务类封装

发布时间 2023-03-27 10:53:12作者: 潘潘潘的博客
<?php
namespace app\service;
use Elasticsearch\ClientBuilder;
use app\service\Service;
class ElasticsearchService extends Service
{
    private $client;
    private $index_name;
    private $type;
    // 构造函数
    public function __construct()
    {
        $elasticsearch_hosts = [];
        $this->client = ClientBuilder::create()->setHosts($elasticsearch_hosts)->build();
        $this->index_name = 'shuiguo'; // 索引名(项目名)
        $this->type = '_doc'; // 类型
    }

    public static function build() {
        return new self();
    }

    /**
     * 删除索引
     *
     * @param string $keyName  索引名
     * @return void
     */
    public function deleteIndex(string $keyName)
    {
        $params = ['index' => $keyName];
        return $this->client->indices()->delete($params);
    }

    /**
     * 判断文档存在
     * @param string $keyName  索引名
     * @param string $id        索引id
     * @return bool
     */
    public function existsDoc(string $keyName, string $id) 
    {
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'type'  => $this->type,
            'id'    => $id
        ];
        return $this->client->exists($params);
    }

    /**
     * 添加文档(单条)
     * @param string $keyName  索引名
     * @param string $id        索引id
     * @param array $doc        跟创建文档结构时properties(es文档模板)的字段一致
     * @return array|callable
     */
    public function addDoc(string $keyName, string $id, array $doc) 
    {
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'type'  => $this->type,
            'id'    => $id,
            'body'  => $doc
        ];
        return $this->client->index($params);
    }

    /**
     * 添加文档(批量),如果id已存在则为更新
     * @param string $keyName  索引名
     * @param string $id        索引id
     * @param array $list       跟创建文档结构时properties(es文档模板)的字段一致
     * @return array|callable
     */
    public function addDocAll(string $keyName, array $list) 
    {
        $index_name = $this->index_name .'_'. $keyName;
        $docs = [];
        foreach ($list as $key => $value) {
            $docs['body'][] = ['index'=>['_index'=>$index_name, '_id'=>$value['id']]];
            $docs['body'][] = $value;
        }
        return $response = $this->client->bulk($docs);
    }

    /**
     * 删除文档
     * @param string $keyName  索引名
     * @param string $id        文档id
     * @return array|callable
     */
    public function deleteDoc(string $keyName, string $id) 
    {
        // 文档是否存在
        $res = $this->existsDoc($keyName, $id);
        if (!$res) {
            throw new \think\Exception('文档不存在');
        }
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'type'  => $this->type,
            'id'    => $id
        ];
        return $this->client->delete($params);
    }

    /**
     * 更新文档(字段内容)
     * @param string $keyName  索引名
     * @param string $id        文档id
     * @param string $key       更新的字段
     * @param string $value     更新的内容
     * @return array|callable
     */
    public function updateDoc(string $keyName, string $id, string $key, string $value)
    {
        // 文档是否存在
        $res = $this->existsDoc($keyName, $id);
        if (!$res) {
            throw new \think\Exception('文档不存在');
        }

        // 可以灵活添加新字段,最好不要乱添加
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'type'  => $this->type,
            'id'    => $id,
            'body'  => [
                'doc' => [
                    $key => $value
                ]
            ]
        ];
        return $this->client->update($params);
    }

    /** 
     * 更新文档(数组)
     * @param string $keyName  索引名
     * @param string $id        文档id
     * @param array $doc       更新的字段
     * @return array|callable
     */
    public function updateDocArray(string $keyName, string $id, array $doc)
    {
        // 文档是否存在
        $res = $this->existsDoc($keyName, $id);
        if (!$res) {
            throw new \think\Exception('文档不存在');
        }

        // 可以灵活添加新字段,最好不要乱添加
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'type'  => $this->type,
            'id'    => $id,
            'body'  => ['doc'=>$doc]
        ];
        return $this->client->update($params);
    }


    /**
     * 获取文档
     * @param string $keyName  索引名
     * @param string $id        文档id
     * @return array
     */
    public function getDoc(string $keyName, string $id){
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'type'  => $this->type,
            'id'    => $id
        ];
        $response = $this->client->get($params);
        return $response['_source'];
    }




    /**
     * es单字段模糊匹配 
        $sort  3维数组  例:'sort' => [
            ['time' => ['order' => 'desc']],
            ['popularity' => ['order' => 'desc']]
        ]
     * @param string $keyName    索引名
     * @param string $fieldName  字段名
     * @param string $search      关键词
     * @param int $from           起始位置
     * @param int $size           文档数量
     * @param array $sort         排序
     * @return void
     */
    function esSingleFieldSearch($keyName, $fieldName, $search, $from=0, $size=0, $sort=[])
    {
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'body'  => [
                'query' => [
                    'match' => [
                        $fieldName => $search
                    ]
                ]
            ]
        ];
        if($size != 0){
            $params['body']['from'] = $from;
            $params['body']['size'] = $size;
        }
        if(!empty($sort)){
            $params['body']['sort'] = $sort;
        }
        $res = $this->client->search($params);
        $res = array_column($res['hits']['hits'], '_source');
        return $res;
    }



    /**
     * es多字段模糊匹配同一数据
     *  param $fieldName     1维数组
        param $includeFields 1维数组
        param $sort           3维数组  例: 
            [
                ['time' => ['order' => 'desc']],
                ['popularity' => ['order' => 'desc']]
            ]
     * @param string $keyName       索引名
     * @param array $fieldName      字段名(多字段)
     * @param string $search         关键词
     * @param int $from              起始位置
     * @param int $size              文档数量
     * @param array $sort            排序
     * @param array $includeFields  返回的字段
     * @return void
     */
    function esMultiFieldSearch($keyName, $fieldName=[], $search, $from=0, $size=0, $sort=[], $includeFields=[])
    {
        $params = [
            'index' => $this->index_name .'_'. $keyName,
            'body'  => [
                    "query"=>[
                        "multi_match"=> [
                            "query" => $search,
                            "fields" => $fieldName
                        ]
                    ]
            ]
        ];
        if($size!=0){
            $params['body']['from'] = $from;
            $params['body']['size'] = $size;
        }
        if(!empty($sort)){
            $params['body']['sort'] = $sort;
        }
        if(!empty($includeFields)){
            $params['body']["_source"] = $includeFields;
        }

        $res    = $this->client->search($params);
        $res = array_column($res['hits']['hits'], '_source');
        return $res;
    }

}