当前位置: 首页 > article >正文

Client 操作索引库和文档(PHP版)

一、安装 PHP Client

官方文档:https://www.elastic.co/guide/en/elasticsearch/client/php-api/7.17/connecting.html

二、创建 hotel 表,并导入数据

CREATE TABLE `hotel` (
  `id` bigint(20) NOT NULL COMMENT '酒店id',
  `name` varchar(255) NOT NULL COMMENT '酒店名称',
  `address` varchar(255) NOT NULL COMMENT '酒店地址',
  `price` int(10) NOT NULL COMMENT '酒店价格',
  `score` int(2) NOT NULL COMMENT '酒店评分',
  `brand` varchar(32) NOT NULL COMMENT '酒店品牌',
  `city` varchar(32) NOT NULL COMMENT '所在城市',
  `star_name` varchar(16) DEFAULT NULL COMMENT '酒店星级,1星到5星,1钻到5钻',
  `business` varchar(255) DEFAULT NULL COMMENT '商圈',
  `latitude` varchar(32) NOT NULL COMMENT '纬度',
  `longitude` varchar(32) NOT NULL COMMENT '经度',
  `pic` varchar(255) DEFAULT NULL COMMENT '酒店图片',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;

三、分析数据结构

mapping 映射要考虑的信息包括:

  • 字段名
  • 数据类型
  • 是否参与搜索
  • 是否分词,如果分词,分词器选择什么?

说明:

  • 字段名、字段数据类型,可以参考数据表结构的名称和类型
  • 是否参与搜索要根据业务来判断,例如:图片地址就无需参与搜索
  • 是否分词看文本内容,内容如果是一个整体就无需分词,反之则要分词
  • 分词器的选择由分词粒度决定

四、使用 Kibana 工具,创建索引库

PUT /hote
{
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_max_word",
        "copy_to": "all"
      },
      "address":{
        "type": "keyword",
        "index": false
      },
      "price":{
        "type": "integer"
      },
      "score":{
        "type": "integer"
      },
      "brand":{
        "type": "keyword",
        "copy_to": "all"
      },
      "city":{
        "type": "keyword",
        "copy_to": "all"
      },
      "starName":{
        "type": "keyword"
      },
      "business":{
        "type": "keyword"
      },
      "location":{
        "type": "geo_point"
      },
      "pic":{
        "type": "keyword",
        "index": false
      },
      "all":{
        "type": "text",
        "analyzer": "ik_max_word"
      }
    }
  }
}

说明:

  • location:地理坐标,里面包含精度、纬度,定义成 geo_point 类型
  • all:一个组合字段,数据库不存在该字段,其目的是将多字段的值,利用 copy_to 合并,提供给用户搜索

在这里插入图片描述
在这里插入图片描述

五、基于 PHP Client 操作 ES

5.1 初始化客户端

<?php

use Elasticsearch\ClientBuilder;

class Index 
{
    private $client;

    public function __construct(App $app)
    {
        $this->initClient();
    }

    private function initClient()
    {
        if (!$this->client) {
            $host = sprintf('http://%s:%s@%s:%s', env('es.username'), env('es.password'), env('es.host'), env('es.port'));

            $hosts = [
                $host
            ];

            $this->client = ClientBuilder::create()->setHosts($hosts)->build();
        }

        return $this->client;
    }
}

5.2 创建索引库

public function createIndex()
{
    $result = $this->client->indices()->create([
        'index' => 'hotel',
        'body' => [
            'mappings' => [
                'properties' => [
                    'id' => [
                        'type' => 'keyword',
                    ],
                    'name' => [
                        'type' => 'text',
                        'analyzer' => 'ik_max_word',
                        'copy_to' => 'all'
                    ],
                    'address' => [
                        'type' => 'keyword',
                        'index' => 'false'
                    ],
                    'price' => [
                        'type' => 'integer'
                    ],
                    'score' => [
                        'type' => 'integer'
                    ],
                    'brand' => [
                        'type' => 'keyword',
                        'copy_to' => 'all'
                    ],
                    'city' => [
                        'type' => 'keyword',
                        'copy_to' => 'all'
                    ],
                    'starName' => [
                        'type' => 'keyword',
                    ],
                    'business' => [
                        'type' => 'keyword',
                    ],
                    'location' => [
                        'type' => 'geo_point',
                    ],
                    'pic' => [
                        'type' => 'keyword',
                        'index' => 'false'
                    ],
                    'all' => [
                        'type' => 'text',
                        'analyzer' => 'ik_max_word',
                    ]
                ]
            ]
        ]
    ]);

    return json($result); 
}
# 响应结果:{"acknowledged":true,"shards_acknowledged":true,"index":"hotel"}

