쿼리 응답 형식
쿼리 응답 형식 (Query Response Format)
Pinot 브로커 응답 페이로드 레퍼런스를 다루는 문서예요. Pinot 쿼리 응답은 주변에 소수의 실행 통계를 감싼 SQL 유사 표 형식 페이로드예요. 쿼리 동작을 디버깅하거나 대형 결과를 페이지네이션할 때 가장 자주 살펴볼 필드를 문서화해요.
출처: 문서
본문
Pinot 쿼리 응답은 소수의 실행 통계를 둘러싼 SQL 유사 표 형식 페이로드예요. 이 페이지는 쿼리 동작을 디버깅하거나 대형 결과를 페이지네이션할 때 가장 자주 검사할 필드를 문서화해요.
응답 형태 (Response Shape)
표준 브로커 쿼리 응답은 다음을 포함한 resultTable을 가져요:
| 필드 | 의미 |
|---|---|
resultTable.dataSchema.columnNames |
쿼리가 반환한 이름 |
resultTable.dataSchema.columnDataTypes |
반환된 각 컬럼의 데이터 타입 |
resultTable.rows |
컬럼 순서대로의 행 값 |
커서 기반 응답도 동일한 resultTable 형태를 사용하지만, rows 배열에는 현재 페이지만 담겨 있어요.
커서 필드 (Cursor Fields)
쿼리가 getCursor=true로 제출되면 Pinot는 일반 브로커 응답 주위에 커서 메타데이터를 추가해요:
| 필드 | 의미 |
|---|---|
requestId |
/responseStore/{requestId}와 함께 사용하는 커서 식별자 |
numRowsResultSet |
전체 결과 집합에 걸친 총 사용 가능 행 수 |
offset |
현재 페이지의 0 기반 오프셋 |
numRows |
현재 페이지에 반환된 행 수 |
brokerHost |
응답 저장소를 소유한 브로커 호스트 |
brokerPort |
응답 저장소를 소유한 브로커 포트 |
submissionTimeMs |
Pinot가 응답 저장소 항목을 만든 타임스탬프 |
expirationTimeMs |
Pinot가 커서가 만료됐다고 간주하는 타임스탬프 |
cursorResultWriteTimeMs |
원본 결과를 응답 저장소에 쓰는 데 걸린 시간; 일반적으로 커서를 만드는 최초 응답에 채워짐 |
cursorFetchTimeMs |
응답 저장소에서 현재 페이지를 읽는 데 걸린 시간 |
bytesWritten |
저장된 결과의 직렬화 크기 |
실행 통계 (Execution Stats)
| 필드 | 의미 |
|---|---|
timeUsedMs |
브로커 측에서 쿼리를 처리하는 데 걸린 시간 |
numServersQueried |
쿼리 처리를 요청받은 서버 수 |
numServersResponded |
응답을 반환한 서버 수 |
numSegmentsQueried |
쿼리에 고려된 세그먼트 수 |
numSegmentsProcessed |
실제로 처리된 세그먼트 수 |
numSegmentsMatched |
일치가 하나 이상인 세그먼트 수 |
numDocsScanned |
필터링 후 선택된 문서 수 |
numEntriesScannedInFilter |
필터 단계에서 스캔된 항목 |
numEntriesScannedPostFilter |
필터 후 단계에서 스캔된 항목 |
partialResult |
Pinot가 완전한 답 대신 부분 결과를 반환했는지 여부. MSE Lite 쿼리의 경우 mseLiteLeafStageLimitReached=true일 때 이 값도 true가 돼요. |
mseLiteLeafStageLimitReached |
다중 스테이지 Lite 모드 플래그로, Pinot가 적어도 한 워커에서 브로커 주입 암시적 리프 스테이지 제한에 도달했음을 나타냄. true면 응답이 잘리고 partialResult도 true예요. |
mseLiteLeafStageEffectiveLimit |
Pinot가 암시적 리프 스테이지 제한을 주입한 MSE Lite 쿼리의 경우, Pinot가 강제한 워커당 유효 제한 |
mseLiteFanOutAdjustedLimitApplied |
Pinot가 암시적 리프 스테이지 제한을 주입한 MSE Lite 쿼리의 경우, 유효 제한이 기본 liteModeLeafStageLimit 대신 liteModeLeafStageFanOutAdjustedLimit에서 나왔는지 여부 |
earlyTerminationReasons |
DISTINCT_MAX_ROWS 같은 조기 종료 이유를 나열하는 다중 스테이지 V2 응답 필드 |
maxRowsInDistinctReached |
maxRowsInDistinct 예산을 초과했음을 나타내는 단일 스테이지 DISTINCT 플래그 |
maxRowsWithoutChangeInDistinctReached |
maxRowsWithoutChangeInDistinct 예산을 초과했음을 나타내는 단일 스테이지 DISTINCT 플래그 |
maxExecutionTimeInDistinctReached |
maxExecutionTimeMsInDistinct 예산을 초과했음을 나타내는 단일 스테이지 DISTINCT 플래그 |
numGroupsLimitReached |
group-by 트리밍이 제한에 도달했는지 여부 |
numGroupsWarningLimitReached |
group-by 실행이 그룹 수에 대한 구성된 경고 임계값을 넘었는지 여부 |
serverStats |
단일 스테이지 서버별 타이밍·응답 크기 분해 |
stageStats |
다중 스테이지 쿼리의 스테이지별 통계 |
exceptions |
쿼리 처리 예외(있을 경우) |
rlsFiltersApplied |
행 수준 보안(row-level security) 프레디킷이 주입됐는지 여부 |
responseMetadata |
확장 정의 비치명 쿼리 메타데이터를 포함하는 선택적 다중 스테이지 V2 객체. 값은 JSON 타입을 유지하며, 비어 있으면 필드가 생략돼요. |
DISTINCT 조기 종료의 경우 응답 형태는 엔진에 따라 달라져요. 단일 스테이지 응답은 maxRowsInDistinctReached 같은 레거시 부울 필드를 사용하는 반면, 다중 스테이지 V2 응답은 동일한 조건을 partialResult=true와 earlyTerminationReasons를 통해 드러내요.
Lite Mode 경고 필드는 다중 스테이지 V2 응답에만 해당해요. mseLiteLeafStageLimitReached는 항상 부울로 존재하지만, mseLiteLeafStageEffectiveLimit와 mseLiteFanOutAdjustedLimitApplied는 Pinot가 실제로 해당 쿼리에서 암시적 리프 스테이지 제한을 주입했을 때만 나타나요. 따라서 응답은 유효 제한을 표시하면서도 mseLiteLeafStageLimitReached=false일 수 있는데, 이는 보호 장치(guardrail)가 활성화됐지만 해당 실행을 잘라내지 않았다는 뜻이에요.
확장 응답 메타데이터 (Extension response metadata)
다중 스테이지 V2 응답은 브로커 측 확장의 정보성 메모(예: 폴백 적용 여부)를 위한 responseMetadata 객체를 포함할 수 있어요. 핵심 Pinot는 이 객체에 대한 안정적인 키나 의미를 정의하지 않으므로, 클라이언트는 모든 항목을 확장별로 취급하고 알 수 없는 키를 허용해야 해요. 값은 JSON 타입을 유지하며 문자열뿐 아니라 스칼라, 객체, 배열일 수 있어요.
{
"resultTable": { "...": "..." },
"numDocsScanned": 12345,
"timeUsedMs": 42,
"responseMetadata": {
"fallbackApplied": true,
"note": "served from cache",
"detail": { "stage": 2, "strategy": "broadcast" }
}
}
현재 브로커 측 다중 스테이지 쿼리 처리만이 응답에 메타데이터를 기여할 수 있어요. 워커나 서버에 등록된 메타데이터는 브로커 응답에 전파되지 않아요. 항목이 추가되지 않으면 Pinot는 responseMetadata를 완전히 생략해요.
단일 스테이지 쿼리의 경우 serverStats는 헤더 행 뒤에 서버별 항목 하나가 오는 세미콜론으로 구분된 문자열이에요. 헤더는 순서대로 메트릭 이름을 지정해요:
Server=SubmitDelayMs,ResponseDelayMs,ResponseSize,DeserializationTimeMs,RequestSentDelayMs;pinot-server-0_O=0,1,7571,0,0
이는 어느 단일 스테이지 서버가 느리게 응답했는지 또는 예상치 못하게 큰 페이로드를 반환했는지 정확히 짚어내는 데 유용한 가벼운 브로커 응답 필드로 serverStats를 쓸 수 있게 해줘요.
예시 (Example)
curl -H "Content-Type: application/json" -X POST \
-d '{"sql":"SELECT moo, bar, foo FROM myTable ORDER BY foo DESC"}' \
http://localhost:8099/query/sql
커서 예시:
curl -H "Content-Type: application/json" -X POST \
-d '{"sql":"SELECT * FROM myTable LIMIT 100000"}' \
'http://localhost:8099/query/sql?getCursor=true&numRows=1000'
이 페이지에서 다룬 내용 (What this page covered)
- Pinot 브로커 응답의 구조
- 성능이나 정확성을 디버깅할 때 가장 중요한 실행 통계
- 일반 결과와 다중 스테이지 쿼리 응답 사이에서 다른 필드
다음 단계 (Next step)
필드 이름은 맞는데 데이터가 안 맞다면, 다음으로 쿼리 계획과 응답 저장소 흐름을 검사해 보세요.