php操作elasticsearch,亲测可用

PHP 环境要求:PHP >= 7.2 + 安装 ES 客户端

复制代码
composer require elasticsearch/elasticsearch
php 复制代码
<?php
require 'vendor/autoload.php'; // 加载 composer 依赖

use Elasticsearch\ClientBuilder;
use DateTime;

// ========== 连接 Elasticsearch ==========

// 1. 基本连接(对应 Python 基础连接)
$client = ClientBuilder::create()
    ->setHosts(['http://localhost:9200']) // ES 地址
    ->build();

// 2. 带认证连接(账号密码 + 证书)
$client = ClientBuilder::create()
    ->setHosts(['https://localhost:9200'])
    ->setBasicAuthentication('elastic', 'password') // 认证
    ->setCABundle('/path/to/http_ca.crt') // 证书
    ->build();

// 3. 多节点连接
$client = ClientBuilder::create()
    ->setHosts([
        'http://node1:9200',
        'http://node2:9200',
        'http://node3:9200',
    ])
    ->build();

// 验证连接(输出 ES 信息)
print_r($client->info());

// ========== 索引操作 ==========

// 创建索引(结构与 Python 完全一致)
$indexParams = [
    'index' => 'articles', // 索引名
    'body' => [
        'settings' => [
            'number_of_shards' => 1,   // 主分片
            'number_of_replicas' => 0,  // 副本
        ],
        'mappings' => [
            'properties' => [
                'title' => ['type' => 'text', 'analyzer' => 'standard'],
                'content' => ['type' => 'text'],
                'author' => ['type' => 'keyword'],
                'publish_date' => ['type' => 'date'],
                'views' => ['type' => 'integer'],
                'tags' => ['type' => 'keyword'],
            ]
        ]
    ]
];

// 创建索引,忽略已存在错误(400)
try {
    $client->indices()->create($indexParams);
} catch (Exception $e) {}

// 检查索引是否存在
if ($client->indices()->exists(['index' => 'articles'])) {
    echo "索引存在\n";
}

// 删除索引(忽略 400/404 错误)
try {
    $client->indices()->delete(['index' => 'articles']);
} catch (Exception $e) {}

// ========== 文档操作 ==========

// 插入单个文档(ID=1)
$doc = [
    'title' => 'Elasticsearch入门教程',
    'content' => 'Elasticsearch是一个分布式搜索引擎...',
    'author' => '张三',
    'publish_date' => (new DateTime())->format('Y-m-d H:i:s'),
    'views' => 1000,
    'tags' => ['elasticsearch', '搜索', '教程']
];

$response = $client->index([
    'index' => 'articles',
    'id' => 1,
    'body' => $doc
]);

echo "插入结果:" . $response['result'] . "\n";

// ========== 批量插入文档(2~101) ==========
$params = ['body' => []];
for ($i = 2; $i < 102; $i++) {
    // 批量第一行:指定操作
    $params['body'][] = [
        'index' => [
            '_index' => 'articles',
            '_id' => $i
        ]
    ];
    // 批量第二行:文档内容
    $params['body'][] = [
        'title' => "文章标题$i",
        'content' => "文章内容$i",
        'author' => "作者" . $i % 5,
        'publish_date' => (new DateTime())->format('Y-m-d H:i:s'),
        'views' => $i * 100
    ];
}

// 执行批量
$responses = $client->bulk($params);
$success = $i - 2 - count($responses['items']);
echo "成功:" . ($i - 2) . ",失败:" . count($responses['items']) . "\n";

// ========== 获取单个文档 ==========
$doc = $client->get([
    'index' => 'articles',
    'id' => 1
]);
print_r($doc['_source']);

// ========== 更新文档 ==========
$client->update([
    'index' => 'articles',
    'id' => 1,
    'body' => [
        'doc' => [
            'views' => 1500,
            'updated_at' => (new DateTime())->format('Y-m-d H:i:s')
        ]
    ]
]);

// ========== 删除文档 ==========
$client->delete([
    'index' => 'articles',
    'id' => 1
]);

// ========== 搜索操作 ==========

// match 查询(标题搜索)
$result = $client->search([
    'index' => 'articles',
    'body' => [
        'query' => [
            'match' => [
                'title' => 'Elasticsearch 教程'
            ]
        ]
    ]
]);

// 遍历搜索结果
foreach ($result['hits']['hits'] as $hit) {
    echo "ID: {$hit['_id']}, Score: {$hit['_score']}\n";
    echo "Title: {$hit['_source']['title']}\n";
}

// ========== bool 复合查询 ==========
$result = $client->search([
    'index' => 'articles',
    'body' => [
        'query' => [
            'bool' => [
                'must' => [
                    ['match' => ['content' => '搜索引擎']]
                ],
                'filter' => [
                    ['range' => ['views' => ['gte' => 500]]],
                    ['term' => ['author' => '张三']]
                ]
            ]
        ],
        'sort' => [
            ['views' => 'desc'],
            '_score'
        ],
        'from' => 0,
        'size' => 10,
        '_source' => ['title', 'author', 'views']
    ]
]);

