Beispiel #1
0
    def _apply_agg(self, search_query):
        exclude_tags = {self.qf._name}
        if self._conj_operator == QueryFilter.CONJ_OR:
            exclude_tags.add(self.name)

        filters = self._get_agg_filters(
            search_query.get_context().iter_post_filters_with_meta(), exclude_tags
        )

        terms_agg = agg.Nested(path=self.path, aggs={
            self._filter_key_agg_name: agg.Filter(
                self.key_expression,
                aggs={
                    self._filter_value_agg_name: agg.Terms(
                        self.value_field,
                        instance_mapper=self._instance_mapper,
                        **self._agg_kwargs
                    )
                },
                **self._agg_kwargs
            )
        })
        if filters:
            aggs = {
                self._filter_agg_name: agg.Filter(
                    Bool.must(*filters), aggs={self._agg_name: terms_agg}
                )
            }
        else:
            aggs = {self._agg_name: terms_agg}

        return search_query.aggregations(**aggs)
Beispiel #2
0
    def _get_group_values(self, search_query, post_filters, pagination_agg):
        if post_filters:
            aggs = {
                self._filter_agg_name: agg.Filter(
                    Bool.must(*post_filters),
                    aggs={self._pagination_agg_name: pagination_agg}
                )
            }
        else:
            aggs = {self._pagination_agg_name: pagination_agg}

        sq = (
            search_query
            .with_search_type('count')
            .aggs(None)
            .aggs(**aggs)
        )

        pagination_agg_res = self._get_pagination_agg_result(sq.result)
        self._process_pagination_agg(pagination_agg_res)
        values = [
            group_bucket.key for group_bucket in pagination_agg_res.buckets
        ]

        offset = self._get_offset()
        return values[offset:offset + self.per_page]
Beispiel #3
0
 def _apply_agg(self, search_query):
     if self.selected:
         return search_query
     agg_filters = search_query.get_context().post_filters
     return search_query.aggregations(
         **{
             self._agg_name: agg.Filter(
                 Bool.must(*chain(agg_filters, [self._condition])))
         })
Beispiel #4
0
    def _get_expression(self, params):
        values = self._get_values_from_params(params.get(self.alias, {}))
        if not values:
            return None

        if len(values) == 1:
            return self.field == values[0]

        if self._conj_operator == QueryFilter.CONJ_AND:
            return Bool.must(*(self.field == v for v in values))
        else:
            return self.field.in_(values)
Beispiel #5
0
    def _get_expression(self, params):
        values = self._get_values_from_params(params.get(self.alias, {}))
        if not values:
            return None

        if len(values) == 1:
            return self.field == values[0]

        if self._conj_operator == QueryFilter.CONJ_AND:
            return Bool.must(*(self.field == v for v in values))
        else:
            return self.field.in_(values)
Beispiel #6
0
    def _get_expression(self, params):
        values = self._get_values_from_params(params.get(self.alias, {}))
        if not values:
            return None

        if len(values) == 1:
            return Nested(
                path=self.path,
                query=Bool.must(
                    self.key_expression,
                    self.value_field == values[0]
                )
            )

        expressions = [self.key_expression]
        if self._conj_operator == QueryFilter.CONJ_AND:
            expressions.extend([self.value_field == v for v in values])
        else:
            expressions.append(self.value_field.in_(values))

        return Nested(
            path=self.path,
            query=Bool.must(*expressions)
        )
Beispiel #7
0
    def _apply_filter(self, search_query, params):
        params = params.get(self.alias) or {}
        self.from_value = self._get_from_value(params)
        self.to_value = self._get_to_value(params)
        if self.from_value is None and self.to_value is None:
            return search_query

        expr = Nested(
            path=self.path,
            query=Bool.must(
                self.key_expression,
                self.value_field.range(gte=self.from_value, lte=self.to_value),
            )
        )
        return search_query.post_filter(expr, meta={'tags': {self.name}})
Beispiel #8
0
def test_weight():
    assert Weight(3).to_elastic() == {"weight": 3}
    assert Weight(2, filter=Bool.must(
        PostDocument.status.in_([0, 1]),
        PostDocument.created_date >= 'now/d-7d')
    ).to_elastic() == {
        "weight": 2,
        "filter": {
            "bool": {
                "must": [
                    {"terms": {"status": [0, 1]}},
                    {"range": {"created_date": {"gte": "now/d-7d"}}}
                ]
            }
        }
    }
