Example #1
0
    def test_data_in_index(self):
        """Verify the data we are indexing."""
        p = product(save=True)
        q = question(locale='pt-BR', product=p, save=True)
        a = answer(question=q, save=True)

        self.refresh()

        eq_(AnswerMetricsMappingType.search().count(), 1)
        data = AnswerMetricsMappingType.search()[0]
        eq_(data['locale'], q.locale)
        eq_(data['product'], [p.slug])
        eq_(data['creator_id'], a.creator_id)
        eq_(data['is_solution'], False)
        eq_(data['by_asker'], False)

        # Mark as solution and verify
        q.solution = a
        q.save()

        self.refresh()
        data = AnswerMetricsMappingType.search()[0]
        eq_(data['is_solution'], True)

        # Make the answer creator to be the question creator and verify.
        a.creator = q.creator
        a.save()

        self.refresh()
        data = AnswerMetricsMappingType.search()[0]
        eq_(data['by_asker'], True)
Example #2
0
    def test_data_in_index(self):
        """Verify the data we are indexing."""
        p = ProductFactory()
        q = QuestionFactory(locale='pt-BR', product=p)
        a = AnswerFactory(question=q)

        self.refresh()

        eq_(AnswerMetricsMappingType.search().count(), 1)
        data = AnswerMetricsMappingType.search()[0]
        eq_(data['locale'], q.locale)
        eq_(data['product'], [p.slug])
        eq_(data['creator_id'], a.creator_id)
        eq_(data['is_solution'], False)
        eq_(data['by_asker'], False)

        # Mark as solution and verify
        q.solution = a
        q.save()

        self.refresh()
        data = AnswerMetricsMappingType.search()[0]
        eq_(data['is_solution'], True)

        # Make the answer creator to be the question creator and verify.
        a.creator = q.creator
        a.save()

        self.refresh()
        data = AnswerMetricsMappingType.search()[0]
        eq_(data['by_asker'], True)
Example #3
0
    def test_add_and_delete(self):
        """Adding an answer should add it to the index.

        Deleting should delete it.
        """
        a = AnswerFactory()
        self.refresh()
        eq_(AnswerMetricsMappingType.search().count(), 1)

        a.delete()
        self.refresh()
        eq_(AnswerMetricsMappingType.search().count(), 0)
Example #4
0
    def test_add_and_delete(self):
        """Adding an answer should add it to the index.

        Deleting should delete it.
        """
        a = answer(save=True)
        self.refresh()
        eq_(AnswerMetricsMappingType.search().count(), 1)

        a.delete()
        self.refresh()
        eq_(AnswerMetricsMappingType.search().count(), 0)
Example #5
0
def top_contributors_questions(start=None, end=None, locale=None, product=None,
                               count=10, page=1, use_cache=True):
    """Get the top Support Forum contributors."""
    # Get the user ids and contribution count of the top contributors.

    if use_cache:
        cache_key = u'{}_{}_{}_{}_{}_{}'.format(start, end, locale, product, count, page)
        cache_key = hashlib.sha1(cache_key.encode('utf-8')).hexdigest()
        cache_key = 'top_contributors_questions_{}'.format(cache_key)
        cached = cache.get(cache_key, None)
        if cached:
            return cached

    query = AnswerMetricsMappingType.search()

    # Adding answer to your own question, isn't a contribution.
    query = query.filter(by_asker=False)
    query = _apply_filters(query, start, end, locale, product)

    answers = [q.id for q in query.all()[:HUGE_NUMBER]]
    users = (User.objects
             .filter(answers__in=answers)
             .annotate(query_count=Count('answers'))
             .order_by('-query_count'))

    counts = _get_creator_counts(users, count, page)
    if use_cache:
        cache.set(cache_key, counts, 60*15)  # 15 minutes
    return counts
