class_docstr: Class to build and search annoy indices.
  
  TODO(b/162421415): Split the managing of indices and the index logic.
  
  Upon instantiation of this class, it will first create empty indices for
  every model/embedding/dataset triple. It will then search for existing indices
  in the data directory and fill those. If the flag `initialize_new_indices` is
  set, it will fill the remaining indices by iterating over the data.
  During the saving process, both the index and a mapping from index-row to
  example are saved. These are used during the nearest neighbor lookup to return
  the closest example.
  
  Attributes:
     models: specification akin to the LIT server.
     datasets: specification akin to the LIT server.
     data_dir: path for (de-)serialization of indices.
     initialize_new_indices: whether to build new indices or simply load
       existing ones.
docstr: Create all indices for a single model.
docstr_tok: ["Create","all","indices","for","a","single","model","."]
code: def _fill_indices(self, model_name, dataset_name):
      """Create all indices for a single model."""
      model = self._models.get(model_name)
      assert model is not None, "Invalid model name."
      examples = self.datasets[dataset_name].examples
      model_embeddings_names = utils.find_spec_keys(
          model.output_spec(), lit_types.Embeddings
      )
      lookup_key = self._get_lookup_key(model_name, dataset_name)
  
      # If the model has no embeddings to extract, skip the following.
      if not model_embeddings_names:
          return
  
      # Load from file if it exists.
      for emb_name in model_embeddings_names:
          # Initialize the index object in self._indices with serialized index.
          self._init_index_from_file(model_name, dataset_name, emb_name)
      # Load example lookup dictionary from file.
      self._example_lookup[lookup_key] = self._load_lookup(lookup_key)
  
      # Identify which indices need to be initialized.
      embeddings_to_index = [
          emb_name
          for emb_name in model_embeddings_names
          if not self._is_index_initialized(
              model_name, dataset_name, emb_name
          )
      ]
      # Early exit if all embeddings are now initialized.
      if not embeddings_to_index:
          return
  
      # Cold start: Get embeddings for non-initialized settings.
      if self._initialize_new_indices:
          for res_ix, (result, example) in enumerate(
              zip(model.predict(examples), examples)
          ):
              for emb_name in embeddings_to_index:
                  index_key = self._get_index_key(
                      model_name, dataset_name, emb_name
                  )
                  # Initialize saving in the first iteration.
                  if res_ix == 0:
                      file_path = self._get_index_path(index_key)
                      self._indices[index_key].on_disk_build(file_path)
                  index = self._indices.get(index_key)
                  assert (
                      index is not None
                  ), "Index needs to be created first."
                  # Each item has an incrementing ID res_ix.
                  self._indices[index_key].add_item(
                      res_ix, result[emb_name]
                  )
              # Add item to lookup table.
              self._example_lookup[lookup_key][res_ix] = example
  
          # Create the trees from the indices - using 10 as recommended by doc.
          for emb_name in embeddings_to_index:
              index_key = self._get_index_key(
                  model_name, dataset_name, emb_name
              )
              logging.info("Creating new index: %s", index_key)
              self._indices[index_key].build(10)
              index_size = self._indices[index_key].get_n_items()
              logging.info(
                  "Created new index with %s items.", index_size
              )
  
imports: import collections
  from collections.abc import Mapping
  import os
  import pickle
  from typing import Optional
  from absl import logging
  import annoy
  from lit_nlp.api import dataset
  from lit_nlp.api import model
  from lit_nlp.api import types
  from lit_nlp.lib import utils
label_desc: Use image node_id 8 for calling the Indexer obj's underlying member method code with example usage: obj._fill_indices(model_name, dataset_name) without return types