Beispiel #9
0
    def _apply_agg(self, search_query):
        order_aggs, order_by = self._extract_orders(search_query)

        group_agg = agg.Terms(
            self.group_by,
            size=self.per_page,
            order=order_by,
            aggs=dict(
                {self._top_hits_agg_name: agg.TopHits(**self.group_kwargs)},
                **order_aggs
            )
        )

        pagination_agg = agg.Terms(
            self.group_by,
            size=self.max_items,
            order=order_by,
            aggs=order_aggs,
        )

        post_filters = list(search_query.get_context().iter_post_filters())

        if self.page == 1:
            page_aggs = {
                self._agg_name: group_agg,
                self._pagination_agg_name: pagination_agg,
            }
        else:
            group_values = self._get_group_values(search_query, post_filters, pagination_agg)
            post_filters.append(self.group_by.in_(group_values))
            page_aggs={
                self._agg_name: group_agg,
            }

        if post_filters:
            aggs = {
                self._filter_agg_name: agg.Filter(
                    Bool.must(*post_filters),
                    aggs=page_aggs
                )
            }
        else:
            aggs = page_aggs

        search_query = search_query.aggs(aggs)

        return search_query
Beispiel #10
0
    def _apply_agg(self, search_query):
        filters = self._get_agg_filters(
            search_query.get_context().iter_post_filters_with_meta(), {self.qf._name, self.name}
        )

        aggs = {}
        if self._compute_enabled:
            aggs.update({
                self._enabled_agg_name: agg.Nested(
                    path=self.path,
                    aggs={
                        self._filter_key_agg_name: agg.Filter(
                            self.key_expression,
                            aggs={
                                self._filter_value_agg_name: agg.Filter(
                                    self.value_field != None
                                )
                            }
                        )
                    }
                )
            })
        if self._compute_min_max:
            stat_aggs = {
                self._enabled_agg_name_stat: agg.Nested(
                    path=self.path,
                    aggs={
                        self._filter_key_agg_name: agg.Filter(
                            self.key_expression,
                            aggs={
                                self._min_agg_name: agg.Min(self.value_field),
                                self._max_agg_name: agg.Max(self.value_field),
                            }
                        )
                    }
                )
            }
            if filters:
                aggs.update({
                    self._filter_agg_name: agg.Filter(Bool.must(*filters), aggs=stat_aggs)
                })
            else:
                aggs.update(stat_aggs)

        return search_query.aggregations(**aggs)
Beispiel #11
0
    def _apply_agg(self, search_query):
        exclude_tags = {self.qf._name}
        if self._conj_operator == QueryFilter.CONJ_OR:
            exclude_tags.add(self.name)
        filters = self._get_agg_filters(
            search_query.iter_post_filters_with_meta(), exclude_tags
        )

        terms_agg = agg.Terms(self.field, instance_mapper=self._instance_mapper, **self._agg_kwargs)
        if filters:
            aggs = {
                self._filter_agg_name: agg.Filter(
                    Bool.must(*filters), aggs={self._agg_name: terms_agg}
                )
            }
        else:
            aggs = {self._agg_name: terms_agg}

        return search_query.aggregations(**aggs)
Beispiel #12
0
    def _apply_agg(self, search_query):
        exclude_tags = {self.qf._name}
        if self._conj_operator == QueryFilter.CONJ_OR:
            exclude_tags.add(self.name)
        filters = self._get_agg_filters(
            search_query.get_context().iter_post_filters_with_meta(), exclude_tags
        )
        additional_filters = self._filters or []

        terms_agg = agg.Terms(self.field, instance_mapper=self._instance_mapper, **self._agg_kwargs)
        if filters or additional_filters:
            aggs = {
                self._filter_agg_name: agg.Filter(
                    Bool.must(*(filters + additional_filters)),
                    aggs={self._agg_name: terms_agg}
                )
            }
        else:
            aggs = {self._agg_name: terms_agg}
        return search_query.aggregations(**aggs)