5.3 获取索引库

public function getIndex()
{
    $result = $this->client->indices()->get(['index' => 'hotel']);

    return json($result);
}

# 响应结果:
{"hotel":{"aliases":[],"mappings":{"properties":{"address":{"type":"keyword","index":false},"all":{"type":"text","analyzer":"ik_max_word"},"brand":{"type":"keyword","copy_to":["all"]},"business":{"type":"keyword"},"city":{"type":"keyword","copy_to":["all"]},"id":{"type":"keyword"},"location":{"type":"geo_point"},"name":{"type":"text","copy_to":["all"],"analyzer":"ik_max_word"},"pic":{"type":"keyword","index":false},"price":{"type":"integer"},"score":{"type":"integer"},"starName":{"type":"keyword"}}},"settings":{"index":{"routing":{"allocation":{"include":{"_tier_preference":"data_content"}}},"number_of_shards":"1","provided_name":"hotel","creation_date":"1732073635610","number_of_replicas":"1","uuid":"HBkKJctjTQaqoBpmuMQbUg","version":{"created":"8518000"}}}}}

5.3 删除索引库

public function deleteIndex()
{
     $result = $this->client->indices()->delete(['index' => 'hotel']);

     return json($result);
 }

# 响应结果:
{"acknowledged":true}

5.4 新增文档

新增酒店数据:添加单条记录

public function addDoc()
{
   $log = Hotel::find(36934);

   $result = $this->client->index([
       'index' => 'hotel',
       'id' => $log->id,
       'body' => [
           'id' => $log->id,
           'name' => $log->name,
           'address' => $log->address,
           'price' => $log->price,
           'score' => $log->score,
           'brand' => $log->brand,
           'city' => $log->city,
           'starName' => $log->star_name,
           'business' => $log->business,
           'location' => $log->latitude . ',' . $log->longitude, // 纬度,经度
           'pic' => $log->pic,
       ]
   ]);

   return json($result);
}

