From 7f1b7f639c7574ee09a49681fac0adcbceb569a4 Mon Sep 17 00:00:00 2001 From: Nicolas Dietrich Date: Fri, 8 Feb 2013 01:05:54 +0100 Subject: [PATCH] Fix facet item counts for facets with exclusive values The solution to calculate facet item counts for facets with exclusive values in 9e7c7c46568dd370019a61978655bac248ab21e9 was wrong and only worked for simple cases. The general solution in this commit instead does the following: For each facet with exclusive values, create another solr query, which is the same as the current main query (facet_query), but without the filter on that same facet. This would normally be done in solr with `LocalParams`, but this isn't yet implemented in sunburnt (see tow/sunburnt#6). A workaround (as described in the latter issue) would be possible if sunburnt would allow to create multiple filter query parts instead of putting them together in one filter query with `AND` constructs (see tow/sunburnt#37). --- adhocracy/lib/pager.py | 56 +++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/adhocracy/lib/pager.py b/adhocracy/lib/pager.py index 1a4b77581..c3e613b7d 100644 --- a/adhocracy/lib/pager.py +++ b/adhocracy/lib/pager.py @@ -425,11 +425,15 @@ class SolrFacet(SolrIndexer): >>> some_facet = SomeFacet('mypager_prefix', request) >>> q = solr_query() >>> counts_query = q - >>> # configure the query further - >>> q, counts_query = some_facet.add_to_queries(q, counts_query) + >>> exclusive_qs = [] + >>> # configure the queries further + >>> q, counts_query, exclusive_qs = some_facet.add_to_queries(q, exclusive_qs) >>> response = q.execute() >>> counts_response = counts_response.execute() - >>> some_facet.update(response, counts_response) + >>> exclusive_responses = dict([counts_response = counts_response.execute() + >>> exclusive_responses = dict(map(lambda ((k, q)): (k, q.execute()), + ... exclusive_qs.iteritems())) + >>> some_facet.update(response, counts_response, exclusive_responses) >>> some_facet.items [...] """ @@ -476,7 +480,7 @@ def get_thumbnail(self, entity): ''' return '' - def add_to_queries(self, query, counts_query): + def add_to_queries(self, query, counts_query, exclusive_queries): ''' Add the facet to the queries *query* and *counts_query*. The difference is that the *query* will be limited to facet values @@ -486,11 +490,21 @@ def add_to_queries(self, query, counts_query): ''' query = query.facet_by(self.solr_field) counts_query = counts_query.facet_by(self.solr_field) + + if self.exclusive: + exclusive_queries[self.solr_field] =\ + exclusive_queries[self.solr_field].facet_by(self.solr_field) + for value in self.used: query = query.query(**{self.solr_field: value}) - return query, counts_query - def update(self, response, counts_response): + for k, v in exclusive_queries.iteritems(): + if k != self.solr_field: + exclusive_queries[k] = v.query(**{self.solr_field: value}) + + return query, counts_query, exclusive_queries + + def update(self, response, counts_response, exclusive_responses): ''' Compute and update different attributes of the facet based on the solr *response* and the *base_query*. @@ -514,6 +528,18 @@ def update(self, response, counts_response): key=lambda(value, count): count, reverse=True) self.facet_counts = dict(self.sorted_facet_counts) + + # the counts in the current query without the current query for this + # facet if this is an exclusive (single value) facet + if self.exclusive: + exclusive_counts = exclusive_responses[solr_field]\ + .facet_counts.facet_fields[solr_field] + self.sorted_exclusive_counts = sorted( + exclusive_counts, + key=lambda(value, count): count, + reverse=True) + self.exclusive_counts = dict(self.sorted_exclusive_counts) + self.current_items = self._current_items() # fixme: memoize @@ -593,7 +619,7 @@ def show_facet(current_count, token_count, show_empty, facet_items = OrderedDict() for (token, token_count) in token_counts: if self.exclusive: - current_count = self.facet_counts[token] + current_count = self.exclusive_counts[token] else: current_count = self.current_counts[token] @@ -1094,10 +1120,18 @@ def __init__(self, name, itemfunc, entity_type=None, extra_filter=None, # Add facets counts_query = query counts_query = counts_query.paginate(rows=0) + + exclusive_queries = dict((f.solr_field, counts_query) + for f in self.facets if f.exclusive) + query.faceter.update(limit='65000') counts_query.faceter.update(limit='65000') + map(lambda q: q.faceter.update(limit='65000'), + exclusive_queries.values()) + for facet in self.facets: - query, counts_query = facet.add_to_queries(query, counts_query) + query, counts_query, exclusive_queries = facet.add_to_queries( + query, counts_query, exclusive_queries) # Add pagination and sorting if enable_pages: @@ -1109,6 +1143,9 @@ def __init__(self, name, itemfunc, entity_type=None, extra_filter=None, # query solr and calculate values from it self.response = query.execute() self.counts_response = counts_query.execute() + self.exclusive_responses = dict(map(lambda ((k, q)): (k, q.execute()), + exclusive_queries.iteritems())) + # if we are out of the page range do a permanent redirect # to the last page if (self.pages > 0) and (self.page > self.pages): @@ -1116,7 +1153,8 @@ def __init__(self, name, itemfunc, entity_type=None, extra_filter=None, redirect(new_url, code=301) for facet in self.facets: - facet.update(self.response, self.counts_response) + facet.update(self.response, self.counts_response, + self.exclusive_responses) self.items = self._items_from_response(self.response) def total_num_items(self):