Beispiel #13
0
    def _apply_agg(self, search_query):
        exclude_tags = {self.qf._name}
        if self._conj_operator == QueryFilter.CONJ_OR:
            exclude_tags.add(self.name)
        filters = self._get_agg_filters(
            search_query.get_context().iter_post_filters_with_meta(), exclude_tags
        )

        filter_aggs = {}
        for fv in self.values:
            filter_aggs[self._make_agg_name(fv.value)] = agg.Filter(fv.expr, **self.agg_kwargs)

        if filters:
            aggs = {
                self._filter_agg_name: agg.Filter(
                    Bool.must(*filters), aggs=filter_aggs
                )
            }
        else:
            aggs = filter_aggs

        return search_query.aggregations(**aggs)
Beispiel #14
0
    def _get_expression(self, params):
        values = params.get(self.alias, {}).get('exact')
        if not values:
            if self.default:
                values = [[self.default]]
        if not values:
            return None

        expressions = []
        for v in values:
            w = v[0]
            filter_value = self.get_value(w)
            if filter_value and not isinstance(filter_value.expr, MatchAll):
                expressions.append(filter_value.expr)

        if not expressions:
            return None

        if self._conj_operator == QueryFilter.CONJ_AND:
            return Bool.must(*expressions)
        else:
            return Bool.should(*expressions)
Beispiel #15
0
    def _apply_agg(self, search_query):
        exclude_tags = {self.qf._name}
        if self._conj_operator == QueryFilter.CONJ_OR:
            exclude_tags.add(self.name)
        filters = self._get_agg_filters(
            search_query.iter_post_filters_with_meta(), exclude_tags
        )

        filter_aggs = {}
        for fv in self.values:
            filter_aggs[self._make_agg_name(fv.value)] = agg.Filter(fv.expr, **self.agg_kwargs)

        if filters:
            aggs = {
                self._filter_agg_name: agg.Filter(
                    Bool.must(*filters), aggs=filter_aggs
                )
            }
        else:
            aggs = filter_aggs

        return search_query.aggregations(**aggs)
Beispiel #16
0
    def _get_expression(self, params):
        values = params.get(self.alias, {}).get('exact')
        if not values:
            if self.default:
                values = [[self.default]]
        if not values:
            return None

        expressions = []
        for v in values:
            w = v[0]
            filter_value = self.get_value(w)
            if filter_value and not isinstance(filter_value.expr, MatchAll):
                expressions.append(filter_value.expr)

        if not expressions:
            return None

        if self._conj_operator == QueryFilter.CONJ_AND:
            return Bool.must(*expressions)
        else:
            return Bool.should(*expressions)
Beispiel #17
0
    def _apply_agg(self, search_query):
        filters = self._get_agg_filters(
            search_query.iter_post_filters_with_meta(), {self.qf._name, self.name}
        )

        aggs = {}
        if self._compute_enabled:
            aggs.update({
                self._enabled_agg_name: agg.Filter(self.field != None),
            })

        if self._compute_min_max:
            stat_aggs = {
                self._min_agg_name: agg.Min(self.field),
                self._max_agg_name: agg.Max(self.field),
            }
            if filters:
                aggs.update({
                    self._filter_agg_name: agg.Filter(Bool.must(*filters), aggs=stat_aggs)
                })
            else:
                aggs.update(stat_aggs)

        return search_query.aggregations(**aggs)
Beispiel #18
0
    def _get_filter_expression(self, attr_id: int,
                               values: ParamValues) -> t.Optional[Expression]:
        gte = self._parse_last_value(values, 'gte')
        gte_value = None
        if gte is not None:
            gte_value = merge_attr_value_float(attr_id, gte)

        lte = self._parse_last_value(values, 'lte')
        lte_value = None
        if lte is not None:
            lte_value = merge_attr_value_float(attr_id, lte)

        if gte is not None and lte is not None:
            if gte >= 0.0 and lte >= 0.0:
                return Range(self.field, gte=gte_value, lte=lte_value)
            elif gte < 0.0 and lte < 0.0:
                return Range(self.field, gte=lte_value, lte=gte_value)
            elif gte < 0.0 and lte >= 0:
                return Bool.should(
                    Range(self.field,
                          gte=self._minus_zero(attr_id),
                          lte=gte_value),
                    Range(self.field,
                          gte=self._plus_zero(attr_id),
                          lte=lte_value),
                )
            else:
                return Bool.must(
                    Range(self.field,
                          gte=gte_value,
                          lte=self._plus_inf(attr_id)),
                    Range(self.field,
                          gte=lte_value,
                          lte=self._minus_inf(attr_id)),
                )

        if gte is not None:
            if gte >= 0.0:
                return Range(self.field,
                             gte=gte_value,
                             lte=self._plus_inf(attr_id))
            else:
                return Bool.should(
                    Range(self.field,
                          gte=self._minus_zero(attr_id),
                          lte=gte_value),
                    Range(self.field,
                          gte=self._plus_zero(attr_id),
                          lte=self._plus_inf(attr_id)),
                )

        if lte is not None:
            if lte < 0.0:
                return Range(self.field,
                             gte=lte_value,
                             lte=self._minus_inf(attr_id))
            else:
                return Bool.should(
                    Range(self.field,
                          gte=self._plus_zero(attr_id),
                          lte=lte_value),
                    Range(self.field,
                          gte=self._minus_zero(attr_id),
                          lte=self._minus_inf(attr_id)),
                )

        return None