Example #6
0
def top_contributors_questions(start=None,
                               end=None,
                               locale=None,
                               product=None,
                               count=10,
                               page=1,
                               use_cache=True):
    """Get the top Support Forum contributors."""
    # Get the user ids and contribution count of the top contributors.

    if use_cache:
        cache_key = u'{}_{}_{}_{}_{}_{}'.format(start, end, locale, product,
                                                count, page)
        cache_key = hashlib.sha1(cache_key.encode('utf-8')).hexdigest()
        cache_key = 'top_contributors_questions_{}'.format(cache_key)
        cached = cache.get(cache_key, None)
        if cached:
            return cached

    query = AnswerMetricsMappingType.search()

    # Adding answer to your own question, isn't a contribution.
    query = query.filter(by_asker=False)
    query = _apply_filters(query, start, end, locale, product)

    answers = [q.id for q in query.all()[:HUGE_NUMBER]]
    users = (User.objects.filter(answers__in=answers).annotate(
        query_count=Count('answers')).order_by('-query_count'))

    counts = _get_creator_counts(users, count, page)
    if use_cache:
        cache.set(cache_key, counts, 60 * 15)  # 15 minutes
    return counts
Example #7
0
File: utils.py Project: rik/kitsune
def top_contributors_questions(start=None, end=None, locale=None, product=None, count=10, page=1):
    """Get the top Support Forum contributors."""
    # Get the user ids and contribution count of the top contributors.
    query = AnswerMetricsMappingType.search().facet("creator_id", filtered=True, size=BIG_NUMBER)

    # Adding answer to your own question, isn't a contribution.
    query = query.filter(by_asker=False)

    query = _apply_filters(query, start, end, locale, product)

    return _get_creator_counts(query, count, page)
Example #8
0
def top_contributors_questions(start=None,
                               end=None,
                               locale=None,
                               product=None,
                               count=10):
    """Get the top Support Forum contributors."""
    # Get the user ids and contribution count of the top contributors.
    query = (AnswerMetricsMappingType.search().facet('creator_id',
                                                     filtered=True,
                                                     size=count))

    query = _apply_filters(query, start, end, locale, product)

    return _get_creator_counts(query, count)
Example #9
0
    def test_data_in_index(self):
        """Verify the data we are indexing."""
        p = product(save=True)
        q = question(locale='pt-BR', save=True)
        q.products.add(p)
        a = answer(question=q, save=True)

        self.refresh()

        eq_(AnswerMetricsMappingType.search().count(), 1)
        data = AnswerMetricsMappingType.search().values_dict()[0]
        eq_(data['locale'], q.locale)
        eq_(data['product'], [p.slug])
        eq_(data['creator_id'], a.creator_id)
        eq_(data['is_solution'], False)

        # Mark as solution and verify
        q.solution = a
        q.save()

        self.refresh()
        data = AnswerMetricsMappingType.search().values_dict()[0]
        eq_(data['is_solution'], True)
Example #10
0
def top_contributors_questions(start=None,
                               end=None,
                               locale=None,
                               product=None,
                               count=10,
                               page=1):
    """Get the top Support Forum contributors."""
    # Get the user ids and contribution count of the top contributors.
    query = (AnswerMetricsMappingType.search().facet('creator_id',
                                                     filtered=True,
                                                     size=BIG_NUMBER))

    # Adding answer to your own question, isn't a contribution.
    query = query.filter(by_asker=False)

    query = _apply_filters(query, start, end, locale, product)

    return _get_creator_counts(query, count, page)
