Opchain 변환기 플러그인
Opchain 변환기 플러그인 (Opchain Converter Plugin)
다중 스테이지 엔진 확장성을 위한 커스텀 OpChain 변환기를 구현하는 방법을 다루는 문서예요.
출처: 문서
본문
OpChainConverter SPI(서비스 제공자 인터페이스)는 플러그인 개발자가 다중 스테이지 쿼리 엔진에서 논리적 쿼리 계획을 실행 가능한 OpChain 객체로 변환하는 대체 구현을 제공하게 해줘요. 이는 대체 실행 백엔드(예: 시계열 엔진 같은 전문 실행 엔진 통합)용 확장성과 Pinot의 다중 스테이지 실행(MSE) 통합을 가능하게 해요.
왜 OpChain 변환기 SPI를 사용하나요? (Why Use OpChain Converter SPI?)
OpChainConverter SPI는 다음이 필요할 때 유용해요:
- 특정 실행 시나리오에서 대체 plan-to-OpChain 변환 로직 구현
- 커스텀 실행 백엔드를 다중 스테이지 엔진과 통합
- 전문 워크로드·하드웨어에 쿼리 실행 최적화
- 대체 쿼리 실행 전략 지원
OpChain 변환기 구현 (Implementing an OpChain Converter)
커스텀 OpChain 변환기를 만들려면 OpChainConverter 인터페이스를 구현해요:
package org.apache.pinot.query.runtime.operator;
public interface OpChainConverter {
/**
* Converts a logical plan node into an OpChain for execution.
*
* @param context the plan request context containing query metadata
* @param planNode the logical query plan node to convert
* @return an OpChain ready for execution, or null if this converter cannot handle this plan
*/
OpChain convert(PlanRequestContext context, PlanNode planNode);
/**
* Returns the priority of this converter. Higher priority converters are selected first.
* When multiple converters have the same priority, they are ordered by converter ID.
*
* @return the priority value (higher = higher priority)
*/
int priority();
/**
* Returns a unique identifier for this converter.
*
* @return the converter ID
*/
String getId();
}
OpChain 변환기 등록 (Registering Your OpChain Converter)
OpChainConverter 인터페이스를 구현했다면 Java의 ServiceLoader 메커니즘으로 등록해요:
- Google의
com.google.auto:auto-service라이브러리에서@AutoService어노테이션을 추가해요:
import com.google.auto.service.AutoService;
import org.apache.pinot.query.runtime.operator.OpChainConverter;
@AutoService(OpChainConverter.class)
public class CustomOpChainConverter implements OpChainConverter {
@Override
public OpChain convert(PlanRequestContext context, PlanNode planNode) {
// Implement your conversion logic here
// Return null if this converter cannot handle the plan
if (!canHandle(planNode)) {
return null;
}
return convertToOpChain(context, planNode);
}
@Override
public int priority() {
return 100; // Set your converter's priority
}
@Override
public String getId() {
return "custom-converter";
}
private boolean canHandle(PlanNode planNode) {
// Implement logic to determine if this converter can handle the plan
return true;
}
private OpChain convertToOpChain(PlanRequestContext context, PlanNode planNode) {
// Implement your conversion logic
return null;
}
}
- JAR에
META-INF/services/org.apache.pinot.query.runtime.operator.OpChainConverter에 ServiceLoader 구성 파일을 만들어요:
com.example.CustomOpChainConverter
우선순위와 선택 (Priority and Selection)
OpChainConverterDispatcher는 등록된 모든 변환기를 관리하고 다음을 기준으로 활성 변환기를 선택해요:
- 우선순위 (Priority): 더 높은 우선순위 값이 먼저 평가됨
- 동점 처리 (Tie-breaking): 여러 변환기의 우선순위가 같으면 변환기 ID로 정렬(알파벳순)
- 명시적 오버라이드 (Explicit override):
OpChainConverterDispatcher.setActiveConverterIdOverride(String converterId)로 활성 변환기를 명시적으로 설정 가능
예시: 커스텀 변환기 구현 (Example: Custom Converter Implementation)
특정 플랜 노드 유형을 처리하는 커스텀 OpChain 변환기의 완전한 예시예요:
import com.google.auto.service.AutoService;
import org.apache.pinot.query.planner.PlanNode;
import org.apache.pinot.query.runtime.operator.OpChain;
import org.apache.pinot.query.runtime.operator.OpChainConverter;
import org.apache.pinot.query.runtime.plan.PlanRequestContext;
@AutoService(OpChainConverter.class)
public class TimeSeriesOpChainConverter implements OpChainConverter {
private static final String CONVERTER_ID = "timeseries-converter";
private static final int PRIORITY = 50;
@Override
public OpChain convert(PlanRequestContext context, PlanNode planNode) {
// Check if this is a time-series query that we can optimize
if (!isTimeSeriesQuery(planNode)) {
return null;
}
// Perform custom conversion optimized for time-series execution
return optimizeTimeSeriesExecution(context, planNode);
}
@Override
public int priority() {
return PRIORITY;
}
@Override
public String getId() {
return CONVERTER_ID;
}
private boolean isTimeSeriesQuery(PlanNode planNode) {
// Implement logic to detect time-series queries
// For example, check for time-based aggregations, windowing, etc.
return false;
}
private OpChain optimizeTimeSeriesExecution(PlanRequestContext context, PlanNode planNode) {
// Implement time-series-specific optimization logic
return null;
}
}
기본 구현 (Default Implementation)
Pinot는 기존 PlanNodeToOpChain 변환기에 위임하는 DefaultOpChainConverter를 포함해요. 이 변환기는 가장 낮은 우선순위를 가지며, 다른 변환기가 쿼리 계획을 처리할 수 없을 때 폴백 역할을 해요.
OpChain 변환기 테스트 (Testing Your OpChain Converter)
OpChain 변환기를 테스트할 때:
OpChainConverter인터페이스를 제대로 구현했는지 확인- 설계된 쿼리 계획 유형을 올바르게 처리하는지 테스트
null반환이 다음 변환기로 우아하게 위임되는지 확인- 여러 변환기가 있을 때 우선순위 기반 선택을 테스트
- 명시적 오버라이드 기능이 올바르게 동작하는지 확인