Finds all objects associated with any of the keywords.

    Args:
      index_urn: The base urn of the index.
      keywords: A collection of keywords that we are interested in.
      start_time: Only considers keywords added at or after this point in time.
      end_time: Only considers keywords at or before this point in time.
      last_seen_map: If present, is treated as a dict and populated to map pairs
        (keyword, name) to the timestamp of the latest connection found.

    Returns:
      A dict mapping each keyword to a set of relevant names.

def IndexReadPostingLists(self,
                            index_urn,
                            keywords,
                            start_time,
                            end_time,
                            last_seen_map=None):
    """Finds all objects associated with any of the keywords.

    Args:
      index_urn: The base urn of the index.
      keywords: A collection of keywords that we are interested in.
      start_time: Only considers keywords added at or after this point in time.
      end_time: Only considers keywords at or before this point in time.
      last_seen_map: If present, is treated as a dict and populated to map pairs
        (keyword, name) to the timestamp of the latest connection found.

    Returns:
      A dict mapping each keyword to a set of relevant names.
    """
    keyword_urns = {self._KeywordToURN(index_urn, k): k for k in keywords}
    result = {}
    for kw in keywords:
      result[kw] = set()

    for keyword_urn, value in self.MultiResolvePrefix(
        list(iterkeys(keyword_urns)),
        self._INDEX_PREFIX,
        timestamp=(start_time, end_time + 1)):
      for column, _, ts in value:
        kw = keyword_urns[keyword_urn]
        name = column[self._INDEX_PREFIX_LEN:]
        result[kw].add(name)
        if last_seen_map is not None:
          last_seen_map[(kw, name)] = max(last_seen_map.get((kw, name), -1), ts)

    return result