PHP项目ES如何在PHP中连接操作

wen PHP项目 25

本文目录导读:

PHP项目ES如何在PHP中连接操作

  1. 使用官方客户端(推荐)
  2. 使用CURL直接操作(无依赖)
  3. 封装成服务类(推荐用于项目)
  4. 配置和最佳实践
  5. 调试和监控

在PHP中连接和操作 Elasticsearch(ES),主要有以下几种方式:

使用官方客户端(推荐)

安装

composer require elasticsearch/elasticsearch

基本连接

<?php
require 'vendor/autoload.php';
use Elastic\Elasticsearch\ClientBuilder;
// 单节点连接
$client = ClientBuilder::create()
    ->setHosts(['localhost:9200'])
    ->build();
// 多节点连接(集群)
$client = ClientBuilder::create()
    ->setHosts([
        '192.168.1.1:9200',
        '192.168.1.2:9200',
        '192.168.1.3:9200'
    ])
    ->build();
// 带认证的连接
$client = ClientBuilder::create()
    ->setHosts(['https://user:password@localhost:9200'])
    ->setSSLVerification(false) // 开发环境可以关闭SSL验证
    ->build();

基本操作示例

创建索引

$params = [
    'index' => 'my_index',
    'body' => [
        'settings' => [
            'number_of_shards' => 3,
            'number_of_replicas' => 2
        ],
        'mappings' => [
            'properties' => [
                'title' => [
                    'type' => 'text'
                ],
                'content' => [
                    'type' => 'text'
                ],
                'price' => [
                    'type' => 'float'
                ],
                'created_at' => [
                    'type' => 'date',
                    'format' => 'yyyy-MM-dd HH:mm:ss'
                ]
            ]
        ]
    ]
];
$response = $client->indices()->create($params);

添加文档

// 单条添加
$params = [
    'index' => 'my_index',
    'id' => '1',
    'body' => [
        'title' => 'PHP教程',
        'content' => '学习PHP编程',
        'price' => 29.99,
        'created_at' => '2024-01-15 10:30:00'
    ]
];
$response = $client->index($params);
// 批量添加
$params = ['body' => []];
for ($i = 1; $i <= 100; $i++) {
    $params['body'][] = [
        'index' => [
            '_index' => 'my_index',
            '_id' => $i
        ]
    ];
    $params['body'][] = [
        'title' => "文章{$i}",
        'content' => "这是第{$i}篇文章的内容",
        'price' => rand(10, 100),
        'created_at' => date('Y-m-d H:i:s', strtotime("-{$i} days"))
    ];
}
$responses = $client->bulk($params);

搜索文档

// 基本搜索
$params = [
    'index' => 'my_index',
    'body' => [
        'query' => [
            'match' => [
                'title' => 'PHP'
            ]
        ],
        'size' => 10,
        'from' => 0,
        'sort' => [
            'price' => 'desc'
        ]
    ]
];
$response = $client->search($params);
// 处理结果
$hits = $response['hits']['hits'];
$total = $response['hits']['total']['value'];
foreach ($hits as $hit) {
    echo "ID: " . $hit['_id'] . "\n";
    echo "Score: " . $hit['_score'] . "\n";
    print_r($hit['_source']);
    echo "---\n";
}
// 高级搜索(多条件)
$params = [
    'index' => 'my_index',
    'body' => [
        'query' => [
            'bool' => [
                'must' => [
                    ['match' => ['title' => 'PHP']],
                    ['range' => ['price' => ['gte' => 20, 'lte' => 50]]]
                ],
                'filter' => [
                    ['term' => ['status' => 'active']]
                ]
            ]
        ],
        'aggs' => [
            'avg_price' => [
                'avg' => ['field' => 'price']
            ],
            'price_ranges' => [
                'range' => [
                    'field' => 'price',
                    'ranges' => [
                        ['to' => 30],
                        ['from' => 30, 'to' => 60],
                        ['from' => 60]
                    ]
                ]
            ]
        ]
    ]
];
$response = $client->search($params);

更新文档

// 部分更新
$params = [
    'index' => 'my_index',
    'id' => '1',
    'body' => [
        'doc' => [
            'price' => 39.99,
            'updated_at' => date('Y-m-d H:i:s')
        ]
    ]
];
$response = $client->update($params);
// 通过脚本更新
$params = [
    'index' => 'my_index',
    'id' => '1',
    'body' => [
        'script' => [
            'source' => 'ctx._source.price += params.discount',
            'params' => ['discount' => -5]
        ]
    ]
];
$response = $client->updateByQuery($params);

