CDK-634: Add Dataset creation to MR and Crunch.

This adds an option to set a descriptor for the output URI, which is
used to create a Dataset if one doesn't already exist. For Datasets
that use the MergeOutputCommitter, the final Dataset is created in the
commitJob method and the NullOutputCommitter creates the dataset in the
setupJob method because tasks write directly to it.

This adds methods to store and retrieve a descriptor in a Configuration
to DescriptorUtil. These methods take a context String that is used to
build property names, so multiple descriptors can be stored in the same
Configuration.

Because the Descriptor can be stored in the Job Configuration, this no
longer relies on the job Dataset to serialize the descriptor to task
attempts. Task attemps no longer load the job Dataset to create the task
attempt Datasets.
Actually, it looks like I'm wrong. Our definition of exists is not empty. So it wouldn't cause the subsequent job to fail, but it would have a side-effect of creating the dataset. That is not wanted in some situations. For example, if the job failed because of Schema problems. Then you'd have to fix the dataset before rerunning the job.