def update_labels_and_tags(dataset_id,
                           existing_labels_or_tags,
                           new_labels_or_tags,
                           overwrite_ok=False):
    """
    Updates labels or tags in dataset if not set or needing to be updated
    or overwrites existing labels or tags in the dataset

    :param dataset_id:  string name to identify the dataset
    :param existing_labels_or_tags:  labels already existing on the dataset = Dict[str, str]
                                     tags already existing on the dataset = Dict[str, '']
    :param new_labels_or_tags:  new labels to add to the dataset = Dict[str, str]
                                new tags to add to the dataset = Dict[str, '']
    :param overwrite_ok:  flag to signal if labels or tags are to be either
                             overwritten (False as default) or updated (True)

    :raises:  RuntimeError if parameters are not specified
    :raises:  RuntimeError if overwrite_ok is false and new value for label is provided

    :return:  a dictionary of new labels or tags
    """
    if not dataset_id:
        raise RuntimeError("Provide a dataset_id")

    if not new_labels_or_tags:
        raise RuntimeError("Please provide a label or tag")

    # excludes duplicate keys
    updates = dict(new_labels_or_tags.items() - existing_labels_or_tags.items())

    overwrite_keys = updates.keys() & existing_labels_or_tags.keys()

    if overwrite_keys:
        if not overwrite_ok:
            raise RuntimeError(f'Cannot update labels on dataset {dataset_id}'
                               f'without overwriting keys {overwrite_keys}')
        return {**existing_labels_or_tags, **updates}