Another agg ES response strategy

This commit is contained in:
Kuroshini 2019-11-28 21:24:39 +03:00
parent 9b02b855d6
commit 68626e9fd5
3 changed files with 82 additions and 7 deletions

View File

@ -1,7 +1,48 @@
"""Search indexes filters."""
from elasticsearch_dsl.query import Q
from django_elasticsearch_dsl_drf.filter_backends import SearchFilterBackend
from django_elasticsearch_dsl_drf.filter_backends import SearchFilterBackend, FacetedSearchFilterBackend
from search_indexes.utils import OBJECT_FIELD_PROPERTIES
from six import iteritems
class CustomFacetedSearchFilterBackend(FacetedSearchFilterBackend):
def __init__(self):
self.facets_computed = {}
def aggregate(self, request, queryset, view):
"""Aggregate.
:param request:
:param queryset:
:param view:
:return:
"""
def makefilter(cur_facet):
def myfilter(x):
return cur_facet['facet']._params['field'] != next(iter(x._params))
return myfilter
__facets = self.construct_facets(request, view)
for __field, __facet in iteritems(__facets):
agg = __facet['facet'].get_aggregation()
agg_filter = Q('match_all')
if __facet['global']:
queryset.aggs.bucket(
'_filter_' + __field,
'global'
).bucket(__field, agg)
else:
qs = queryset._clone()
filterer = makefilter(__facet)
qs.query._proxied._params['must'] = list(filter(filterer, qs.query._proxied._params['must']))
facet_name = '_filter_' + __field
qs.aggs.bucket(
facet_name,
'filter',
filter=agg_filter
).bucket(__field, agg)
self.facets_computed.update({facet_name: qs.execute().aggregations[facet_name]})
return queryset
class CustomSearchFilterBackend(SearchFilterBackend):

View File

@ -14,7 +14,25 @@ from search_indexes.documents.product import ProductDocument
from utils.pagination import ESDocumentPagination
class NewsDocumentViewSet(BaseDocumentViewSet):
class FacetedResponseMixin:
def filter_queryset(self, queryset):
"""
Given a queryset, filter it with whichever filter backend is in use.
You are unlikely to want to override this method, although you may need
to call it either from a list view, or from a custom `get_object`
method if you want to apply the configured filtering backend to the
default queryset.
"""
for backend in list(self.filter_backends):
bc = backend()
queryset = bc.filter_queryset(self.request, queryset, self)
if hasattr(bc, 'facets_computed'):
setattr(self, 'facets_computed', bc.facets_computed)
return queryset
class NewsDocumentViewSet(BaseDocumentViewSet, FacetedResponseMixin):
"""News document ViewSet."""
document = NewsDocument
@ -26,7 +44,7 @@ class NewsDocumentViewSet(BaseDocumentViewSet):
filter_backends = [
filters.CustomSearchFilterBackend,
FilteringFilterBackend,
FacetedSearchFilterBackend,
filters.CustomFacetedSearchFilterBackend,
]
faceted_search_fields = {
@ -86,7 +104,7 @@ class MobileNewsDocumentViewSet(NewsDocumentViewSet):
]
class EstablishmentDocumentViewSet(BaseDocumentViewSet):
class EstablishmentDocumentViewSet(BaseDocumentViewSet, FacetedResponseMixin):
"""Establishment document ViewSet."""
document = EstablishmentDocument
@ -103,7 +121,7 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
FilteringFilterBackend,
filters.CustomSearchFilterBackend,
GeoSpatialFilteringFilterBackend,
FacetedSearchFilterBackend,
filters.CustomFacetedSearchFilterBackend,
]
faceted_search_fields = {
@ -306,7 +324,7 @@ class ProductDocumentViewSet(BaseDocumentViewSet):
filter_backends = [
FilteringFilterBackend,
filters.CustomSearchFilterBackend,
FacetedSearchFilterBackend,
filters.CustomFacetedSearchFilterBackend,
]
search_fields = {

View File

@ -6,7 +6,6 @@ from django.conf import settings
from rest_framework.pagination import CursorPagination, PageNumberPagination
from django_elasticsearch_dsl_drf.pagination import PageNumberPagination as ESPagination
class ProjectPageNumberPagination(PageNumberPagination):
"""Customized pagination class."""
@ -65,6 +64,23 @@ class ESDocumentPagination(ESPagination):
return None
return self.page.previous_page_number()
def get_facets(self, page=None):
"""Get facets.
:param page:
:return:
"""
if page is None:
page = self.page
if hasattr(self, 'facets_computed'):
ret = {}
for filter_field, bucket_data in self.facets_computed.items():
ret.update({filter_field: bucket_data.__dict__['_d_']})
return ret
elif hasattr(page, 'facets') and hasattr(page.facets, '_d_'):
return page.facets._d_
class EstablishmentPortionPagination(ProjectMobilePagination):
"""