### Description

It should be enough to have ShardId + nodeId key in `routingToDataPath` to find the necessary data path. 
Changing the key would allow us to minimize the size of ClusterInfo size and find the data path when shard changes its status.

`ClusterInfo` might be sent over the wire when cluster allocation explain is executed with `includeDiskInfo=true`.
ShardRouting -> ShardId + nodeId conversion is trivial. The oposit would require additional information that could be faked.

Current key is also used in here:
https://github.com/elastic/elasticsearch/blob/9ebbe1c62bf0157d332f20f392544a1921a710df/server/src/main/java/org/elasticsearch/cluster/ClusterInfo.java#L149-L154
where it produces a string with ShardRouting#shortSummary that is excessive and might be simplified to ShardId + nodeId as well
server/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java
public ClusterInfo getClusterInfo() {
        final IndicesStatsSummary indicesStatsSummary = this.indicesStatsSummary; 
        return new ClusterInfo(
            leastAvailableSpaceUsages,
            mostAvailableSpaceUsages,
            indicesStatsSummary.shardSizes,
            indicesStatsSummary.shardDataSetSizes,
            indicesStatsSummary.shardRoutingToDataPath,
            indicesStatsSummary.reservedSpace
        );
    }
    
    List<NodeStats> adjustNodesStats(List<NodeStats> nodeStats) {
        return nodeStats;
    }
    ShardStats[] adjustShardStats(ShardStats[] shardStats) {
        return shardStats;
    }
    void refreshAsync(ActionListener<ClusterInfo> future) {
        final Runnable newRefresh;
        synchronized (mutex) {
            nextRefreshListeners.add(future);
            newRefresh = getNewRefresh();
            assert assertRefreshInvariant();
        }
        newRefresh.run();
    }
    @Override
    public void addListener(Consumer<ClusterInfo> clusterInfoConsumer) {
        listeners.add(clusterInfoConsumer);