public static Cluster greedyShufflePartitions(final Cluster nextCandidateCluster,
                                                  final int greedyAttempts,
                                                  final int greedySwapMaxPartitionsPerNode,
                                                  final int greedySwapMaxPartitionsPerZone,
                                                  List<Integer> greedySwapZoneIds,
                                                  List<StoreDefinition> storeDefs) {
        List<Integer> zoneIds = null;
        if(greedySwapZoneIds.isEmpty()) {
            zoneIds = new ArrayList<Integer>(nextCandidateCluster.getZoneIds());
        } else {
            zoneIds = new ArrayList<Integer>(greedySwapZoneIds);
        }

        List<Integer> nodeIds = new ArrayList<Integer>();
        Cluster returnCluster = Cluster.cloneCluster(nextCandidateCluster);
        double currentUtility = new PartitionBalance(returnCluster, storeDefs).getUtility();

        for(int i = 0; i < greedyAttempts; i++) {

            // Iterate over zone ids to decide which node ids to include for
            // intra-zone swapping.
            // In future, if there is a need to support inter-zone swapping,
            // then just remove the
            // zone specific logic that populates nodeIdSet and add all nodes
            // from across all zones.

            int zoneIdOffset = i % zoneIds.size();
            Set<Integer> nodeIdSet = nextCandidateCluster.getNodeIdsInZone(zoneIds.get(zoneIdOffset));
            nodeIds = new ArrayList<Integer>(nodeIdSet);

            Collections.shuffle(zoneIds, new Random(System.currentTimeMillis()));
            Cluster shuffleResults = swapGreedyRandomPartitions(returnCluster,
                                                                nodeIds,
                                                                greedySwapMaxPartitionsPerNode,
                                                                greedySwapMaxPartitionsPerZone,
                                                                storeDefs);

            double nextUtility = new PartitionBalance(shuffleResults, storeDefs).getUtility();
            System.out.println("Swap improved max-min ratio: " + currentUtility + " -> "
                               + nextUtility + " (swap attempt " + i + " in zone "
                               + zoneIds.get(zoneIdOffset) + ")");
            returnCluster = shuffleResults;
            currentUtility = nextUtility;
        }
        return returnCluster;
    }
public static Cluster greedyShufflePartitions ( final Cluster nextCandidateCluster , final int greedyAttempts , final int greedySwapMaxPartitionsPerNode , final int greedySwapMaxPartitionsPerZone , List < Integer > greedySwapZoneIds , List < StoreDefinition > storeDefs ) { List < Integer > zoneIds = null ; if ( greedySwapZoneIds . isEmpty ( ) ) { zoneIds = new ArrayList < Integer > ( nextCandidateCluster . getZoneIds ( ) ) ; } else { zoneIds = new ArrayList < Integer > ( greedySwapZoneIds ) ; } List < Integer > nodeIds = new ArrayList < Integer > ( ) ; Cluster returnCluster = Cluster . cloneCluster ( nextCandidateCluster ) ; double currentUtility = new PartitionBalance ( returnCluster , storeDefs ) . getUtility ( ) ; for ( int i = 0 ; i < greedyAttempts ; i ++ ) { int zoneIdOffset = i % zoneIds . size ( ) ; Set < Integer > nodeIdSet = nextCandidateCluster . getNodeIdsInZone ( zoneIds . get ( zoneIdOffset ) ) ; nodeIds = new ArrayList < Integer > ( nodeIdSet ) ; Collections . shuffle ( zoneIds , new Random ( System . currentTimeMillis ( ) ) ) ; Cluster shuffleResults = swapGreedyRandomPartitions ( returnCluster , nodeIds , greedySwapMaxPartitionsPerNode , greedySwapMaxPartitionsPerZone , storeDefs ) ; double nextUtility = new PartitionBalance ( shuffleResults , storeDefs ) . getUtility ( ) ; System . out . println ( "Swap improved max-min ratio: " + currentUtility + " -> " + nextUtility + " (swap attempt " + i + " in zone " + zoneIds . get ( zoneIdOffset ) + ")" ) ; returnCluster = shuffleResults ; currentUtility = nextUtility ; } return returnCluster ; }
Within a single zone, tries swapping some minimum number of random
partitions per node with some minimum number of random partitions from
other nodes within the zone. Chooses the best swap in each iteration.
Large values of the greedSwapMaxPartitions... arguments make this method
equivalent to comparing every possible swap. This is very expensive.

Normal case should be :

#zones X #nodes/zone X max partitions/node X max partitions/zone

@param nextCandidateCluster cluster object.
@param greedyAttempts See RebalanceCLI.
@param greedySwapMaxPartitionsPerNode See RebalanceCLI.
@param greedySwapMaxPartitionsPerZone See RebalanceCLI.
@param greedySwapZoneIds The set of zoneIds to consider. Each zone is done
independently.
@param storeDefs
@return updated cluster