3232import java .util .Set ;
3333import java .util .concurrent .ConcurrentLinkedQueue ;
3434import java .util .concurrent .ExecutorService ;
35+ import java .util .function .Function ;
36+ import java .util .function .Supplier ;
37+ import java .util .stream .Collectors ;
3538import org .apache .iceberg .exceptions .RuntimeIOException ;
3639import org .apache .iceberg .exceptions .ValidationException ;
3740import org .apache .iceberg .expressions .Expression ;
@@ -366,6 +369,7 @@ static class Builder {
366369 private final Iterable <DeleteFile > deleteFiles ;
367370 private long minSequenceNumber = 0L ;
368371 private Map <Integer , PartitionSpec > specsById = null ;
372+ private Map <Integer , Schema > schemasById = null ;
369373 private Expression dataFilter = Expressions .alwaysTrue ();
370374 private Expression partitionFilter = Expressions .alwaysTrue ();
371375 private PartitionSet partitionSet = null ;
@@ -391,6 +395,11 @@ Builder afterSequenceNumber(long seq) {
391395 return this ;
392396 }
393397
398+ Builder schemasById (Map <Integer , Schema > newSchemasById ) {
399+ this .schemasById = newSchemasById ;
400+ return this ;
401+ }
402+
394403 Builder specsById (Map <Integer , PartitionSpec > newSpecsById ) {
395404 this .specsById = newSpecsById ;
396405 return this ;
@@ -471,10 +480,20 @@ private Collection<DeleteFile> loadDeleteFiles() {
471480 return files ;
472481 }
473482
483+ private Collection <Schema > schemas () {
484+ if (schemasById != null ) {
485+ return schemasById .values ();
486+ } else {
487+ return specsById .values ().stream ().map (PartitionSpec ::schema ).collect (Collectors .toList ());
488+ }
489+ }
490+
474491 DeleteFileIndex build () {
492+ Map <Integer , Types .NestedField > fieldsById = Schema .indexFields (schemas ());
493+ Function <Integer , Types .NestedField > fieldLookup = fieldsById ::get ;
475494 Iterable <DeleteFile > files = deleteFiles != null ? filterDeleteFiles () : loadDeleteFiles ();
476495
477- EqualityDeletes globalDeletes = new EqualityDeletes ();
496+ EqualityDeletes globalDeletes = new EqualityDeletes (fieldLookup );
478497 PartitionMap <EqualityDeletes > eqDeletesByPartition = PartitionMap .create (specsById );
479498 PartitionMap <PositionDeletes > posDeletesByPartition = PartitionMap .create (specsById );
480499 Map <String , PositionDeletes > posDeletesByPath = Maps .newHashMap ();
@@ -490,7 +509,7 @@ DeleteFileIndex build() {
490509 }
491510 break ;
492511 case EQUALITY_DELETES :
493- add (globalDeletes , eqDeletesByPartition , file );
512+ add (globalDeletes , eqDeletesByPartition , file , fieldLookup );
494513 break ;
495514 default :
496515 throw new UnsupportedOperationException ("Unsupported content: " + file .content ());
@@ -537,7 +556,8 @@ private void add(
537556 private void add (
538557 EqualityDeletes globalDeletes ,
539558 PartitionMap <EqualityDeletes > deletesByPartition ,
540- DeleteFile file ) {
559+ DeleteFile file ,
560+ Function <Integer , Types .NestedField > fieldLookup ) {
541561 PartitionSpec spec = specsById .get (file .specId ());
542562
543563 EqualityDeletes deletes ;
@@ -546,10 +566,11 @@ private void add(
546566 } else {
547567 int specId = spec .specId ();
548568 StructLike partition = file .partition ();
549- deletes = deletesByPartition .computeIfAbsent (specId , partition , EqualityDeletes ::new );
569+ Supplier <EqualityDeletes > initEqDeletes = () -> new EqualityDeletes (fieldLookup );
570+ deletes = deletesByPartition .computeIfAbsent (specId , partition , initEqDeletes );
550571 }
551572
552- deletes .add (spec , file );
573+ deletes .add (file );
553574 }
554575
555576 private Iterable <CloseableIterable <ManifestEntry <DeleteFile >>> deleteManifestReaders () {
@@ -726,16 +747,22 @@ static class EqualityDeletes {
726747 Comparator .comparingLong (EqualityDeleteFile ::applySequenceNumber );
727748 private static final EqualityDeleteFile [] EMPTY_EQUALITY_DELETES = new EqualityDeleteFile [0 ];
728749
750+ private final Function <Integer , Types .NestedField > fieldLookup ;
751+
729752 // indexed state
730753 private long [] seqs = null ;
731754 private EqualityDeleteFile [] files = null ;
732755
733756 // a buffer that is used to hold files before indexing
734757 private volatile List <EqualityDeleteFile > buffer = Lists .newArrayList ();
735758
736- public void add (PartitionSpec spec , DeleteFile file ) {
759+ EqualityDeletes (Function <Integer , Types .NestedField > fieldLookup ) {
760+ this .fieldLookup = fieldLookup ;
761+ }
762+
763+ public void add (DeleteFile file ) {
737764 Preconditions .checkState (buffer != null , "Can't add files upon indexing" );
738- buffer .add (new EqualityDeleteFile (spec , file ));
765+ buffer .add (new EqualityDeleteFile (fieldLookup , file ));
739766 }
740767
741768 public DeleteFile [] filter (long seq , DataFile dataFile ) {
@@ -801,15 +828,15 @@ private static long[] indexSeqs(EqualityDeleteFile[] files) {
801828 // an equality delete file wrapper that caches the converted boundaries for faster boundary checks
802829 // this class is not meant to be exposed beyond the delete file index
803830 private static class EqualityDeleteFile {
804- private final PartitionSpec spec ;
831+ private final Function < Integer , Types . NestedField > fieldLookup ;
805832 private final DeleteFile wrapped ;
806833 private final long applySequenceNumber ;
807834 private volatile List <Types .NestedField > equalityFields = null ;
808835 private volatile Map <Integer , Object > convertedLowerBounds = null ;
809836 private volatile Map <Integer , Object > convertedUpperBounds = null ;
810837
811- EqualityDeleteFile (PartitionSpec spec , DeleteFile file ) {
812- this .spec = spec ;
838+ EqualityDeleteFile (Function < Integer , Types . NestedField > fieldLookup , DeleteFile file ) {
839+ this .fieldLookup = fieldLookup ;
813840 this .wrapped = file ;
814841 this .applySequenceNumber = wrapped .dataSequenceNumber () - 1 ;
815842 }
@@ -828,7 +855,8 @@ public List<Types.NestedField> equalityFields() {
828855 if (equalityFields == null ) {
829856 List <Types .NestedField > fields = Lists .newArrayList ();
830857 for (int id : wrapped .equalityFieldIds ()) {
831- Types .NestedField field = spec .schema ().findField (id );
858+ Types .NestedField field = fieldLookup .apply (id );
859+ Preconditions .checkArgument (field != null , "Cannot find field for ID %s" , id );
832860 fields .add (field );
833861 }
834862 this .equalityFields = fields ;
@@ -891,7 +919,7 @@ private Map<Integer, Object> convertBounds(Map<Integer, ByteBuffer> bounds) {
891919 if (bounds != null ) {
892920 for (Types .NestedField field : equalityFields ()) {
893921 int id = field .fieldId ();
894- Type type = spec . schema (). findField ( id ) .type ();
922+ Type type = field .type ();
895923 if (type .isPrimitiveType ()) {
896924 ByteBuffer bound = bounds .get (id );
897925 if (bound != null ) {
0 commit comments