def load_kb(
      self, name, kb_file
  ):
    r"""Load KB from file.

    We store KB as a dictionary of dictionaries, where keys are subjects and
    values are dictionaries of facts. Each dictionary of facts is constructed
    with relations as keys and objects as values.

    Input formats are different in different tasks. In the "webqsp" task,
    subject, relation, and object entities are split by "\t".

    Args:
      name: task name
      kb_file: kb file

    Returns:
      a dictionary of dictionaries, and mappings from fact/relation/entity to id
    """

    def get_delimiter():
      if name == 'webqsp' or name.startswith('query2box'):
        return '\t'
      else:
        return '|'

    def set_has_inverse_fact():
      if name == 'webqsp':
        return False
      else:
        return True

    def set_reorder():
      if name == 'webqsp':
        return lambda ps: (ps[1], ps[0], ps[2])
      else:
        return lambda ps: ps

    def set_inv_suffix():
      if name.startswith('query2box'):
        suffix = '_reverse'
      else:
        suffix = '-inv'
      return suffix

    # Prepare for loading the KB.
    self._inv_suffix = set_inv_suffix()
    delimiter = get_delimiter()
    has_inverse_fact = set_has_inverse_fact()
    reorder = set_reorder()

    kb = dict()
    fact2id = dict()
    entity2id = dict()
    relation2id = dict()
    with gfile.GFile(kb_file, 'r') as f_in:
      for line in tqdm(f_in):
        subj, rel, obj = reorder(tuple(line.strip().split(delimiter)))
        rel_inv = self._inverse_rel(rel)

        if (subj, rel, obj) not in fact2id:
          fact2id[(subj, rel, obj)] = len(fact2id)
          if has_inverse_fact:
            assert (obj, rel_inv, subj) not in fact2id
            fact2id[(obj, rel_inv, subj)] = len(fact2id)

        # Load KB facts.
        if subj not in kb:
          kb[subj] = dict()
        if rel not in kb[subj]:
          kb[subj][rel] = set()
        kb[subj][rel].add(obj)

        # Build a mapping from relations and entities to ids.
        if rel not in relation2id:
          relation2id[rel] = len(relation2id)
        if subj not in entity2id:
          entity2id[subj] = len(entity2id)
        if obj not in entity2id:
          entity2id[obj] = len(entity2id)

        if has_inverse_fact:
          # assert (obj, rel_inv, subj) not in fact2id
          # fact2id[(obj, rel_inv, subj)] = len(fact2id)
          # Load reverse KB facts.
          if obj not in kb:
            kb[obj] = dict()
          if rel_inv not in kb[obj]:
            kb[obj][rel_inv] = set()
          kb[obj][rel_inv].add(subj)
          # Build a mapping from inverse relations to ids.
          if rel_inv not in relation2id:
            relation2id[rel_inv] = len(relation2id)

    return kb, fact2id, entity2id, relation2id
Load KB from file.

    We store KB as a dictionary of dictionaries, where keys are subjects and
    values are dictionaries of facts. Each dictionary of facts is constructed
    with relations as keys and objects as values.

    Input formats are different in different tasks. In the "webqsp" task,
    subject, relation, and object entities are split by "\t".

    Args:
      name: task name
      kb_file: kb file

    Returns:
      a dictionary of dictionaries, and mappings from fact/relation/entity to id
    
language/emql/data_loader.py