def get_default_filters(self, request): fields = super(InitiativeSearchFilter, self).get_filter_fields(request) permission = 'initiatives.api_read_initiative' if not request.user.has_perm(permission): filters = [Term(owner_id=request.user.id)] if 'owner.id' not in fields: filters.append(Term(status='approved')) return filters elif 'owner.id' in fields and request.user.is_authenticated: value = request.user.pk return [ Nested(path='owner', query=Term(owner__id=value)) | Nested(path='promoter', query=Term(promoter__id=value)) | Nested(path='activity_manager', query=Term(activity_manager__id=value)) | Nested(path='activity_owners', query=Term(activity_owners__id=value)) | Term(status='approved') ] else: return [Term(status='approved')]
def get_filter(self, request, field): # Also return activity_manger.id when filtering on owner.id if field == 'owner.id': value = request.GET['filter[{}]'.format(field)] return Q( Nested(path='owner', query=Term(**{field: value})) | Nested(path='promoter', query=Term(promoter__id=value)) | Nested(path='activity_owners', query=Term(activity_owners__id=value)) | Nested(path='activity_manager', query=Term(activity_manager__id=value))) return super(InitiativeSearchFilter, self).get_filter(request, field)
def _get_nested_query(self, *, query, path, fields): """Generate a nested query with passed parameters.""" queries = self._get_queries( query=query, fields=fields, ) raw_fields = [ # Remove boosting from the field re.sub(r'\^.*$', '', field) for field in fields ] # Highlight from the raw fields too, if it is a single term. if self._is_single_term(query): raw_fields.extend( [re.sub(r'\^.*$', '.raw', field) for field in fields]) highlight = dict( self._highlight_options, fields={field: {} for field in raw_fields}, ) return Nested( path=path, inner_hits={'highlight': highlight}, query=Bool(should=queries), )
def _get_nested_query(self, *, query, path, fields): """Generate a nested query with passed parameters.""" queries = self._get_queries( query=query, fields=fields, ) raw_fields = [ # Remove boosting from the field re.sub(r'\^.*$', '', field) for field in fields ] highlight = dict( self._highlight_options, fields={ field: {} for field in raw_fields }, ) return Nested( path=path, inner_hits={'highlight': highlight}, query=Bool(should=queries), )
def keywords_query(query, lang): return Nested( path='keywords', query=Bool( must=[Term(keywords__name=query), Term(keywords__language=lang)]), )
def get_filter(self, request, field): value = request.GET['filter[{}]'.format(field)] if '.' in field: path = field.split('.')[0] return Nested(path=path, query=Term(**{field: value})) else: try: return getattr(self, 'get_{}_filter'.format(field))(value, request) except AttributeError: return Term(**{field: value})
def get_default_filters(self, request): permission = 'activities.api_read_activity' if not request.user.has_perm(permission): return [ Nested( path='owner', query=Term(owner__id=request.user.pk) ), ~Terms(status=['draft', 'needs_work', 'submitted', 'deleted', 'closed', 'cancelled']) ] else: return [ ~Terms(status=['draft', 'needs_work', 'submitted', 'deleted', 'closed', 'cancelled']) ]
def generate_nested_query(self, query, path, fields, inner_hits): """Generate a nested query with passed parameters.""" queries = [] for operator in self.operators: query_string = SimpleQueryString(query=query, fields=fields, default_operator=operator) queries.append(query_string) bool_query = Bool(should=queries) nested_query = Nested(path=path, inner_hits=inner_hits, query=bool_query) return nested_query
def get_filters(self, request): filters = super(ActivitySearchFilter, self).get_filters(request) regex = re.compile('^filter\[segment\.(?P<type>[\w\-]+)\]$') for key, value in list(request.GET.items()): matches = regex.match(key) if matches: filters.append( Nested( path='segments', query=Term( segments__type=matches.groupdict()['type'] ) & Term( segments__id=value ) ) ) return filters
def get_search_query(self, request): terms = request.GET.get(self.search_field) if terms: queries = [] for field in self.search_fields: boost = self.boost.get(field, 1) if '.' in field: path = field.split('.')[0] query = Nested( path=path, query=MatchPhrasePrefix( **{field: {'query': terms, 'boost': boost}} ) ) else: query = MatchPhrasePrefix(**{field: {'query': terms, 'boost': boost}}) queries.append(query) return Bool(should=queries)
def _get_nested_query(self, *, query, path, fields): """Generate a nested query with passed parameters.""" queries = self._get_queries( query=query, fields=fields, ) bool_query = Bool(should=queries) raw_fields = [ # Remove boosting from the field re.sub(r'\^.*$', '', field) for field in fields ] # The ``post_filter`` filter will only filter documents # at the parent level (domains is a nested document), # resulting in results with domains that don't match the current # role_name being filtered, so we need to force filtering by role_name # on the ``domains`` document here. See #8268. # TODO: We should use a flattened document instead # to avoid this kind of problems and have faster queries. role_name = self.filter_values.get('role_name') if path == 'domains' and role_name: role_name_query = Bool(must=Terms( **{'domains.role_name': role_name})) bool_query = Bool(must=[role_name_query, bool_query]) highlight = dict( self._highlight_options, fields={field: {} for field in raw_fields}, ) return Nested( path=path, inner_hits={'highlight': highlight}, query=bool_query, )
def aggregate(self, request, queryset, view): filter_query_params = self.get_filter_query_params(request, view).values() __facets = self.construct_facets(request, view) __nested_facets = self.construct_nested_facets(request, view) __facets.update(__nested_facets) for __field, __facet in __facets.items(): agg = __facet["facet"].get_aggregation() agg_filter = Q("match_all") global_facet = __facet.get("global", False) nested_facet = "path" in __facet for options in filter_query_params: if nested_facet: if __facet["filter_field"] == options["field"] or __facet[ "filter_field"] == options.get( "filter_field" ): # Don't filter nested aggregation on its own field continue else: if __field == options["field"] or __field == options.get( "filter_field" ): # Don't filter aggregation on its own field continue if (isinstance(options["values"], (list, tuple)) and options["lookup"] is None): if "path" in options: # Filter term is nested if options["path"] == "keywords": for val in options["values"]: agg_filter &= Nested( path=options["path"], query=MatchPhrase( **{options["field"]: val}), ) else: agg_filter &= Nested( path=options["path"], query=Terms( **{options["field"]: options["values"]}), ) else: agg_filter &= Q( "terms", **{options["field"]: options["values"]}) continue lookup_filter = Q("match_all") for value in options["values"]: if options["lookup"] == LOOKUP_FILTER_TERMS: lookup_filter &= Q( "terms", **{ options["field"]: self.split_lookup_complex_value(value) }, ) elif options["lookup"] == LOOKUP_FILTER_RANGE: lookup_filter &= Q( "range", **{options["field"]: self.get_range_params(value)}) elif options["lookup"] == LOOKUP_QUERY_GT: lookup_filter &= Q( "range", **{ options["field"]: self.get_gte_lte_params(value, "gt") }, ) elif options["lookup"] == LOOKUP_QUERY_GTE: lookup_filter &= Q( "range", **{ options["field"]: self.get_gte_lte_params(value, "gte") }, ) elif options["lookup"] == LOOKUP_QUERY_LT: lookup_filter &= Q( "range", **{ options["field"]: self.get_gte_lte_params(value, "lt") }, ) elif options["lookup"] == LOOKUP_QUERY_LTE: lookup_filter &= Q( "range", **{ options["field"]: self.get_gte_lte_params(value, "lte") }, ) elif options["lookup"] == "match_phrase": lookup_filter &= MatchPhrase( **{options["field"]: value}) if "path" in options: # Filter term is nested agg_filter &= Nested(path=options["path"], query=lookup_filter) else: agg_filter &= lookup_filter if nested_facet: if global_facet: queryset.aggs.bucket( "_filter_" + __field, "global" ).bucket( # Filter must appear BEFORE nested aggregation to have effect "_filter_" + __field, "filter", filter=agg_filter, ).bucket("_filter_" + __field, "nested", path=__facet["path"]).bucket(__field, agg) else: queryset.aggs.bucket("_filter_" + __field, "filter", filter=agg_filter).bucket( "_filter_" + __field, "nested", path=__facet["path"]).bucket( __field, agg) else: if global_facet: queryset.aggs.bucket("_filter_" + __field, "global").bucket( "_filter_" + __field, "filter", filter=agg_filter).bucket( __field, agg) else: queryset.aggs.bucket("_filter_" + __field, "filter", filter=agg_filter).bucket( __field, agg) return queryset
def get_sort_popularity(self, request): score = FunctionScore( score_mode='sum', functions=[ SF( 'field_value_factor', field='status_score', weight=10, factor=10 ), SF( 'gauss', weight=0.1, created={ 'scale': "365d" }, ), ] ) | FunctionScore( score_mode='multiply', functions=[ SF( 'field_value_factor', field='contribution_count', missing=0 ), SF( 'gauss', weight=0.1, multi_value_mode='avg', contributions={ 'scale': '5d' }, ), ] ) if request.user.is_authenticated: if request.user.skills: score = score | FunctionScore( score_mode='first', functions=[ SF({ 'filter': Nested( path='expertise', query=Q( 'terms', expertise__id=[skill.pk for skill in request.user.skills.all()] ) ), 'weight': 1, }), SF({'weight': 0}), ] ) if request.user.favourite_themes: score = score | FunctionScore( score_mode='first', functions=[ SF({ 'filter': Nested( path='theme', query=Q( 'terms', theme__id=[theme.pk for theme in request.user.favourite_themes.all()] ) ), 'weight': 1, }), SF({'weight': 0}), ] ) position = None if request.user.location and request.user.location.position: position = { 'lat': request.user.location.position.latitude, 'lon': request.user.location.position.longitude } elif request.user.place and request.user.place.position: position = { 'lat': request.user.place.position.latitude, 'lon': request.user.place.position.longitude } if position: score = score | FunctionScore( score_mode='first', functions=[ SF({ 'filter': {'exists': {'field': 'position'}}, 'weight': 1, 'gauss': { 'position': { 'origin': position, 'scale': "100km" }, 'multi_value_mode': 'max', }, }), SF({'weight': 0}), ] ) return score