Example #11
0
    def get_data(self, request):
        super(TopContributorsQuestions, self).get_data(request)

        # This is the base of all the metrics. Each metric branches off from
        # this to get a particular metric type, since we can't do Aggregates.
        query = AnswerMetricsMappingType.search()
        base_filters = self.get_filters()

        # This branch is to get the total number of answers for each user.
        answer_query = (
            query
            .filter(base_filters)
            .facet('creator_id', filtered=True, size=BIG_NUMBER))

        # This branch gets the number of answers that are solutions for each user.
        solutions_filter = base_filters & F(is_solution=True)
        solutions_query = (
            query
            .filter(solutions_filter)
            .facet('creator_id', filtered=True, size=BIG_NUMBER))

        # This branch gets the number of helpful votes across all answers for
        # each user. It is a raw facet because elasticutils only supports the
        # term facet type in non-raw facets. Because it is raw facet, we have
        # to also put the filter in the facet ourselves.
        helpful_query = (
            query
            .facet_raw(
                creator_id={
                    'terms_stats': {
                        'key_field': 'creator_id',
                        'value_field': 'helpful_count',
                    },
                    'facet_filter': query._process_filters(base_filters.filters),
                }))

        # Collect three lists of objects that correlates users and the appropriate metric count
        creator_answer_counts = answer_query.facet_counts()['creator_id']['terms']
        creator_solutions_counts = solutions_query.facet_counts()['creator_id']['terms']
        creator_helpful_counts = helpful_query.facet_counts()['creator_id']['terms']

        # Combine all the metric types into one big list.
        combined = defaultdict(lambda: {
            'answer_count': 0,
            'solution_count': 0,
            'helpful_vote_count': 0,
        })

        for d in creator_answer_counts:
            combined[d['term']]['user_id'] = d['term']
            combined[d['term']]['answer_count'] = d['count']

        for d in creator_solutions_counts:
            combined[d['term']]['user_id'] = d['term']
            combined[d['term']]['solution_count'] = d['count']

        for d in creator_helpful_counts:
            combined[d['term']]['user_id'] = d['term']
            # Since this is a term_stats filter, not just a term filter, it is total, not count.
            combined[d['term']]['helpful_vote_count'] = int(d['total'])

        # Sort by answer count, and get just the ids into a list.
        sort_key = self.query_values['ordering']
        if sort_key[0] == '-':
            sort_reverse = True
            sort_key = sort_key[1:]
        else:
            sort_reverse = False

        top_contributors = combined.values()
        top_contributors.sort(key=lambda d: d[sort_key], reverse=sort_reverse)
        user_ids = [c['user_id'] for c in top_contributors]
        full_count = len(user_ids)

        # Paginate those user ids.
        page_start = (self.query_values['page'] - 1) * self.query_values['page_size']
        page_end = page_start + self.query_values['page_size']
        user_ids = user_ids[page_start:page_end]

        # Get full user objects for every id on this page.
        users = UserMappingType.reshape(
            UserMappingType
            .search()
            .filter(id__in=user_ids)
            .values_dict('id', 'username', 'display_name', 'avatar', 'last_contribution_date')
            [:self.query_values['page_size']])

        # For ever user object found, mix in the metrics counts for that user,
        # and then reshape the data to make more sense to clients.
        data = []
        for u in users:
            d = combined[u['id']]
            d['user'] = u
            d['last_contribution_date'] = d['user'].get('last_contribution_date', None)
            d.pop('user_id', None)
            d['user'].pop('id', None)
            d['user'].pop('last_contribution_date', None)
            data.append(d)

        # One last sort, since ES didn't return the users in any particular order.
        data.sort(key=lambda d: d[sort_key], reverse=sort_reverse)

        # Add ranks to the objects.
        for i, contributor in enumerate(data, 1):
            contributor['rank'] = page_start + i

        return {
            'results': data,
            'count': full_count,
            'filters': self.query_values,
            'allowed_orderings': self.get_allowed_orderings(),
            'warnings': self.warnings,
        }