# 响应结果:
{"_index":"hotel","_id":"36934","_version":3,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":2,"_primary_term":1}

5.5 查询文档

根据ID查询文档:

public function getDocById()
{
    $id = 36934;

    $result = $this->client->get(['index' => 'hotel', 'id' => $id]);

    return json($result);
}

# 响应结果:
{"_index":"hotel","_id":"36934","_version":3,"_seq_no":2,"_primary_term":1,"found":true,"_source":{"id":36934,"name":"7天连锁酒店(上海宝山路地铁站店)","address":"静安交通路40号","price":336,"score":37,"brand":"7天酒店","city":"上海","starName":"二钻","business":"四川北路商业区","location":"31.251433,121.47522","pic":"https:\/\/m.tuniucdn.com\/fb2\/t1\/G1\/M00\/3E\/40\/Cii9EVkyLrKIXo1vAAHgrxo_pUcAALcKQLD688AAeDH564_w200_h200_c1_t0.jpg"}}

5.6 修改文档

增量修改:

public function updateDocById()
{
    $id = 36934;

    $result = $this->client->update([
        'index' => 'hotel',
        'id' => $id,
        'body' => [
            // 需更新的字段
            'doc' => [
                'address' => '静安交通路41号'
            ]
        ]
    ]);

    return json($result);
}

# 响应结果:
{"_index":"hotel","_id":"36934","_version":4,"result":"updated","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":3,"_primary_term":1}

5.7 删除文档

根据ID删除指定记录:

public function deleteDocById()
{
    $id = 36934;

    $result = $this->client->delete(['index' => 'hotel', 'id' => $id]);

    return json($result);
}

# 响应结果:
{"_index":"hotel","_id":"36934","_version":5,"result":"deleted","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":4,"_primary_term":1}

5.8 批量导入文档

public function batchAddDoc()
{
    $hotels = Hotel::order(['id' => 'asc'])->limit(2)->select();

    $params = [];
    foreach ($hotels as $hotel) {
        $params['body'][] = [
            'index' => [
                '_index' => 'hotel',
                '_id' => $hotel->id,
            ]
        ];

        $params['body'][] = [
            'id' => $hotel->id,
            'name' => $hotel->name,
            'address' => $hotel->address,
            'price' => $hotel->price,
            'score' => $hotel->score,
            'brand' => $hotel->brand,
            'city' => $hotel->city,
            'starName' => $hotel->star_name,
            'business' => $hotel->business,
            'location' => $hotel->latitude . ',' . $hotel->longitude,
            'pic' => $hotel->pic,
        ];
    }

    $result = $this->client->bulk($params);

    return json($result);
}

# 响应结果:
{"errors":false,"took":0,"items":[{"index":{"_index":"hotel","_id":"36934","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":5,"_primary_term":1,"status":201}},{"index":{"_index":"hotel","_id":"38609","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":6,"_primary_term":1,"status":201}}]}

5.9 ES 服务类

<?php

namespace app\pkg;

use Elasticsearch\ClientBuilder;
use Elasticsearch\Client;

class ES
{
    private Client $client;

    public function __construct(array $hosts)
    {
        $this->client = ClientBuilder::create()->setHosts($hosts)->build();
    }

    // ================================= 索引相关操作 =================================================

    /**
     * 创建索引
     *
     * @param string $index 索引名称
     * @param array $settings 索引设置
     * @param array $mappings 索引映射
     * @return array
     */
    public function creatIndex(string $index, array $settings = [], array $mappings = []): array
    {
        $params = [
            'index' => $index,
            'body'  => [
                'settings' => $settings,
                'mappings' => $mappings,
            ]
        ];

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

    /**
     * 删除索引
     *
     * @param $indexName string 索引名称
     * @return array
     */
    public function deleteIndex(string $indexName): array
    {
        $params = [
            'index' => $indexName,
        ];

        return $this->client->indices()->delete($params);
    }

    /**
     * 检查索引是否存在
     *
     * @param string $indexName
     * @return bool
     */
    public function existsIndex(string $indexName)
    {
        return $this->client->indices()->exists(['index' => $indexName]);
    }

    /**
     * 获取索引设置
     *
     * @param string $indexName 索引名称
     * @return array
     */
    public function getIndexSettings(string $indexName): array
    {
        $params = [
            'index' => $indexName
        ];

        return $this->client->indices()->getSettings($params);
    }

    /**
     * 关闭索引
     *
     * @param $indexName string 索引名称
     * @return array
     */
    public function closeIndex(string $indexName): array
    {
        $params = ['index' => $indexName];

        return $this->client->indices()->close($params);
    }

    /**
     * 打开索引
     *
     * @param $indexName string 索引名称
     * @return array
     */
    public function openIndex(string $indexName): array
    {
        $params = ['index' => $indexName];

        return $this->client->indices()->open($params);
    }

    /**
     * 更新索引设置
     *
     * @param string $indexName 索引名称
     * @param array $settings 新的索引设置
     * @return array 更新索引设置的响应
     */
    public function updateIndexSettings(string $indexName, array $settings): array
    {
        $params = [
            'index' => $indexName,
            'body'  => ['settings' => $settings]
        ];

        return $this->client->indices()->putSettings($params);
    }

    /**
     * 更新非动态索引设置
     *
     * @param $indexName string 索引名称
     * @param array $settings 索引设置
     * @return array
     */
    public function updateNonDynamicIndexSettings(string $indexName, array $settings)
    {
        // 关闭索引
        $this->closeIndex($indexName);

        // 更新索引设置
        $response = $this->updateIndexSettings($indexName, $settings);

        // 重新打开索引
        $this->openIndex($indexName);

        return $response;
    }

    /**
     * 获取索引映射
     *
     * @param string $indexName 索引名称
     * @return array 获取索引映射的响应
     */
    public function getIndexMappings($indexName)
    {
        $params = [
            'index' => $indexName
        ];

        return $this->client->indices()->getMapping($params);
    }

    /**
     * 更新索引映射
     *
     * @param string $indexName 索引名称
     * @param array $mappings 新的索引映射
     * @return array 更新索引映射的响应
     */
    public function updateIndexMappings(string $indexName, array $mappings): array
    {
        $params = [
            'index' => $indexName,
            'body'  => ['properties' => $mappings]
        ];

        return $this->client->indices()->putMapping($params);
    }

    /**
     * 刷新索引
     *
     * @param $indexName string 索引名称
     * @return array
     */
    public function refreshIndex(string $indexName): array
    {
        $params = [
            'index' => $indexName
        ];

        return $this->client->indices()->refresh($params);
    }

    // ===================================== 文档相关操作 ===============================================

    /**
     * 新增文档
     *
     * @param string $indexName 索引名称
     * @param string $id 文档ID
     * @param array $body 文档内容
     * @return array
     */
    public function addDocument($indexName, $id, array $body)
    {
        $params = [
            'index' => $indexName,
            'id'    => $id, // 文档ID,可省略,默认生成随机ID; 即使传入的是正整形,查询存到的结果还是字符串类型
            'body'  => $body
        ];

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

    /**
     * 批量新增文档
     *
     * @param array $params
     * @return array|callable
     */
    public function batchAddDocument(array $params)
    {
        return $this->client->bulk($params);
    }

    /**
     * 获取文档
     * 说明:查询单挑记录
     *
     * @param string $indexName 索引名称
     * @param string $id 文档ID
     * @return array|callable
     */
    public function getDocument(string $indexName, $id)
    {
        $params = [
            'index' => $indexName,
            'id'    => $id,
        ];

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

    /**
     * 更新文档
     *
     * @param string $indexName 索引名称
     * @param string $id 文档ID
     * @param array $doc 更新内容
     * @return array|callable
     */
    public function updateDocument(string $indexName, $id, array $doc)
    {
        $params = [
            'index' => $indexName,
            'id'    => $id,
            'body'  => [
                'doc' => $doc, // 需要更新的内容
            ],
        ];

        return $this->client->update($params);
    }

    /**
     * 删除文档
     *
     * @param string $indexName
     * @param $id
     * @return array|callable
     */
    public function deleteDocument(string $indexName, int $id)
    {
        $params = [
            'index' => $indexName,
            'id'    => $id,
        ];

        return $this->client->delete($params);
    }

    // ======================================= 搜索相关操作 ================================================

    /**
     * 基础搜索方法
     *
     * @param string $indexName 索引名称
     * @param array $query 搜索查询
     * @param array|null $sort 排序参数
     * @param int|null $from 起始位置
     * @param int|null $size 返回结果数
     * @return array
     */
    public function search(string $indexName, array $query, array $sort = null, int $from = null, int $size = null)
    {
        $params = [
            'index' => $indexName,
            'body'  => [
                'query' => $query
            ]
        ];

        if ($sort) {
            $params['body']['sort'] = $sort;
        }

        if (!is_null($from)) {
            $params['body']['from'] = $from;
        }

        if (!is_null($size)) {
            $params['body']['size'] = $size;
        }


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

http://www.kler.cn/a/409474.html

相关文章:

  • Python 获取微博用户信息及作品(完整版)
  • 如何选择服务器
  • 一文学习开源框架OkHttp
  • (超级详细!!!)解决“com.mysql.jdbc.Driver is deprecated”警告:详解与优化
  • C++注释
  • 解决 Android 单元测试 No tests found for given includes:
  • 后台发货时用户收到【商品确认收货提醒】
  • C 语言多文件项目
  • 探索 Vue.js:构建交互式前端的强大工具
  • v-if和:visible.sync
  • 第144场双周赛题解:两个字符串得切换距离
  • Dubbo Golang快速开发Rpc服务
  • 详解Oracle表的类型(二)
  • springboot集成shiro和前后端分离配置
  • matlab 反距离插值 IDW
  • 【系统架构设计师】真题论文: 论非功能性需求对企业应用架构设计的影响(包括解题思路和素材)
  • 基于YOLOv8深度学习的智慧交通事故检测系统研究与实现(PyQt5界面+数据集+训练代码)
  • jdk8特性:CompletableFuture的使用
  • 小R的随机播放顺序
  • 论文 | Recitation-Augmented Language Models
  • 6.STM32之通信接口《精讲》之USART通信(PC串口与OLED交互)---多字节数据收发(数据包的模式:HEX数据包和文本数据包)
  • 五天SpringCloud计划——DAY1之mybatis-plus的使用
  • SpringBoot3中的性能提升介绍
  • Linux上安装单机版ElasticSearch6.8.1
  • 设计模式之创建模式篇
  • 签到送金币项目