def clean_up_indexes(self, direction):
    if direction == datastore_pb.Query_Order.ASCENDING:
      table_name = dbconstants.ASC_PROPERTY_TABLE
      task_id = self.CLEAN_ASC_INDICES_TASK
    else:
      table_name = dbconstants.DSC_PROPERTY_TABLE
      task_id = self.CLEAN_DSC_INDICES_TASK

    # If we have state information beyond what function to use,
    # load the last seen start key.
    if len(self.groomer_state) > 1 and self.groomer_state[0] == task_id:
      start_key = self.groomer_state[1]
    else:
      start_key = ''
    end_key = dbconstants.TERMINATING_STRING

    while True:
      references = self.db_access.range_query(
        table_name=table_name,
        column_names=dbconstants.PROPERTY_SCHEMA,
        start_key=start_key,
        end_key=end_key,
        limit=self.BATCH_SIZE,
        start_inclusive=False,
      )
      if len(references) == 0:
        break

      self.index_entries_checked += len(references)
      if time.time() > self.last_logged + self.LOG_PROGRESS_FREQUENCY:
        logging.info('Checked {} index entries'
          .format(self.index_entries_checked))
        self.last_logged = time.time()
      first_ref = references[0].keys()[0]
      logging.debug('Fetched {} total refs, starting with {}, direction: {}'
        .format(self.index_entries_checked, [first_ref], direction))

      last_start_key = start_key
      start_key = references[-1].keys()[0]
      if start_key == last_start_key:
        raise dbconstants.AppScaleDBError(
          'An infinite loop was detected while fetching references.')

      entities = self.fetch_entity_dict_for_references(references)

      # Group invalid references by entity key so we can minimize locks.
      invalid_refs = {}
      for reference in references:
        prop_name = reference.keys()[0].split(self.ds_access._SEPARATOR)[3]
        if not self.ds_access._DatastoreDistributed__valid_index_entry(
          reference, entities, direction, prop_name):
          entity_key = reference.values()[0][self.ds_access.INDEX_REFERENCE_COLUMN]
          if entity_key not in invalid_refs:
            invalid_refs[entity_key] = []
          invalid_refs[entity_key].append(reference)

      for entity_key in invalid_refs:
        self.lock_and_delete_indexes(invalid_refs[entity_key], direction, entity_key)
      self.update_groomer_state([task_id, start_key])
Custom version of np.searchsorted. Return the largest index `i` such
dataset/ETHPy150Open AppScale/appscale/AppDB/groomer.py/DatastoreGroomer.clean_up_indexes--crossover with--dataset/ETHPy150Open QuantEcon/QuantEcon.py/quantecon/util/array.py/searchsorted