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);
相关推荐
XR12345678810 分钟前
工业园区整体组网,方案对比怎么选?
开发语言·php
东东最爱敲键盘15 分钟前
day9.C++多态之虚函数
开发语言·c++
码云数智-园园22 分钟前
类似小鹅通的知识付费小程序平台有哪些
开发语言
snow@li30 分钟前
Java:跨平台原理与JDK、JRE、JVM全景深度解析
java·开发语言·jvm
Livia要学习33 分钟前
Python闭包
开发语言·jvm·python
覆东流34 分钟前
2.Java程序基础
java·开发语言·后端
ttwuai42 分钟前
Go 后台定时任务启停不生效怎么办?先查调度同步链路
开发语言·后端·golang
小的~~1 小时前
ThreadLocal 、InheritableThreadLocal 与 TransmittableThreadLocal 的进阶指南
java·开发语言
Ramboooooooo1 小时前
SkyWalking-10.4.0 Docker + Nacos + Elasticsearch 生产级部署手册
elasticsearch·docker·skywalking
键盘会跳舞1 小时前
C++:std::pair 源码级深度剖析 —— 关联容器的基石
开发语言·c++·pair·关联容器