def rank(self):
        """
          Perform the ranking with the given parameters
        """

        values = deepcopy(self.values)

        # Get the current scoring
        changes = {
            'lock' : Lock()
        }
        scoringThread = CoordinateDescentRankingThread(values, self.keywords, changes, 'original', self.relevantResults,
                                                       CoordinateDescentRanking.getIndexLocation() + '-original')
        scoringThread.start()
        scoringThread.join()
        results = scoringThread.results

        return results
    def learn(self):
        """
          Run the learning algorithm, and return the learned feature weights
        """

        # Get a copy of the values to tweak
        values = deepcopy(self.values)

        # Get the current scoring
        changes = {
            'lock' : Lock()
        }
        print "about to start learning"
        scoringThread = CoordinateDescentRankingThread(values, self.keywords, changes, 'original',
                                                       self.relevantResults, CoordinateDescentRanking.getIndexLocation() + '-original')
        scoringThread.start()
        scoringThread.join()
        currentWeightingScoring = changes['original']
        print "Original scoring: %1.5f" % currentWeightingScoring

        # The set of features to still tweak
        features = self.values.keys()

        # Keep looping until no further change is necessary
        complete = False
        iterations = 0
        while not complete:

            complete = True
            iterations += 1

            # Create data structures for managing threads
            changes = {
                'lock' : Lock()
            }
            threads = []

            # Launch threads to test changes to each feature weight
            print "Preparing threads..."
            for feature in features:

                # Form the path to the index to use for this test
                featureIndexLocation = CoordinateDescentRanking.getIndexLocation() + '-' + feature

                # Launch test for increasing weight of this feature
                values = deepcopy(self.values)
                values[feature] += self.stepSizes[feature]
                scoringThread = CoordinateDescentRankingThread(values, self.keywords, changes, feature + '+',
                                                               self.relevantResults, featureIndexLocation)
                threads.append(scoringThread)

                # Launch test for decreasing weight of this feature
                values = deepcopy(self.values)
                values[feature] -= self.stepSizes[feature]
                scoringThread = CoordinateDescentRankingThread(values, self.keywords, changes, feature + '-',
                                                               self.relevantResults, featureIndexLocation)
                threads.append(scoringThread)


            print "Launching threads..."
            for thread in threads:
                thread.start()

            # Wait for all threads to finish
            print "Waiting for threads to finish..."
            for thread in threads:
                thread.join()

            # Update feature weights accordingly
            print "Analyzing ranking results"
            for feature in deepcopy(features):

                increaseFeatureWeightResultScoring = changes[feature+'+']
                decreaseFeatureWeightResultScoring = changes[feature+'-']

                # If one of these improved...
                if increaseFeatureWeightResultScoring > currentWeightingScoring or decreaseFeatureWeightResultScoring > currentWeightingScoring:
                    if increaseFeatureWeightResultScoring > decreaseFeatureWeightResultScoring:
                        self.values[feature] += self.stepSizes[feature]
                    elif decreaseFeatureWeightResultScoring >= increaseFeatureWeightResultScoring:
                        self.values[feature] -= self.stepSizes[feature]
                    complete = False
                else:
                    del features[feature]
                    print "No improvement found for tweaking %s!" % feature

            print "Finished learning iteration %d, new values:" % iterations
            pprint(self.values)