删除文档

// 删除单个
$params = [
    'index' => 'my_index',
    'id' => '1'
];
$response = $client->delete($params);
// 条件删除
$params = [
    'index' => 'my_index',
    'body' => [
        'query' => [
            'range' => [
                'created_at' => [
                    'lte' => '2024-01-01'
                ]
            ]
        ]
    ]
];
$response = $client->deleteByQuery($params);

使用CURL直接操作(无依赖)

function esRequest($method, $uri, $body = null) {
    $url = "http://localhost:9200/{$uri}";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    if ($body) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    }
    $response = curl_exec($ch);
    curl_close($ch);
    return json_decode($response, true);
}
// 使用示例
$result = esRequest('GET', 'my_index/_search', [
    'query' => [
        'match' => ['title' => 'PHP']
    ]
]);

封装成服务类(推荐用于项目)

<?php
namespace App\Services;
use Elastic\Elasticsearch\ClientBuilder;
class ElasticsearchService
{
    private $client;
    private $index;
    public function __construct($hosts = ['localhost:9200'], $index = 'default_index')
    {
        $this->client = ClientBuilder::create()
            ->setHosts($hosts)
            ->build();
        $this->index = $index;
    }
    public function setIndex($index)
    {
        $this->index = $index;
        return $this;
    }
    public function search($query, $page = 1, $size = 10, $sort = [])
    {
        $params = [
            'index' => $this->index,
            'body' => [
                'query' => $query,
                'from' => ($page - 1) * $size,
                'size' => $size
            ]
        ];
        if (!empty($sort)) {
            $params['body']['sort'] = $sort;
        }
        try {
            $response = $this->client->search($params);
            return [
                'total' => $response['hits']['total']['value'],
                'hits' => $response['hits']['hits'],
                'page' => $page,
                'size' => $size
            ];
        } catch (\Exception $e) {
            return ['error' => $e->getMessage()];
        }
    }
    public function indexDocument($id, $data)
    {
        $params = [
            'index' => $this->index,
            'id' => $id,
            'body' => $data
        ];
        return $this->client->index($params);
    }
    public function deleteDocument($id)
    {
        $params = [
            'index' => $this->index,
            'id' => $id
        ];
        return $this->client->delete($params);
    }
    public function bulkIndex($documents)
    {
        $params = ['body' => []];
        foreach ($documents as $doc) {
            $params['body'][] = [
                'index' => [
                    '_index' => $this->index,
                    '_id' => $doc['id']
                ]
            ];
            $params['body'][] = $doc['data'];
        }
        return $this->client->bulk($params);
    }
}

配置和最佳实践

连接池配置

$client = ClientBuilder::create()
    ->setHosts(['localhost:9200'])
    ->setConnectionPool('\Elasticsearch\ConnectionPool\StaticNoPingConnectionPool')
    ->setRetries(3)
    ->setHandler(ClientBuilder::singleHandler())
    ->build();

错误处理

try {
    $response = $client->search($params);
} catch (\Elastic\Elasticsearch\Exception\ElasticsearchException $e) {
    echo "ES错误: " . $e->getMessage();
} catch (\Exception $e) {
    echo "一般错误: " . $e->getMessage();
}

性能优化

// 设置批量处理大小
$batchSize = 1000;
$documents = [/* ... */];
$params = ['body' => []];
foreach ($documents as $doc) {
    $params['body'][] = [
        'index' => ['_index' => 'my_index', '_id' => $doc['id']]
    ];
    $params['body'][] = $doc['data'];
    if (count($params['body']) >= $batchSize * 2) {
        $client->bulk($params);
        $params = ['body' => []];
    }
}
// 处理剩余文档
if (!empty($params['body'])) {
    $client->bulk($params);
}

调试和监控

// 开启调试模式
$logger = ClientBuilder::defaultLogger('path/to/logs/elastic.log');
$client = ClientBuilder::create()
    ->setHosts(['localhost:9200'])
    ->setLogger($logger)
    ->build();
// 查看请求信息
$response = $client->search($params);
echo "用时: " . $response['took'] . "ms\n";
echo "分片信息: " . print_r($response['_shards'], true);

选择哪种方式取决于你的项目需求:

  • 小型项目:使用官方客户端最简单
  • 大型项目:封装成服务类更易维护
  • 无依赖需求:CURL方式最轻量

抱歉,评论功能暂时关闭!