docs: public GlobalProperties filterBySemanticProperties(SemanticProperties props, int input) {
  
  		if (props == null) {
  			throw new NullPointerException("SemanticProperties may not be null.");
  		}
  
  		GlobalProperties gp = new GlobalProperties();
  
  		// filter partitioning
  		switch(this.partitioning) {
  			case RANGE_PARTITIONED:
  				// check if ordering is preserved
  				Ordering newOrdering = new Ordering();
  				for (int i = 0; i < this.ordering.getInvolvedIndexes().size(); i++) {
  					int sourceField = this.ordering.getInvolvedIndexes().get(i);
  					FieldSet targetField = props.getForwardingTargetFields(input, sourceField);
  
  					if (targetField == null || targetField.size() == 0) {
  						// partitioning is destroyed
  						newOrdering = null;
  						break;
  					} else {
  						// use any field of target fields for now. We should use something like field equivalence sets in the future.
  						if(targetField.size() > 1) {
  							LOG.warn("Found that a field is forwarded to more than one target field in " +
  									"semantic forwarded field information. Will only use the field with the lowest index.");
  						}
  						newOrdering.appendOrdering(targetField.toArray()[0], this.ordering.getType(i), this.ordering.getOrder(i));
  					}
  				}
  				if(newOrdering != null) {
  					gp.partitioning = PartitioningProperty.RANGE_PARTITIONED;
  					gp.ordering = newOrdering;
  					gp.partitioningFields = newOrdering.getInvolvedIndexes();
  					gp.distribution = this.distribution;
  				}
  				break;
  			case HASH_PARTITIONED:
  			case ANY_PARTITIONING:
  			case CUSTOM_PARTITIONING:
  				FieldList newPartitioningFields = new FieldList();
  				for (int sourceField : this.partitioningFields) {
  					FieldSet targetField = props.getForwardingTargetFields(input, sourceField);
  
  					if (targetField == null || targetField.size() == 0) {
  						newPartitioningFields = null;
  						break;
  					} else {
  						// use any field of target fields for now.  We should use something like field equivalence sets in the future.
  						if(targetField.size() > 1) {
  							LOG.warn("Found that a field is forwarded to more than one target field in " +
  									"semantic forwarded field information. Will only use the field with the lowest index.");
  						}
  						newPartitioningFields = newPartitioningFields.addField(targetField.toArray()[0]);
  					}
  				}
  				if(newPartitioningFields != null) {
  					gp.partitioning = this.partitioning;
  					gp.partitioningFields = newPartitioningFields;
  					gp.customPartitioner = this.customPartitioner;
  				}
  				break;
  			case FORCED_REBALANCED:
  			case FULL_REPLICATION:
  			case RANDOM_PARTITIONED:
  				gp.partitioning = this.partitioning;
  				break;
  			default:
  				throw new RuntimeException("Unknown partitioning type.");
  		}
  
  		// filter unique field combinations
  		if (this.uniqueFieldCombinations != null) {
  			Set<FieldSet> newUniqueFieldCombinations = new HashSet<FieldSet>();
  			for (FieldSet fieldCombo : this.uniqueFieldCombinations) {
  				FieldSet newFieldCombo = new FieldSet();
  				for (Integer sourceField : fieldCombo) {
  					FieldSet targetField = props.getForwardingTargetFields(input, sourceField);
  
  					if (targetField == null || targetField.size() == 0) {
  						newFieldCombo = null;
  						break;
  					} else {
  						// use any field of target fields for now.  We should use something like field equivalence sets in the future.
  						if(targetField.size() > 1) {
  							LOG.warn("Found that a field is forwarded to more than one target field in " +
  									"semantic forwarded field information. Will only use the field with the lowest index.");
  						}
  						newFieldCombo = newFieldCombo.addField(targetField.toArray()[0]);
  					}
  				}
  				if (newFieldCombo != null) {
  					newUniqueFieldCombinations.add(newFieldCombo);
  				}
  			}
  			if(!newUniqueFieldCombinations.isEmpty()) {
  				gp.uniqueFieldCombinations = newUniqueFieldCombinations;
  			}
  		}
  
  		return gp;
  	}