本文目录导读:

我来提供一个完整的PHP Elasticsearch索引管理指南,涵盖常用的索引管理操作。
安装和初始化
<?php
require_once 'vendor/autoload.php';
use Elastic\Elasticsearch\ClientBuilder;
class ElasticsearchManager {
private $client;
public function __construct($hosts = ['localhost:9200']) {
$this->client = ClientBuilder::create()
->setHosts($hosts)
->setBasicAuthentication('username', 'password') // 如果有认证
->setSSLVerification(false) // 如果使用HTTPS且不需要验证证书
->build();
}
public function getClient() {
return $this->client;
}
}
索引创建
class IndexManager {
private $client;
public function __construct($client) {
$this->client = $client;
}
// 创建索引
public function createIndex($indexName, $mappings = [], $settings = []) {
$params = [
'index' => $indexName,
'body' => [
'settings' => array_merge([
'number_of_shards' => 3,
'number_of_replicas' => 2
], $settings),
'mappings' => $mappings
]
];
try {
$response = $this->client->indices()->create($params);
return $response->asArray();
} catch (\Exception $e) {
throw new \Exception("创建索引失败: " . $e->getMessage());
}
}
// 创建索引(带完整配置示例)
public function createUserIndex() {
$mappings = [
'properties' => [
'id' => ['type' => 'long'],
'name' => [
'type' => 'text',
'fields' => [
'keyword' => ['type' => 'keyword']
]
],
'email' => ['type' => 'keyword'],
'age' => ['type' => 'integer'],
'created_at' => ['type' => 'date'],
'tags' => ['type' => 'keyword'],
'bio' => [
'type' => 'text',
'analyzer' => 'ik_max_word' // 中文分词器
]
]
];
$settings = [
'number_of_shards' => 2,
'number_of_replicas' => 1,
'analysis' => [
'analyzer' => [
'default' => [
'type' => 'ik_max_word'
]
]
]
];
return $this->createIndex('users', $mappings, $settings);
}
// 仅当索引不存在时创建
public function createIndexIfNotExists($indexName, $mappings = [], $settings = []) {
if (!$this->indexExists($indexName)) {
return $this->createIndex($indexName, $mappings, $settings);
}
return ['acknowledged' => true, 'message' => '索引已存在'];
}
}
索引查询和检查
class IndexManager {
// 检查索引是否存在
public function indexExists($indexName) {
$params = ['index' => $indexName];
return $this->client->indices()->exists($params)->asBool();
}
// 获取索引信息
public function getIndexInfo($indexName) {
$params = ['index' => $indexName];
return $this->client->indices()->get($params)->asArray();
}
// 获取索引设置
public function getIndexSettings($indexName) {
$params = [
'index' => $indexName,
'include_defaults' => true
];
return $this->client->indices()->getSettings($params)->asArray();
}
// 获取索引映射
public function getIndexMapping($indexName) {
$params = ['index' => $indexName];
return $this->client->indices()->getMapping($params)->asArray();
}
// 获取索引统计信息
public function getIndexStats($indexName) {
$params = [
'index' => $indexName,
'metric' => 'docs,store,indexing,get,search'
];
return $this->client->indices()->stats($params)->asArray();
}
// 获取所有索引列表
public function getAllIndices() {
$params = [
'index' => '*',
'expand_wildcards' => 'all'
];
return $this->client->indices()->get($params)->asArray();
}
// 获取索引健康状态
public function getIndexHealth($indexName = null) {
$params = [];
if ($indexName) {
$params['index'] = $indexName;
}
return $this->client->cluster()->health($params)->asArray();
}
}
索引更新和修改
class IndexManager {
// 更新索引设置
public function updateIndexSettings($indexName, $settings) {
$params = [
'index' => $indexName,
'body' => [
'settings' => $settings
]
];
try {
return $this->client->indices()->putSettings($params)->asArray();
} catch (\Exception $e) {
throw new \Exception("更新索引设置失败: " . $e->getMessage());
}
}
// 添加映射字段
public function addMapping($indexName, $properties) {
$params = [
'index' => $indexName,
'body' => [
'properties' => $properties
]
];
try {
return $this->client->indices()->putMapping($params)->asArray();
} catch (\Exception $e) {
throw new \Exception("添加映射失败: " . $e->getMessage());
}
}
// 更新现有映射(注意:只能添加新字段,不能修改已有字段)
public function updateMapping($indexName, $newFields) {
try {
$existingMapping = $this->getIndexMapping($indexName);
$existingProperties = $existingMapping[$indexName]['mappings']['properties'] ?? [];
// 合并字段
$mergedProperties = array_merge($existingProperties, $newFields);
return $this->addMapping($indexName, $mergedProperties);
} catch (\Exception $e) {
throw new \Exception("更新映射失败: " . $e->getMessage());
}
}
// 刷新索引
public function refreshIndex($indexName) {
$params = ['index' => $indexName];
return $this->client->indices()->refresh($params)->asArray();
}
// 强制合并段
public function forceMerge($indexName, $maxSegments = 1) {
$params = [
'index' => $indexName,
'max_num_segments' => $maxSegments,
'wait_for_completion' => true
];
return $this->client->indices()->forcemerge($params)->asArray();
}
// 清空索引缓存
public function clearCache($indexName) {
$params = ['index' => $indexName];
return $this->client->indices()->clearCache($params)->asArray();
}
// 开启或关闭索引
public function openIndex($indexName) {
return $this->client->indices()->open(['index' => $indexName]);
}
public function closeIndex($indexName) {
return $this->client->indices()->close(['index' => $indexName]);
}
}
索引别名管理
class IndexManager {
// 创建别名
public function createAlias($indexName, $aliasName) {
$params = [
'index' => $indexName,
'name' => $aliasName
];
return $this->client->indices()->putAlias($params)->asArray();
}
// 创建多个别名
public function createAliases($actions) {
$params = ['body' => ['actions' => $actions]];
return $this->client->indices()->updateAliases($params)->asArray();
}
// 删除别名
public function deleteAlias($indexName, $aliasName) {
$params = [
'index' => $indexName,
'name' => $aliasName
];
return $this->client->indices()->deleteAlias($params)->asArray();
}
// 获取别名信息
public function getAliases($indexName = null) {
$params = [];
if ($indexName) {
$params['index'] = $indexName;
}
return $this->client->indices()->getAliases($params)->asArray();
}
// 别名切换(用于索引重建)
public function switchAlias($oldIndex, $newIndex, $aliasName) {
$params = [
'body' => [
'actions' => [
['remove' => ['index' => $oldIndex, 'alias' => $aliasName]],
['add' => ['index' => $newIndex, 'alias' => $aliasName]]
]
]
];
return $this->client->indices()->updateAliases($params)->asArray();
}
}
索引模板管理
class IndexManager {
// 创建索引模板
public function createTemplate($templateName, $template) {
$params = [
'name' => $templateName,
'body' => $template
];
return $this->client->indices()->putTemplate($params)->asArray();
}
// 创建示例模板
public function createUserTemplate() {
$template = [
'index_patterns' => ['users-*'],
'settings' => [
'number_of_shards' => 2,
'number_of_replicas' => 1
],
'mappings' => [
'properties' => [
'name' => ['type' => 'text'],
'email' => ['type' => 'keyword'],
'created_at' => ['type' => 'date']
]
],
'aliases' => [
'all-users' => []
]
];
return $this->createTemplate('users_template', $template);
}
// 获取模板
public function getTemplate($templateName) {
return $this->client->indices()->getTemplate(['name' => $templateName])->asArray();
}
// 删除模板
public function deleteTemplate($templateName) {
return $this->client->indices()->deleteTemplate(['name' => $templateName])->asArray();
}
// 获取所有模板
public function getAllTemplates() {
return $this->client->indices()->getTemplate()->asArray();
}
// 更新模板
public function updateTemplate($templateName, $newTemplate) {
return $this->createTemplate($templateName, $newTemplate);
}
}
索引生命周期管理
class IndexManager {
// 创建生命周期策略
public function createILMPolicy($policyName, $policy) {
$params = [
'name' => $policyName,
'body' => $policy
];
return $this->client->ilm()->putLifecycle($params)->asArray();
}
// 创建示例生命周期策略
public function createDefaultILMPolicy() {
$policy = [
'policy' => [
'phases' => [
'hot' => [
'actions' => [
'rollover' => [
'max_size' => '50gb',
'max_age' => '30d'
]
]
],
'delete' => [
'min_age' => '90d',
'actions' => [
'delete' => []
]
]
]
]
];
return $this->createILMPolicy('logs-lifecycle', $policy);
}
// 应用生命周期策略到索引
public function applyILMPolicy($indexName, $policyName) {
$params = [
'index' => $indexName,
'body' => [
'index' => [
'lifecycle' => [
'name' => $policyName
]
]
]
];
return $this->updateIndexSettings($indexName, $params['body']);
}
}
索引删除操作
class IndexManager {
// 删除单个索引
public function deleteIndex($indexName) {
$params = ['index' => $indexName];
try {
return $this->client->indices()->delete($params)->asArray();
} catch (\Exception $e) {
throw new \Exception("删除索引失败: " . $e->getMessage());
}
}
// 删除多个索引
public function deleteIndices($indices) {
$params = ['index' => implode(',', $indices)];
return $this->client->indices()->delete($params)->asArray();
}
// 按模式删除索引
public function deleteByPattern($pattern) {
$allIndices = $this->getAllIndices();
$toDelete = [];
foreach (array_keys($allIndices) as $indexName) {
if (fnmatch($pattern, $indexName)) {
$toDelete[] = $indexName;
}
}
if (!empty($toDelete)) {
return $this->deleteIndices($toDelete);
}
return ['deleted' => 0, 'message' => '没有匹配的索引'];
}
// 清理旧索引(基于日期)
public function cleanupOldIndices($prefix, $daysToKeep) {
$allIndices = $this->getAllIndices();
$cutoffDate = strtotime("-{$daysToKeep} days");
$toDelete = [];
foreach (array_keys($allIndices) as $indexName) {
if (strpos($indexName, $prefix) === 0) {
$dateStr = str_replace($prefix, '', $indexName);
$timestamp = strtotime($dateStr);
if ($timestamp && $timestamp < $cutoffDate) {
$toDelete[] = $indexName;
}
}
}
if (!empty($toDelete)) {
return $this->deleteIndices($toDelete);
}
return ['deleted' => 0, 'message' => '没有需要清理的索引'];
}
}
索引重建(Reindex)
class IndexManager {
// 重建索引
public function reindex($sourceIndex, $targetIndex, $query = []) {
$params = [
'body' => [
'source' => ['index' => $sourceIndex],
'dest' => ['index' => $targetIndex]
]
];
if (!empty($query)) {
$params['body']['source']['query'] = $query;
}
return $this->client->reindex($params)->asArray();
}
// 异步重建索引
public function reindexAsync($sourceIndex, $targetIndex, $query = []) {
$params = [
'wait_for_completion' => false,
'body' => [
'source' => ['index' => $sourceIndex],
'dest' => ['index' => $targetIndex]
]
];
if (!empty($query)) {
$params['body']['source']['query'] = $query;
}
return $this->client->reindex($params)->asArray();
}
// 获取重建任务状态
public function getTaskStatus($taskId) {
return $this->client->tasks()->get(['task_id' => $taskId])->asArray();
}
// 取消重建任务
public function cancelTask($taskId) {
return $this->client->tasks()->cancel(['task_id' => $taskId])->asArray();
}
// 零停机索引重建(使用别名)
public function reindexWithAlias($indexName, $newIndexPrefix, $aliasName) {
$newIndexName = $newIndexPrefix . '-' . date('Y-m-d-H-i-s');
// 1. 创建新索引
$oldMapping = $this->getIndexMapping($indexName);
$oldSettings = $this->getIndexSettings($indexName);
// 只复制必要设置
$settings = $oldSettings[$indexName]['settings']['index'];
unset($settings['uuid'], $settings['creation_date'], $settings['version']);
$this->createIndexIfNotExists($newIndexName, $oldMapping[$indexName]['mappings'], $settings);
// 2. 复制数据
$this->reindex($indexName, $newIndexName);
// 3. 切换别名
$this->switchAlias($indexName, $newIndexName, $aliasName);
// 4. 删除旧索引
$this->deleteIndex($indexName);
return $newIndexName;
}
}
完整使用示例
class ElasticsearchDemo {
public function run() {
// 初始化
$esManager = new ElasticsearchManager(['https://localhost:9200']);
$client = $esManager->getClient();
$indexManager = new IndexManager($client);
// 1. 创建索引
echo "=== 创建索引 ===\n";
$result = $indexManager->createUserIndex();
echo json_encode($result, JSON_PRETTY_PRINT) . "\n";
// 2. 检查索引是否存在
echo "=== 检查索引 ===\n";
$exists = $indexManager->indexExists('users');
echo "users索引存在: " . ($exists ? '是' : '否') . "\n";
// 3. 获取索引信息
echo "=== 获取索引信息 ===\n";
$info = $indexManager->getIndexInfo('users');
echo json_encode($info, JSON_PRETTY_PRINT) . "\n";
// 4. 添加映射字段
echo "=== 添加映射字段 ===\n";
$result = $indexManager->addMapping('users', [
'phone' => ['type' => 'keyword']
]);
echo json_encode($result, JSON_PRETTY_PRINT) . "\n";
// 5. 创建别名
echo "=== 创建别名 ===\n";
$result = $indexManager->createAlias('users', 'all-users');
echo json_encode($result, JSON_PRETTY_PRINT) . "\n";
// 6. 创建索引模板
echo "=== 创建索引模板 ===\n";
$result = $indexManager->createUserTemplate();
echo json_encode($result, JSON_PRETTY_PRINT) . "\n";
// 7. 获取索引统计
echo "=== 获取索引统计 ===\n";
$stats = $indexManager->getIndexStats('users');
echo json_encode($stats, JSON_PRETTY_PRINT) . "\n";
// 8. 清理示例(最后执行)
// echo "=== 清理索引 ===\n";
// $indexManager->deleteIndex('users');
// $indexManager->deleteTemplate('users_template');
}
}
// 执行示例
$demo = new ElasticsearchDemo();
$demo->run();
最佳实践建议
class IndexBestPractices {
// 索引命名规范
public function namingConventions() {
return [
'格式' => '<prefix>-<type>-<date>',
'示例' => [
'logs-app-2024-01-01',
'logs-system-2024-01-01',
'users-v1',
'transactions-2024-01'
],
'建议' => [
'使用小写字母',
'使用连字符分隔',
'避免特殊字符',
'包含日期用于区分'
]
];
}
// 分片设置建议
public function shardRecommendations() {
return [
'分片数量' => '每个分片大小控制在20-50GB',
'副本数量' => '生产环境至少1个副本',
'计算公式' => '分片数 = 预计存储量 / 30GB',
'注意事项' => [
'分片数量创建后不可修改',
'分片过多会降低搜索性能',
'分片过少会影响扩展性'
]
];
}
// 映射设计建议
public function mappingDesign() {
return [
'字段类型' => [
'避免使用text类型做精确匹配',
'使用keyword类型做精确匹配',
'数值字段使用合适的数值类型'
],
'分析器' => [
'中文使用ik_max_word或smartcn',
'英文使用standard分析器',
'自定义分析器适合特殊需求'
],
'索引选项' => [
'不需要搜索的字段关闭index',
'需要排序的字段使用doc_values',
'大字段考虑关闭store'
]
];
}
// 索引维护建议
public function maintenanceRecommendations() {
return [
'定期操作' => [
'优化:force merge',
'清理:删除过期索引',
'备份:定期做快照',
'监控:查看索引健康度'
],
'监控指标' => [
'索引大小',
'文档数量',
'查询延迟',
'磁盘使用率'
],
'紧急处理' => [
'索引只读:处理磁盘满',
'强制刷新:处理数据不一致',
'重建索引:解决映射问题'
]
];
}
}
这个完整的PHP Elasticsearch索引管理指南涵盖了:
- 基础操作:创建、删除、查询索引
- 配置管理:设置、映射、别名
- 高级功能:模板、生命周期管理
- 维护操作:重建、优化、清理
- 最佳实践:命名规范、分片设计等
建议根据实际需求选择合适的操作,并做好错误处理和日志记录,在生产环境中要注意索引的备份和恢复策略。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播