echo "总命中:" . $result['hits']['total']['value'] . "\n";
foreach ($result['hits']['hits'] as $hit) {
    print_r($hit['_source']);
}

// ========== 高亮搜索 ==========
$result = $client->search([
    'index' => 'articles',
    'body' => [
        'query' => [
            'match' => [
                'content' => 'Elasticsearch'
            ]
        ],
        'highlight' => [
            'fields' => [
                'content' => [
                    'pre_tags' => ['<em>'],
                    'post_tags' => ['</em>']
                ]
            ]
        ]
    ]
]);

foreach ($result['hits']['hits'] as $hit) {
    if (isset($hit['highlight'])) {
        echo implode(',', $hit['highlight']['content']) . "\n";
    }
}

// ========== 聚合分析:按作者分组 + 平均浏览量 ==========
$result = $client->search([
    'index' => 'articles',
    'body' => [
        'size' => 0,
        'aggs' => [
            'by_author' => [
                'terms' => [
                    'field' => 'author',
                    'size' => 10
                ],
                'aggs' => [
                    'avg_views' => [
                        'avg' => ['field' => 'views']
                    ]
                ]
            ]
        ]
    ]
]);

// 输出聚合结果
foreach ($result['aggregations']['by_author']['buckets'] as $bucket) {
    $author = $bucket['key'];
    $count = $bucket['doc_count'];
    $avg = round($bucket['avg_views']['value']);
    echo "作者:$author,文章数:$count,平均浏览:$avg\n";
}

// ========== 封装类(与 Python 完全对应) ==========
class ElasticsearchClient
{
    private $es;

    // 构造函数:创建连接
    public function __construct($hosts = ['http://localhost:9200'])
    {
        $this->es = ClientBuilder::create()->setHosts($hosts)->build();
    }

    // 创建索引
    public function createIndex($indexName, $mappings = null, $settings = null)
    {
        $body = [];
        if ($settings) $body['settings'] = $settings;
        if ($mappings) $body['mappings'] = $mappings;

        if (!$this->es->indices()->exists(['index' => $indexName])) {
            $this->es->indices()->create([
                'index' => $indexName,
                'body' => $body
            ]);
            return true;
        }
        return false;
    }

    // 插入文档
    public function indexDocument($indexName, $doc, $docId = null)
    {
        $params = [
            'index' => $indexName,
            'body' => $doc
        ];
        if ($docId) $params['id'] = $docId;
        return $this->es->index($params);
    }

    // 搜索文档
    public function search($indexName, $query, $size = 10, $from = 0, $sort = null)
    {
        $body = [
            'query' => $query,
            'size' => $size,
            'from' => $from
        ];
        if ($sort) $body['sort'] = $sort;

        $result = $this->es->search([
            'index' => $indexName,
            'body' => $body
        ]);

        return [
            'total' => $result['hits']['total']['value'],
            'hits' => array_map(function ($hit) {
                return $hit['_source'];
            }, $result['hits']['hits'])
        ];
    }

    // 按查询条件删除
    public function deleteByQuery($indexName, $query)
    {
        return $this->es->deleteByQuery([
            'index' => $indexName,
            'body' => ['query' => $query]
        ]);
    }

    // 关闭客户端
    public function close()
    {
        $this->es = null;
    }
}

// ========== 封装类使用示例 ==========
$client = new ElasticsearchClient();

// 创建测试索引
$client->createIndex('test_index', [
    'properties' => [
        'title' => ['type' => 'text'],
        'content' => ['type' => 'text']
    ]
]);

// 插入文档
$client->indexDocument('test_index', [
    'title' => '测试文档',
    'content' => '这是一个测试'
]);

// 搜索
$res = $client->search('test_index', [
    'match' => ['title' => '测试']
]);

print_r($res);
相关推荐
Deadly_Bug_GF2 小时前
PID 控制器的核心原理
开发语言·python
rqtz2 小时前
【C++】揭秘工程实践:Boost 源码编译与 CMake 环境搭建的具体流程
开发语言·c++·网络编程·boost
Yupureki2 小时前
《Linux系统编程》19.线程同步与互斥
java·linux·服务器·c语言·开发语言·数据结构·c++
FL16238631292 小时前
基于C#winform部署RealESRGAN的onnx模型实现超分辨率图片无损放大模糊图片变清晰
开发语言·c#
liuyao_xianhui2 小时前
优选算法_锯齿形层序遍历二叉树_队列_C++
java·开发语言·数据结构·c++·算法·链表
Elnaij3 小时前
从C++开始的编程生活(24)——C++11标准Ⅰ
开发语言·c++
mjhcsp3 小时前
AT_arc205_c [ARC205C] No Collision Moves 题解
开发语言·c++·算法·题解
MLGDOU3 小时前
【Qt开发】信号与槽
开发语言·数据库·qt
风萧萧19993 小时前
Milvus Java 快速入门
java·开发语言·milvus