cshuo commented on code in PR #18372:
URL: https://github.com/apache/hudi/pull/18372#discussion_r3542065549


##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metadata/index/columnstats/ColumnStatsIndexer.java:
##########
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.metadata.index.columnstats;
+
+import org.apache.hudi.avro.model.HoodieCleanMetadata;
+import org.apache.hudi.common.config.HoodieMetadataConfig;
+import org.apache.hudi.common.data.HoodieData;
+import org.apache.hudi.common.engine.HoodieEngineContext;
+import org.apache.hudi.metadata.model.FileInfo;
+import org.apache.hudi.common.model.HoodieCommitMetadata;
+import org.apache.hudi.common.model.HoodieWriteStat;
+import org.apache.hudi.common.schema.HoodieSchema;
+import org.apache.hudi.common.table.view.HoodieTableFileSystemView;
+import org.apache.hudi.common.util.collection.Pair;
+import org.apache.hudi.exception.HoodieException;
+import org.apache.hudi.metadata.HoodieBackedTableMetadata;
+import org.apache.hudi.metadata.HoodieIndexVersion;
+import org.apache.hudi.metadata.HoodieMetadataPayload;
+import org.apache.hudi.metadata.index.model.IndexPartitionAndRecords;
+import org.apache.hudi.metadata.model.FileSliceAndPartition;
+import org.apache.hudi.common.model.HoodieIndexDefinition;
+import org.apache.hudi.common.model.HoodieRecord;
+import org.apache.hudi.metadata.index.model.IndexPartitionInitialization;
+import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.util.Option;
+import org.apache.hudi.config.HoodieWriteConfig;
+import org.apache.hudi.metadata.HoodieTableMetadataUtil;
+import org.apache.hudi.metadata.MetadataPartitionType;
+import org.apache.hudi.metadata.index.BaseIndexer;
+import org.apache.hudi.stats.HoodieColumnRangeMetadata;
+import org.apache.hudi.util.Lazy;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.apache.hudi.common.fs.FSUtils.getFileNameFromPath;
+import static org.apache.hudi.index.HoodieIndexUtils.register;
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.PARTITION_NAME_COLUMN_STATS;
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.existingIndexVersionOrDefault;
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.getColumnStatsRecords;
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.getColumnsToIndex;
+import static org.apache.hudi.metadata.MetadataPartitionType.COLUMN_STATS;
+
+/**
+ * Implementation of {@link MetadataPartitionType#COLUMN_STATS} metadata
+ */
+@Slf4j
+public class ColumnStatsIndexer extends BaseIndexer {
+  private final Lazy<List<String>> columnsToIndex;
+
+  public ColumnStatsIndexer(HoodieEngineContext engineContext,
+                               HoodieWriteConfig dataTableWriteConfig,
+                               HoodieTableMetaClient dataTableMetaClient) {
+    super(engineContext, dataTableWriteConfig, dataTableMetaClient);
+
+    this.columnsToIndex = Lazy.lazily(() ->
+        new ArrayList<>(getColumnsToIndex(
+            dataTableMetaClient.getTableConfig(),
+            dataTableWriteConfig.getMetadataConfig(),
+            Lazy.lazily(() -> 
HoodieTableMetadataUtil.tryResolveSchemaForTable(dataTableMetaClient)),
+            true,
+            Option.of(dataTableWriteConfig.getRecordMerger().getRecordType()),
+            existingIndexVersionOrDefault(PARTITION_NAME_COLUMN_STATS, 
dataTableMetaClient)).keySet()));
+  }
+
+  @Override
+  public List<IndexPartitionInitialization> buildInitialization(
+      String dataTableInstantTime,
+      String instantTimeForPartition,
+      Map<String, List<FileInfo>> partitionToAllFilesMap,
+      Lazy<List<FileSliceAndPartition>> lazyPartitionFileSlices) throws 
IOException {
+    final int fileGroupCount = 
dataTableWriteConfig.getMetadataConfig().getColumnStatsIndexFileGroupCount();
+    // columnsToIndex can be empty if meta fields are disabled and cols to 
index is not explicitly overridden.
+    if (partitionToAllFilesMap.isEmpty() || columnsToIndex.get().isEmpty()) {
+      return 
Collections.singletonList(IndexPartitionInitialization.of(fileGroupCount, 
COLUMN_STATS.getPartitionPath(), engineContext.emptyHoodieData()));
+    }
+
+    log.info("Indexing {} columns for column stats index", 
columnsToIndex.get().size());
+    // during initialization, we need stats for base and log files.
+    HoodieData<HoodieRecord> records = 
HoodieTableMetadataUtil.convertFilesToColumnStatsRecords(
+        engineContext, Collections.emptyMap(), partitionToAllFilesMap,
+        dataTableMetaClient, 
dataTableWriteConfig.getColumnStatsIndexParallelism(),
+        dataTableWriteConfig.getMetadataConfig().getMaxReaderBufferSize(),
+        columnsToIndex.get());
+    return 
Collections.singletonList(IndexPartitionInitialization.of(fileGroupCount, 
COLUMN_STATS.getPartitionPath(), records));
+  }
+
+  @Override
+  public List<IndexPartitionAndRecords> buildUpdate(
+      String instantTime,
+      HoodieBackedTableMetadata tableMetadata,
+      Lazy<HoodieTableFileSystemView> lazyFileSystemView,
+      HoodieCommitMetadata commitMetadata) {
+    final HoodieData<HoodieRecord> records = 
convertMetadataToColumnStatsRecords(commitMetadata, engineContext,
+        dataTableMetaClient, dataTableWriteConfig.getMetadataConfig(), 
Option.of(dataTableWriteConfig.getRecordMerger().getRecordType()));
+    return 
Collections.singletonList(IndexPartitionAndRecords.of(COLUMN_STATS.getPartitionPath(),
 records));
+  }
+
+  @Override
+  public List<IndexPartitionAndRecords> buildClean(String instantTime, 
HoodieCleanMetadata cleanMetadata) {
+    final HoodieData<HoodieRecord> records =
+        convertMetadataToColumnStatsRecords(cleanMetadata, engineContext, 
dataTableMetaClient,
+            dataTableWriteConfig.getMetadataConfig(), 
Option.of(dataTableWriteConfig.getRecordMerger().getRecordType()));
+    return 
Collections.singletonList(IndexPartitionAndRecords.of(COLUMN_STATS.getPartitionPath(),
 records));
+  }
+
+  @Override
+  public List<IndexPartitionAndRecords> buildRestore(String instantTime, 
List<String> deletedPartitions, Map<String, List<FileInfo>> filesAdded, 
Map<String, List<String>> filesDeleted) {
+    if (filesDeleted.isEmpty() && filesAdded.isEmpty()) {
+      return Collections.emptyList();
+    }
+    Lazy<Option<HoodieSchema>> tableSchema =
+        Lazy.lazily(() -> 
HoodieTableMetadataUtil.tryResolveSchemaForTable(dataTableMetaClient));
+    final List<String> columnsToIndex = new 
ArrayList<>(HoodieTableMetadataUtil.getColumnsToIndex(

Review Comment:
   Fixed.



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metadata/index/expression/ExpressionIndexer.java:
##########
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.metadata.index.expression;
+
+import org.apache.hudi.avro.model.HoodieCleanMetadata;
+import org.apache.hudi.common.config.HoodieMetadataConfig;
+import org.apache.hudi.common.data.HoodieData;
+import org.apache.hudi.common.engine.HoodieEngineContext;
+import org.apache.hudi.common.model.HoodieCommitMetadata;
+import org.apache.hudi.common.model.HoodieIndexDefinition;
+import org.apache.hudi.common.model.HoodieIndexMetadata;
+import org.apache.hudi.common.model.HoodieRecord;
+import org.apache.hudi.common.table.view.HoodieTableFileSystemView;
+import org.apache.hudi.common.util.Option;
+import org.apache.hudi.metadata.HoodieBackedTableMetadata;
+import org.apache.hudi.metadata.index.ExpressionIndexRecordGenerator;
+import org.apache.hudi.metadata.model.FileInfo;
+import org.apache.hudi.metadata.index.bloomfilters.BloomFiltersIndexer;
+import org.apache.hudi.metadata.index.columnstats.ColumnStatsIndexer;
+import org.apache.hudi.metadata.index.model.IndexPartitionAndRecords;
+import org.apache.hudi.metadata.model.FileSliceAndPartition;
+import org.apache.hudi.metadata.model.FileInfoAndPartition;
+import org.apache.hudi.metadata.index.model.IndexPartitionInitialization;
+import org.apache.hudi.common.schema.HoodieSchema;
+import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.util.ValidationUtils;
+import org.apache.hudi.config.HoodieWriteConfig;
+import org.apache.hudi.exception.HoodieMetadataException;
+import org.apache.hudi.metadata.HoodieTableMetadataUtil;
+import org.apache.hudi.metadata.MetadataPartitionType;
+import org.apache.hudi.metadata.index.BaseIndexer;
+import org.apache.hudi.util.Lazy;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.PARTITION_NAME_BLOOM_FILTERS;
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.PARTITION_NAME_COLUMN_STATS;
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.getExpressionIndexPartitionsToInit;
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.getProjectedSchemaForExpressionIndex;
+import static org.apache.hudi.metadata.MetadataPartitionType.EXPRESSION_INDEX;
+import static org.apache.hudi.metadata.MetadataPartitionType.fromPartitionPath;
+
+/**
+ * Implementation of {@link MetadataPartitionType#EXPRESSION_INDEX} index
+ */
+@Slf4j
+public class ExpressionIndexer extends BaseIndexer {
+
+  private final ExpressionIndexRecordGenerator expressionIndexRecordGenerator;
+
+  public ExpressionIndexer(
+      HoodieEngineContext engineContext,
+      HoodieWriteConfig dataTableWriteConfig,
+      HoodieTableMetaClient dataTableMetaClient,
+      ExpressionIndexRecordGenerator expressionIndexRecordGenerator) {
+    super(engineContext, dataTableWriteConfig, dataTableMetaClient);
+
+    this.expressionIndexRecordGenerator = expressionIndexRecordGenerator;
+  }
+
+  @Override
+  public List<IndexPartitionInitialization> buildInitialization(
+      String dataTableInstantTime,
+      String instantTimeForPartition,
+      Map<String, List<FileInfo>> partitionToAllFilesMap,
+      Lazy<List<FileSliceAndPartition>> lazyPartitionFileSlices) throws 
IOException {
+    Set<String> expressionIndexPartitionsToInit = 
getExpressionIndexPartitionsToInit(
+        EXPRESSION_INDEX, dataTableWriteConfig.getMetadataConfig(), 
dataTableMetaClient);
+    if (expressionIndexPartitionsToInit.size() != 1) {
+      if (expressionIndexPartitionsToInit.size() > 1) {
+        log.warn("Skipping expression index initialization as only one 
expression index "
+            + "bootstrap at a time is supported for now. Provided: {}", 
expressionIndexPartitionsToInit);
+      }
+      return Collections.emptyList();
+    }
+
+    String indexName = expressionIndexPartitionsToInit.iterator().next();
+    HoodieIndexDefinition indexDefinition = 
HoodieTableMetadataUtil.getHoodieIndexDefinition(indexName, 
dataTableMetaClient);
+    ValidationUtils.checkState(indexDefinition != null, "Expression Index 
definition is not present for index " + indexName);
+
+    List<FileSliceAndPartition> partitionFileSlicePairs = 
lazyPartitionFileSlices.get();
+    List<FileInfoAndPartition> filesToIndex = new ArrayList<>();
+    partitionFileSlicePairs.forEach(fsp -> {
+      if (fsp.fileSlice().getBaseFile().isPresent()) {
+        filesToIndex.add(FileInfoAndPartition.of(fsp.partitionPath(), 
fsp.fileSlice().getBaseFile().get().getPath(), 
fsp.fileSlice().getBaseFile().get().getFileSize()));
+      }
+      fsp.fileSlice().getLogFiles()
+          .forEach(hoodieLogFile
+              -> filesToIndex.add(FileInfoAndPartition.of(fsp.partitionPath(), 
hoodieLogFile.getPath().toString(), hoodieLogFile.getFileSize())));
+    });
+
+    int fileGroupCount = 
dataTableWriteConfig.getMetadataConfig().getExpressionIndexFileGroupCount();
+    if (filesToIndex.isEmpty()) {
+      return 
Collections.singletonList(IndexPartitionInitialization.of(fileGroupCount, 
indexName, engineContext.emptyHoodieData()));
+    }
+
+    int parallelism = Math.min(filesToIndex.size(), 
dataTableWriteConfig.getMetadataConfig().getExpressionIndexParallelism());
+    HoodieSchema tableSchema =
+        HoodieTableMetadataUtil.tryResolveSchemaForTable(dataTableMetaClient)
+            .orElseThrow(() -> new HoodieMetadataException("Table schema is 
not available for expression index initialization"));
+    HoodieSchema readerSchema = 
getProjectedSchemaForExpressionIndex(indexDefinition, dataTableMetaClient, 
tableSchema);
+
+    HoodieData<HoodieRecord> records = 
expressionIndexRecordGenerator.buildInitialization(
+        filesToIndex, indexDefinition, dataTableMetaClient, parallelism,
+        tableSchema, readerSchema, engineContext.getStorageConf(), 
dataTableInstantTime);
+
+    return 
Collections.singletonList(IndexPartitionInitialization.of(fileGroupCount, 
indexName, records));
+  }
+
+  @Override
+  public List<IndexPartitionAndRecords> buildUpdate(String instantTime, 
HoodieBackedTableMetadata tableMetadata, Lazy<HoodieTableFileSystemView> 
lazyFileSystemView,
+                                                    HoodieCommitMetadata 
commitMetadata) {
+    if 
(!MetadataPartitionType.EXPRESSION_INDEX.isMetadataPartitionAvailable(dataTableMetaClient))
 {
+      log.info("Don't need to update expression index, since no expression 
index is available");
+      return Collections.emptyList();
+    }
+    return dataTableMetaClient.getTableConfig().getMetadataPartitions()
+        .stream()
+        .filter(partition -> 
partition.startsWith(HoodieTableMetadataUtil.PARTITION_NAME_EXPRESSION_INDEX_PREFIX))
+        .map(partition -> {
+          HoodieData<HoodieRecord> expressionIndexRecords;
+          try {
+            expressionIndexRecords = 
expressionIndexRecordGenerator.buildUpdate(dataTableMetaClient, tableMetadata, 
commitMetadata, partition, instantTime);
+          } catch (Exception e) {
+            throw new HoodieMetadataException(String.format("Failed to get 
expression index updates for partition %s", partition), e);
+          }
+          return IndexPartitionAndRecords.of(partition, 
expressionIndexRecords);
+        }).collect(Collectors.toList());
+  }
+
+  @Override
+  public List<IndexPartitionAndRecords> buildClean(String instantTime, 
HoodieCleanMetadata cleanMetadata) {
+    Option<HoodieIndexMetadata> indexMetadata = 
dataTableMetaClient.getIndexMetadata();
+    if (indexMetadata.isEmpty()) {
+      throw new HoodieMetadataException("Expression index metadata not found");
+    }
+    List<IndexPartitionAndRecords> indexRecordsList = new ArrayList<>();
+    HoodieIndexMetadata metadata = indexMetadata.get();
+    Map<String, HoodieIndexDefinition> indexDefinitions = 
metadata.getIndexDefinitions();
+    if (indexDefinitions.isEmpty()) {
+      throw new HoodieMetadataException("Expression index metadata not found");

Review Comment:
   Fixed.



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metadata/index/record/PartitionedRecordIndexer.java:
##########
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.metadata.index.record;
+
+import org.apache.hudi.common.engine.HoodieEngineContext;
+import org.apache.hudi.metadata.MetadataPartitionType;
+import org.apache.hudi.metadata.index.model.DataPartitionAndRecords;
+import org.apache.hudi.metadata.model.FileInfo;
+import org.apache.hudi.metadata.model.FileSliceAndPartition;
+import org.apache.hudi.metadata.index.model.IndexPartitionInitialization;
+import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.util.ValidationUtils;
+import org.apache.hudi.config.HoodieWriteConfig;
+import org.apache.hudi.index.record.HoodieRecordIndex;
+import org.apache.hudi.metadata.BucketizedMetadataTableFileGroupIndexParser;
+import org.apache.hudi.util.Lazy;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import static 
org.apache.hudi.metadata.HoodieTableMetadataUtil.createRecordIndexDefinition;
+import static org.apache.hudi.metadata.MetadataPartitionType.RECORD_INDEX;
+
+/**
+ * Implementation of the partitioned {@link 
MetadataPartitionType#RECORD_INDEX} index
+ */
+@Slf4j
+public class PartitionedRecordIndexer extends BaseRecordIndexer {
+  public PartitionedRecordIndexer(HoodieEngineContext engineContext, 
HoodieWriteConfig dataTableWriteConfig,
+                                     HoodieTableMetaClient 
dataTableMetaClient) {
+    super(engineContext, dataTableWriteConfig, dataTableMetaClient);
+  }
+
+  @Override
+  public List<IndexPartitionInitialization> buildInitialization(String 
dataTableInstantTime, String instantTimeForPartition, Map<String, 
List<FileInfo>> partitionToAllFilesMap,
+                                                                
Lazy<List<FileSliceAndPartition>> lazyPartitionFileSlices) throws IOException {
+    createRecordIndexDefinition(dataTableMetaClient, 
Collections.singletonMap(HoodieRecordIndex.IS_PARTITIONED_OPTION, "true"));
+    Map<String, List<FileSliceAndPartition>> partitionFileSlicePairsMap = 
lazyPartitionFileSlices.get().stream()
+        .collect(Collectors.groupingBy(FileSliceAndPartition::partitionPath));
+    Map<String, DataPartitionAndRecords> fileGroupCountAndRecordsPairMap = new 
HashMap<>(partitionFileSlicePairsMap.size());

Review Comment:
   Fixed.



##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/metadata/index/UnsupportedEngineIndexerSupport.java:
##########
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.metadata.index;
+
+import org.apache.hudi.common.data.HoodieData;
+import org.apache.hudi.common.engine.EngineType;
+import org.apache.hudi.common.model.HoodieCommitMetadata;
+import org.apache.hudi.common.model.HoodieIndexDefinition;
+import org.apache.hudi.common.model.HoodieRecord;
+import org.apache.hudi.common.schema.HoodieSchema;
+import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.table.HoodieTableVersion;
+import org.apache.hudi.exception.HoodieNotSupportedException;
+import org.apache.hudi.metadata.HoodieTableMetadata;
+import org.apache.hudi.metadata.model.FileInfoAndPartition;
+import org.apache.hudi.storage.StorageConfiguration;
+
+import java.util.List;
+
+/**
+ * Fallback {@link ExpressionIndexRecordGenerator} that throws a not-supported 
exception
+ * when expression index bootstrap is requested for unsupported engines.
+ */
+public class UnsupportedExpressionIndexRecordGenerator implements 
ExpressionIndexRecordGenerator {
+
+  private final EngineType engineType;
+
+  public UnsupportedExpressionIndexRecordGenerator(EngineType engineType) {
+    this.engineType = engineType;
+  }
+
+  @Override
+  public EngineType getEngineType() {
+    return engineType;
+  }
+
+  @Override
+  public HoodieData<HoodieRecord> buildInitialization(
+      List<FileInfoAndPartition> filesToIndex,
+      HoodieIndexDefinition indexDefinition,
+      HoodieTableMetaClient metaClient,
+      int parallelism,
+      HoodieSchema tableSchema,
+      HoodieSchema readerSchema,
+      StorageConfiguration<?> storageConf,
+      String instantTime) {
+    if 
(metaClient.getTableConfig().getTableVersion().lesserThan(HoodieTableVersion.EIGHT))
 {
+      throw new HoodieNotSupportedException("Table version 6 and below does 
not support expression index");
+    }
+    throw new HoodieNotSupportedException(engineType + " engine does not 
support building expression index yet");
+  }
+
+  @Override
+  public HoodieData<HoodieRecord> buildUpdate(
+      HoodieTableMetaClient metaClient,
+      HoodieTableMetadata tableMetadata,
+      HoodieCommitMetadata commitMetadata,
+      String indexPartition,
+      String instantTime) {
+    if 
(metaClient.getTableConfig().getTableVersion().lesserThan(HoodieTableVersion.EIGHT))
 {
+      throw new HoodieNotSupportedException("Table version 6 and below does 
not support expression index");
+    }
+    throw new HoodieNotSupportedException(engineType + " engine does not 
support building expression index yet");

Review Comment:
   Fixed.



##########
hudi-common/src/main/java/org/apache/hudi/metadata/model/DirectoryInfo.java:
##########
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hudi.metadata.model;
+
+import org.apache.hudi.common.fs.FSUtils;
+import org.apache.hudi.common.model.HoodiePartitionMetadata;
+import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.util.collection.Pair;
+import org.apache.hudi.metadata.HoodieTableMetadataUtil;
+import org.apache.hudi.storage.StoragePath;
+import org.apache.hudi.storage.StoragePathInfo;
+
+import lombok.Getter;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static 
org.apache.hudi.common.table.timeline.InstantComparison.LESSER_THAN_OR_EQUALS;
+import static 
org.apache.hudi.common.table.timeline.InstantComparison.compareTimestamps;
+
+/**
+ * A class which represents a directory and the files and directories inside 
it.
+ * <p>
+ * A {@code PartitionFileInfo} object saves the name of the partition and 
various properties requires of each file
+ * required for initializing the metadata table. Saving limited properties 
reduces the total memory footprint when
+ * a very large number of files are present in the dataset being initialized.
+ */
+@Getter
+public class DirectoryInfo implements Serializable {
+
+  // Relative path of the directory (relative to the base directory)
+  private final String relativePath;
+  // Map of filenames within this partition to their respective sizes
+  private final Map<String, Long> filenameToSizeMap;
+  // List of directories within this partition
+  private final List<StoragePath> subDirectories = new ArrayList<>();
+  // Is this a hoodie partition
+  private boolean isHoodiePartition = false;
+
+  public DirectoryInfo(String relativePath, List<StoragePathInfo> pathInfos, 
String maxInstantTime, Set<String> pendingDataInstants) {
+    this(relativePath, pathInfos, maxInstantTime, pendingDataInstants, true);
+  }
+
+  /**
+   * When files are directly fetched from Metadata table we do not need to 
validate HoodiePartitions.
+   */
+  public DirectoryInfo(String relativePath, List<StoragePathInfo> pathInfos, 
String maxInstantTime, Set<String> pendingDataInstants,
+                       boolean validateHoodiePartitions) {
+    this.relativePath = relativePath;
+
+    // Pre-allocate with the maximum length possible
+    filenameToSizeMap = new HashMap<>(pathInfos.size());
+
+    // Presence of partition meta file implies this is a HUDI partition
+    // if input files are directly fetched from MDT, it may not contain the 
HoodiePartitionMetadata file. So, we can ignore the validation for 
isHoodiePartition.
+    isHoodiePartition = !validateHoodiePartitions || 
pathInfos.stream().anyMatch(status -> 
status.getPath().getName().startsWith(HoodiePartitionMetadata.HOODIE_PARTITION_METAFILE_PREFIX));
+    for (StoragePathInfo pathInfo : pathInfos) {
+      // Do not attempt to search for more subdirectories inside directories 
that are partitions
+      if (!isHoodiePartition && pathInfo.isDirectory()) {
+        // Ignore .hoodie directory as there cannot be any partitions inside it
+        if 
(!pathInfo.getPath().getName().equals(HoodieTableMetaClient.METAFOLDER_NAME)) {
+          this.subDirectories.add(pathInfo.getPath());
+        }
+      } else if (isHoodiePartition && FSUtils.isDataFile(pathInfo.getPath())) {
+        // Regular HUDI data file (base file or log file)
+        String dataFileCommitTime = 
FSUtils.getCommitTime(pathInfo.getPath().getName());
+        // Limit the file listings to files which were created by successful 
commits before the maxInstant time.
+        if (!pendingDataInstants.contains(dataFileCommitTime) && 
compareTimestamps(dataFileCommitTime, LESSER_THAN_OR_EQUALS, maxInstantTime)) {
+          filenameToSizeMap.put(pathInfo.getPath().getName(), 
pathInfo.getLength());
+        }
+      }
+    }
+  }
+
+  public static Map<String, List<FileInfo>> 
getPartitionToFileInfo(List<DirectoryInfo> partitionInfoList) {
+    return partitionInfoList.stream()
+        .map(p -> {
+          String partitionName = 
HoodieTableMetadataUtil.getPartitionIdentifierForFilesPartition(p.getRelativePath());
+          List<FileInfo> files = p.getFilenameToSizeMap().entrySet().stream()
+              .map(entry -> FileInfo.of(entry.getKey(), entry.getValue()))
+              .collect(Collectors.toList());
+          return Pair.of(partitionName, files);
+        })
+        .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
+  }

Review Comment:
   Fixed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to