Example #12
0
    def get_data(self, request):
        super(TopContributorsQuestions, self).get_data(request)

        # This is the base of all the metrics. Each metric branches off from
        # this to get a particular metric type, since we can't do Aggregates.
        query = AnswerMetricsMappingType.search()
        base_filters = self.get_filters()

        # This branch is to get the total number of answers for each user.
        answer_query = (
            query
            .filter(base_filters)
            .facet('creator_id', filtered=True, size=BIG_NUMBER))

        # This branch gets the number of answers that are solutions for each user.
        solutions_filter = base_filters & F(is_solution=True)
        solutions_query = (
            query
            .filter(solutions_filter)
            .facet('creator_id', filtered=True, size=BIG_NUMBER))

        # This branch gets the number of helpful votes across all answers for
        # each user. It is a raw facet because elasticutils only supports the
        # term facet type in non-raw facets. Because it is raw facet, we have
        # to also put the filter in the facet ourselves.
        helpful_query = (
            query
            .facet_raw(
                creator_id={
                    'terms_stats': {
                        'key_field': 'creator_id',
                        'value_field': 'helpful_count',
                    },
                    'facet_filter': query._process_filters(base_filters.filters),
                }))

        # Collect three lists of objects that correlates users and the appropriate metric count
        creator_answer_counts = answer_query.facet_counts()['creator_id']['terms']
        creator_solutions_counts = solutions_query.facet_counts()['creator_id']['terms']
        creator_helpful_counts = helpful_query.facet_counts()['creator_id']['terms']

        # Combine all the metric types into one big list.
        combined = defaultdict(lambda: {
            'answer_count': 0,
            'solution_count': 0,
            'helpful_vote_count': 0,
        })

        for d in creator_answer_counts:
            combined[d['term']]['user_id'] = d['term']
            combined[d['term']]['answer_count'] = d['count']

        for d in creator_solutions_counts:
            combined[d['term']]['user_id'] = d['term']
            combined[d['term']]['solution_count'] = d['count']

        for d in creator_helpful_counts:
            combined[d['term']]['user_id'] = d['term']
            # Since this is a term_stats filter, not just a term filter, it is total, not count.
            combined[d['term']]['helpful_vote_count'] = int(d['total'])

        # Sort by answer count, and get just the ids into a list.
        sort_key = self.query_values['ordering']
        if sort_key[0] == '-':
            sort_reverse = True
            sort_key = sort_key[1:]
        else:
            sort_reverse = False

        top_contributors = combined.values()
        top_contributors.sort(key=lambda d: d[sort_key], reverse=sort_reverse)
        user_ids = [c['user_id'] for c in top_contributors]
        full_count = len(user_ids)

        # Paginate those user ids.
        page_start = (self.query_values['page'] - 1) * self.query_values['page_size']
        page_end = page_start + self.query_values['page_size']
        user_ids = user_ids[page_start:page_end]

        # Get full user objects for every id on this page.
        users = UserMappingType.reshape(
            UserMappingType
            .search()
            .filter(id__in=user_ids)
            .values_dict('id', 'username', 'display_name', 'avatar', 'last_contribution_date')
            [:self.query_values['page_size']])

        # For ever user object found, mix in the metrics counts for that user,
        # and then reshape the data to make more sense to clients.
        data = []
        for u in users:
            d = combined[u['id']]
            d['user'] = u
            d['last_contribution_date'] = d['user'].get('last_contribution_date', None)
            d.pop('user_id', None)
            d['user'].pop('id', None)
            d['user'].pop('last_contribution_date', None)
            data.append(d)

        # One last sort, since ES didn't return the users in any particular order.
        data.sort(key=lambda d: d[sort_key], reverse=sort_reverse)

        # Add ranks to the objects.
        for i, contributor in enumerate(data, 1):
            contributor['rank'] = page_start + i

        return {
            'results': data,
            'count': full_count,
            'filters': self.query_values,
            'allowed_orderings': self.get_allowed_orderings(),
            'warnings': self.warnings,
        }
