in pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java [1012:1132]
private static void validateIndexingConfig(IndexingConfig indexingConfig, Schema schema) {
ArrayListMultimap<String, String> columnNameToConfigMap = ArrayListMultimap.create();
Set<String> noDictionaryColumnsSet = new HashSet<>();
if (indexingConfig.getNoDictionaryColumns() != null) {
for (String columnName : indexingConfig.getNoDictionaryColumns()) {
columnNameToConfigMap.put(columnName, "No Dictionary Column Config");
noDictionaryColumnsSet.add(columnName);
}
}
Set<String> bloomFilterColumns = new HashSet<>();
if (indexingConfig.getBloomFilterColumns() != null) {
bloomFilterColumns.addAll(indexingConfig.getBloomFilterColumns());
}
if (indexingConfig.getBloomFilterConfigs() != null) {
bloomFilterColumns.addAll(indexingConfig.getBloomFilterConfigs().keySet());
}
for (String bloomFilterColumn : bloomFilterColumns) {
columnNameToConfigMap.put(bloomFilterColumn, "Bloom Filter Config");
}
if (indexingConfig.getInvertedIndexColumns() != null) {
for (String columnName : indexingConfig.getInvertedIndexColumns()) {
if (noDictionaryColumnsSet.contains(columnName)) {
throw new IllegalStateException("Cannot create an Inverted index on column " + columnName
+ " specified in the noDictionaryColumns config");
}
columnNameToConfigMap.put(columnName, "Inverted Index Config");
}
}
if (indexingConfig.getOnHeapDictionaryColumns() != null) {
for (String columnName : indexingConfig.getOnHeapDictionaryColumns()) {
columnNameToConfigMap.put(columnName, "On Heap Dictionary Column Config");
}
}
if (indexingConfig.getRangeIndexColumns() != null) {
for (String columnName : indexingConfig.getRangeIndexColumns()) {
columnNameToConfigMap.put(columnName, "Range Column Config");
}
}
if (indexingConfig.getSortedColumn() != null) {
for (String columnName : indexingConfig.getSortedColumn()) {
columnNameToConfigMap.put(columnName, "Sorted Column Config");
}
}
if (indexingConfig.getVarLengthDictionaryColumns() != null) {
for (String columnName : indexingConfig.getVarLengthDictionaryColumns()) {
columnNameToConfigMap.put(columnName, "Var Length Column Config");
}
}
if (indexingConfig.getSegmentPartitionConfig() != null
&& indexingConfig.getSegmentPartitionConfig().getColumnPartitionMap() != null) {
for (String columnName : indexingConfig.getSegmentPartitionConfig().getColumnPartitionMap().keySet()) {
columnNameToConfigMap.put(columnName, "Segment Partition Config");
}
}
Set<String> jsonIndexColumns = new HashSet<>();
// Ignore jsonIndexColumns when jsonIndexConfigs is configured
if (indexingConfig.getJsonIndexConfigs() != null) {
jsonIndexColumns.addAll(indexingConfig.getJsonIndexConfigs().keySet());
} else {
if (indexingConfig.getJsonIndexColumns() != null) {
jsonIndexColumns.addAll(indexingConfig.getJsonIndexColumns());
}
}
for (String columnName : jsonIndexColumns) {
columnNameToConfigMap.put(columnName, "Json Index Config");
}
validateStarTreeIndexConfigs(indexingConfig, columnNameToConfigMap);
for (Map.Entry<String, String> entry : columnNameToConfigMap.entries()) {
String columnName = entry.getKey();
String configName = entry.getValue();
FieldSpec columnFieldSpec = schema.getFieldSpecFor(columnName);
Preconditions.checkState(columnFieldSpec != null,
"Column Name " + columnName + " defined in " + configName + " must be a valid column defined in the schema");
if (configName.equals(STAR_TREE_CONFIG_NAME)) {
Preconditions.checkState(columnFieldSpec.isSingleValueField(),
"Column Name " + columnName + " defined in " + configName + " must be a single value column");
}
}
// Range index semantic validation
// Range index can be defined on numeric columns and any column with a dictionary
if (indexingConfig.getRangeIndexColumns() != null) {
for (String rangeIndexCol : indexingConfig.getRangeIndexColumns()) {
Preconditions.checkState(
schema.getFieldSpecFor(rangeIndexCol).getDataType().isNumeric() || !noDictionaryColumnsSet.contains(
rangeIndexCol), "Cannot create a range index on non-numeric/no-dictionary column " + rangeIndexCol);
}
}
// Var length dictionary semantic validation
if (indexingConfig.getVarLengthDictionaryColumns() != null) {
for (String varLenDictCol : indexingConfig.getVarLengthDictionaryColumns()) {
FieldSpec varLenDictFieldSpec = schema.getFieldSpecFor(varLenDictCol);
switch (varLenDictFieldSpec.getDataType().getStoredType()) {
case STRING:
case BYTES:
continue;
default:
throw new IllegalStateException(
"var length dictionary can only be created for columns of type STRING and BYTES. Invalid for column "
+ varLenDictCol);
}
}
}
for (String bloomFilterColumn : bloomFilterColumns) {
Preconditions.checkState(schema.getFieldSpecFor(bloomFilterColumn).getDataType() != FieldSpec.DataType.BOOLEAN,
"Cannot create bloom filter on BOOLEAN column: " + bloomFilterColumn);
}
for (String jsonIndexColumn : jsonIndexColumns) {
FieldSpec fieldSpec = schema.getFieldSpecFor(jsonIndexColumn);
Preconditions.checkState(
fieldSpec.isSingleValueField() && fieldSpec.getDataType().getStoredType() == DataType.STRING,
"Json index can only be created for single value String column. Invalid for column: %s", jsonIndexColumn);
}
}