Beispiel #19
0
def test_attr_bool_facet_filter__multiple_selected_values(bool_qf, compiler):
    sq = bool_qf.apply(SearchQuery(), {'a1': ['true', 'false'], 'a2': 'true'})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_bool.filter':
        agg.Filter(
            Bool.must(
                Terms('attr.bool', [0b11, 0b10]),
                Term('attr.bool', 0b101),
            ),
            aggs={'qf.attr_bool': agg.Terms(Field('attr.bool'), size=100)}),
        'qf.attr_bool.filter:1':
        agg.Filter(Term('attr.bool', 0b101),
                   aggs={
                       'qf.attr_bool:1':
                       agg.Terms(Field('attr.bool'),
                                 size=2,
                                 include=[0b10, 0b11])
                   }),
        'qf.attr_bool.filter:2':
        agg.Filter(Terms('attr.bool', [0b11, 0b10]),
                   aggs={
                       'qf.attr_bool:2':
                       agg.Terms(Field('attr.bool'),
                                 size=2,
                                 include=[0b100, 0b101])
                   }),
    }).post_filter(
        Bool.must(
            Terms('attr.bool', [0b11, 0b10]),
            Term('attr.bool', 0b101),
        )).to_dict(compiler=compiler))
    qf_res = bool_qf.process_result(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_bool.filter': {
                        'doc_count': 200,
                        'qf.attr_bool': {
                            'buckets': [
                                {
                                    'key': 0b11,
                                    'doc_count': 123,
                                },
                                {
                                    'key': 0b101,
                                    'doc_count': 1
                                },
                            ]
                        }
                    },
                    'qf.attr_bool.filter:1': {
                        'doc_count': 163,
                        'qf.attr_bool:1': {
                            'buckets': [
                                {
                                    'key': 0b11,
                                    'doc_count': 123,
                                },
                                {
                                    'key': 0b10,
                                    'doc_count': 99
                                },
                            ]
                        }
                    },
                    'qf.attr_bool.filter:2': {
                        'doc_count': 144,
                        'qf.attr_bool:2': {
                            'buckets': [
                                {
                                    'key': 0b101,
                                    'doc_count': 1
                                },
                            ]
                        }
                    },
                }
            },
            aggregations=sq.get_context().aggregations))
    assert len(qf_res.attr_bool.facets) == 2
    facet = qf_res.attr_bool.get_facet(1)
    assert len(facet.all_values) == 2
    assert len(facet.selected_values) == 2
    assert len(facet.values) == 0
    assert facet.all_values[0] is facet.selected_values[0]
    assert facet.all_values[1] is facet.selected_values[1]
    assert facet.all_values[0].value is True
    assert facet.all_values[0].count == 123
    assert facet.all_values[0].count_text == '123'
    assert facet.all_values[0].selected is True
    assert facet.all_values[1].value is False
    assert facet.all_values[1].count == 99
    assert facet.all_values[1].count_text == '99'
    assert facet.all_values[1].selected is True
    facet = qf_res.attr_bool.get_facet(2)
    assert len(facet.all_values) == 1
    assert len(facet.selected_values) == 1
    assert len(facet.values) == 0
    assert facet.all_values[0] is facet.selected_values[0]
    assert facet.all_values[0].value is True
    assert facet.all_values[0].count == 1
    assert facet.all_values[0].count_text == '1'
    assert facet.all_values[0].selected is True