Example #13
0
File: api.py Project: zu83/kitsune
    def get_data(self, request):
        super(TopContributorsQuestions, self).get_data(request)

        # This is the base of all the metrics. Each metric branches off from
        # this to get a particular metric type, since we can't do Aggregates.
        query = AnswerMetricsMappingType.search()
        base_filters = self.get_filters()

        # This branch is to get the total number of answers for each user.
        answer_query = query.filter(base_filters).facet("creator_id",
                                                        filtered=True,
                                                        size=BIG_NUMBER)

        # This branch gets the number of answers that are solutions for each user.
        solutions_filter = base_filters & F(is_solution=True)
        solutions_query = query.filter(solutions_filter).facet("creator_id",
                                                               filtered=True,
                                                               size=BIG_NUMBER)

        # This branch gets the number of helpful votes across all answers for
        # each user. It is a raw facet because elasticutils only supports the
        # term facet type in non-raw facets. Because it is raw facet, we have
        # to also put the filter in the facet ourselves.
        helpful_query = query.facet_raw(
            creator_id={
                "terms_stats": {
                    "key_field": "creator_id",
                    "value_field": "helpful_count",
                },
                "facet_filter": query._process_filters(base_filters.filters),
            })

        # Collect three lists of objects that correlates users and the appropriate metric count
        creator_answer_counts = answer_query.facet_counts(
        )["creator_id"]["terms"]
        creator_solutions_counts = solutions_query.facet_counts(
        )["creator_id"]["terms"]
        creator_helpful_counts = helpful_query.facet_counts(
        )["creator_id"]["terms"]

        # Combine all the metric types into one big list.
        combined = defaultdict(lambda: {
            "answer_count": 0,
            "solution_count": 0,
            "helpful_vote_count": 0,
        })

        for d in creator_answer_counts:
            combined[d["term"]]["user_id"] = d["term"]
            combined[d["term"]]["answer_count"] = d["count"]

        for d in creator_solutions_counts:
            combined[d["term"]]["user_id"] = d["term"]
            combined[d["term"]]["solution_count"] = d["count"]

        for d in creator_helpful_counts:
            combined[d["term"]]["user_id"] = d["term"]
            # Since this is a term_stats filter, not just a term filter, it is total, not count.
            combined[d["term"]]["helpful_vote_count"] = int(d["total"])

        # Sort by answer count, and get just the ids into a list.
        sort_key = self.query_values["ordering"]
        if sort_key[0] == "-":
            sort_reverse = True
            sort_key = sort_key[1:]
        else:
            sort_reverse = False

        top_contributors = list(combined.values())
        top_contributors.sort(key=lambda d: d[sort_key], reverse=sort_reverse)
        user_ids = [c["user_id"] for c in top_contributors]
        full_count = len(user_ids)

        # Paginate those user ids.
        page_start = (self.query_values["page"] -
                      1) * self.query_values["page_size"]
        page_end = page_start + self.query_values["page_size"]
        user_ids = user_ids[page_start:page_end]

        # Get full user objects for every id on this page.
        users = UserMappingType.reshape(
            UserMappingType.search().filter(id__in=user_ids).values_dict(
                "id", "username", "display_name", "avatar",
                "last_contribution_date")[:self.query_values["page_size"]])

        # For ever user object found, mix in the metrics counts for that user,
        # and then reshape the data to make more sense to clients.
        data = []
        for u in users:
            d = combined[u["id"]]
            d["user"] = u
            d["last_contribution_date"] = d["user"].get(
                "last_contribution_date", None)
            d.pop("user_id", None)
            d["user"].pop("id", None)
            d["user"].pop("last_contribution_date", None)
            data.append(d)

        # One last sort, since ES didn't return the users in any particular order.
        data.sort(key=lambda d: d[sort_key], reverse=sort_reverse)

        # Add ranks to the objects.
        for i, contributor in enumerate(data, 1):
            contributor["rank"] = page_start + i

        return {
            "results": data,
            "count": full_count,
            "filters": self.query_values,
            "allowed_orderings": self.get_allowed_orderings(),
            "warnings": self.warnings,
        }