docs: def probabilities(self):
          '''Trains a model and predicts recommendations.
  
          If the query feature collection could not be found or if there
          is insufficient training data, an empty list is returned.
  
          Otherwise, a list of content objects (tuples of content
          id and feature collection) and probabilities is returned.
          The probability is generated from the model, and reflects
          confidence of the model that the corresponding content object
          is related to the query based on the ground truth data.
  
          On a large database, random samples are used for training, so
          this function is not deterministic.
  
          :rtype: ``list`` of
            ((``content_id``, :class:`dossier.fc.FeatureCollection`),
            probability)
          '''
          self.query_fc = self.store.get(self.query_content_id)
          if self.query_fc is None:
              logger.warning('Could not find FC for %s', self.query_content_id)
              return []
  
          # Try the canopy query before training, because if the canopy query
          # gives us nothing, then there's no point in the additional work.
          #
          # Possible optimization: If the canopy query yields fewer than N
          # results, then can we just return all of them? ---AG
          #
          # N.B Doing the canopy query first will cause things to be slower
          # when there is insufficient training data.
          candidates = self.canopy(limit=self.canopy_limit)
          if len(candidates) == 0:
              logger.info(
                  'Could not find any candidates in a canopy query by '
                  'scanning the following indexes: %s',
                  ', '.join(self.store.index_names()))
              return []
  
          # Get labels from the database and translate them to the form
          # `[{-1, 1}, i, j]` where `i, j` are indices into the list
          # `content_objs`, which has type `[(content_id, FeatureCollection)]`.
          logger.info('Fetching labels...')
          labels = list(self.labels_from_query(limit=self.label_limit))
          logger.info('Fetching FCs from labels...')
          content_objs = self.content_objs_from_labels(labels)
          indexed_labels = labels_to_indexed_coref_values(content_objs, labels)
  
          logger.info('Training...')
          model = self.train(content_objs, indexed_labels)
          if model is None:
              logger.info(
                  'Could not train model: insufficient training data. '
                  '(query content id: %s)', self.query_content_id)
              raise InsufficientTrainingData
  
          feature_names, classifier, transformer = model
          return zip(candidates, self.classify(
              feature_names, classifier, transformer, candidates))