Commit e99df3bf authored by platyhouse's avatar platyhouse

# Elasticsearch 인덱스 조회 도구 추가

## 인덱스 조회 도구 구현

### 인덱스 목록 조회 도구
- ptyElasticGetIndexs: Elasticsearch 전체 인덱스 목록 조회 스크립트 추가
  - 인덱스별 상태, 문서 수, 용량, Health 상태 표시
  - 인덱스별 생성 시간 및 마지막 색인 시간 표시
  - 총 인덱스 수, 총 문서 수, 총 용량 요약 정보 제공
  - 설정 파일(~/.ptyElasticConfig.ini) 기반 접속 인증 지원

### 단일 인덱스 상세 조회 도구
- ptyElasticGetIndex: 특정 인덱스의 상세 정보 및 문서 조회 스크립트 추가
  - 인덱스 기본 정보(Health, Status, 샤드 수, 문서 수, 용량) 조회
  - 인덱스 설정(생성 날짜, UUID, 버전, 샤드 설정) 조회
  - 인덱스 통계(색인/검색 작업 수 및 소요 시간) 조회
  - 필드 매핑 정보(필드명 및 타입 목록) 조회
  - 검색어 기반 문서 조회 기능 (와일드카드 및 AND 연산 지원)
  - TOP 50 문서 샘플 조회 기능
  - 컬러 출력 지원(필드명, ID, URL 강조 표시)
parent 7e556677
This diff is collapsed.
#!/usr/bin/env php
<?php
/**
* ptyElasticgetIndexs
*
* Elasticsearch 인덱스 정보를 조회하는 도구
* 설정 파일: ~/.ptyElasticConfig.ini
*/
// 설정 파일 경로
$configFile = getenv('HOME') . '/.ptyElasticConfig.ini';
// 설정 파일 확인
if (!file_exists($configFile)) {
echo "Error: 설정 파일을 찾을 수 없습니다: $configFile\n";
echo "\n설정 파일 예시:\n";
echo "[elastic]\n";
echo "host=https://localhost:9200\n";
echo "user=elastic\n";
echo "password=yourpassword\n";
exit(1);
}
// 설정 파일 읽기
$config = parse_ini_file($configFile, true);
if (!isset($config['elastic'])) {
echo "Error: 설정 파일에 [elastic] 섹션이 없습니다.\n";
exit(1);
}
$elasticConfig = $config['elastic'];
$host = $elasticConfig['host'] ?? '';
$user = $elasticConfig['user'] ?? '';
$password = $elasticConfig['password'] ?? '';
if (empty($host)) {
echo "Error: host 설정이 필요합니다.\n";
exit(1);
}
// Elasticsearch API 호출
function callElasticAPI($url, $user, $password) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
if (!empty($user) && !empty($password)) {
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
$error = curl_error($ch);
curl_close($ch);
throw new Exception("cURL Error: $error");
}
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception("HTTP Error: $httpCode - $response");
}
return $response;
}
// 타임스탬프 형식 변환
function formatTimestamp($timestamp) {
// 밀리초 타임스탬프인 경우 (13자리 숫자)
if (is_numeric($timestamp) && strlen($timestamp) >= 13) {
$seconds = intval($timestamp / 1000);
return date('Y-m-d H:i:s', $seconds);
}
// 초 타임스탬프인 경우 (10자리 숫자)
if (is_numeric($timestamp) && strlen($timestamp) == 10) {
return date('Y-m-d H:i:s', intval($timestamp));
}
// 이미 문자열 형식인 경우
if (is_string($timestamp)) {
return substr($timestamp, 0, 19);
}
return $timestamp;
}
// 인덱스의 마지막 문서 시간 조회
function getLastDocumentTime($host, $user, $password, $indexName) {
try {
$searchUrl = rtrim($host, '/') . '/' . urlencode($indexName) . '/_search';
$searchBody = json_encode([
'size' => 1,
'sort' => [
['_index' => ['order' => 'desc']]
],
'query' => ['match_all' => (object)[]]
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $searchUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, $searchBody);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
if (!empty($user) && !empty($password)) {
curl_setopt($ch, CURLOPT_USERPWD, "$user:$password");
}
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (isset($data['hits']['hits'][0]['_source'])) {
$source = $data['hits']['hits'][0]['_source'];
// 일반적인 타임스탬프 필드 찾기
foreach (['@timestamp', 'timestamp', 'created_at', 'updated_at', 'date', 'createdAt', 'updatedAt'] as $field) {
if (isset($source[$field])) {
return formatTimestamp($source[$field]);
}
}
}
return 'N/A';
} catch (Exception $e) {
return 'N/A';
}
}
try {
// 인덱스 정보 조회 (_cat/indices API 사용)
$url = rtrim($host, '/') . '/_cat/indices?v&format=json&bytes=mb&h=index,status,docs.count,store.size,health,pri,rep,creation.date.string';
echo "Elasticsearch 인덱스 정보 조회 중...\n";
echo "Host: $host\n";
echo str_repeat("=", 80) . "\n\n";
$response = callElasticAPI($url, $user, $password);
$indices = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("JSON 파싱 오류: " . json_last_error_msg());
}
if (empty($indices)) {
echo "인덱스가 없습니다.\n";
exit(0);
}
// 결과 정렬 (인덱스 이름순)
usort($indices, function($a, $b) {
return strcmp($a['index'], $b['index']);
});
// 헤더 출력
printf("%-40s %-10s %-12s %-12s %-10s %-10s %-20s %-20s\n",
"INDEX", "STATUS", "DOCS.COUNT", "STORE.SIZE", "HEALTH", "PRI/REP", "CREATED", "LAST INDEXED");
echo str_repeat("-", 165) . "\n";
// 각 인덱스 정보 출력
$totalDocs = 0;
$totalSize = 0;
foreach ($indices as $index) {
$indexName = $index['index'] ?? 'N/A';
$status = $index['status'] ?? 'N/A';
$docsCount = $index['docs.count'] ?? '0';
$storeSize = $index['store.size'] ?? '0';
$health = $index['health'] ?? 'N/A';
$pri = $index['pri'] ?? '0';
$rep = $index['rep'] ?? '0';
$creationDate = $index['creation.date.string'] ?? 'N/A';
// 마지막 색인 시간 조회
$lastIndexed = 'N/A';
if ($docsCount !== '0' && is_numeric($docsCount)) {
$lastIndexed = getLastDocumentTime($host, $user, $password, $indexName);
}
// 숫자 형식 정리
$docsCount = is_numeric($docsCount) ? number_format($docsCount) : $docsCount;
// 용량 형식 정리 (234mb -> 234 MB)
$storeSizeFormatted = is_numeric($storeSize) ? number_format($storeSize, 2) . ' MB' : $storeSize;
printf("%-40s %-10s %-12s %-12s %-10s %-10s %-20s %-20s\n",
substr($indexName, 0, 40),
$status,
$docsCount,
$storeSizeFormatted,
$health,
$pri . '/' . $rep,
substr($creationDate, 0, 20),
substr($lastIndexed, 0, 20)
);
// 총합 계산
if (is_numeric($index['docs.count'] ?? null)) {
$totalDocs += intval($index['docs.count']);
}
if (is_numeric($index['store.size'] ?? null)) {
$totalSize += floatval($index['store.size']);
}
}
// 요약 정보 출력
echo str_repeat("=", 165) . "\n";
printf("총 인덱스 수: %d\n", count($indices));
printf("총 문서 수: %s\n", number_format($totalDocs));
printf("총 용량: %.2f MB (%.2f GB)\n", $totalSize, $totalSize / 1024);
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
exit(1);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment