コード例 #1
0
def test_attr_int_facet_filter__include_values(int_qf_with_values, compiler):
    sq = int_qf_with_values.apply(SearchQuery(), {'a18': '58084'})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_int.filter':
        agg.Filter(
            Term('attr.int', 0x12_0000e2e4),
            aggs={'qf.attr_int': agg.Terms(Field('attr.int'), size=10_000)}),
        'qf.attr_int:18':
        agg.Terms(Field('attr.int'),
                  size=100,
                  include=[0x12_0000e2e4, 0x12_0000e7e5])
    }).post_filter(Term('attr.int', 0x12_0000e2e4)).to_dict(compiler=compiler))
コード例 #2
0
def test_attr_int_facet_filter__empty_params(int_qf, compiler):
    sq = int_qf.apply(SearchQuery(), {})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_int':
        agg.Terms(Field('attr.int'), size=10_000)
    }).to_dict(compiler=compiler))
    qf_res = int_qf.process_result(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_int': {
                        'buckets': [{
                            'key': 0x12_00000001,
                            'doc_count': 123,
                        }, {
                            'key': 0x144_0000dead,
                            'doc_count': 99
                        }, {
                            'key': 0x12_f0000000,
                            'doc_count': 1
                        }]
                    }
                }
            },
            aggregations=sq.get_context().aggregations))
コード例 #3
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)
コード例 #4
0
def test_attr_int_facet_filter__single_selected_value(int_qf, compiler):
    params = {'a18': '58084'}
    sq = int_qf.apply(SearchQuery(), params)
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_int.filter':
        agg.Filter(Term('attr.int', 0x12_0000e2e4),
                   aggs={
                       'qf.attr_int': agg.Terms(Field('attr.int'),
                                                size=10_000),
                   }),
        'qf.attr_int:18':
        agg.Terms(Field('attr.int'), size=100),
    }).post_filter(Term('attr.int', 0x12_0000e2e4)).to_dict(compiler=compiler))
    qf_res = int_qf.process_result(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_int.filter': {
                        'doc_count': 201,
                        'qf.attr_int': {
                            'buckets': [{
                                'key': 0x144_0000dead,
                                'doc_count': 123,
                            }, {
                                'key': 0x12_0000e2e4,
                                'doc_count': 119
                            }, {
                                'key': 0x144_0000beef,
                                'doc_count': 1
                            }]
                        }
                    },
                    'qf.attr_int:18': {
                        'buckets': [
                            {
                                'key': 0x12_0000e2e4,
                                'doc_count': 99
                            },
                            {
                                'key': 0x12_0000e7e5,
                                'doc_count': 88
                            },
                        ]
                    }
                }
            },
            aggregations=sq.get_context().aggregations))
コード例 #5
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
コード例 #6
0
def test_attr_int_facet_filter__existing_post_filter(int_qf, compiler):
    sq = int_qf.apply(SearchQuery().post_filter(Range('price', lt=100)), {})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_int.filter':
        agg.Filter(
            Range('price', lt=100),
            aggs={'qf.attr_int': agg.Terms(Field('attr.int'), size=10_000)})
    }).post_filter(Range('price', lt=100)).to_dict(compiler=compiler))

    sq = int_qf.apply(
        SearchQuery().post_filter(Range('price', lt=100), meta={'price':
                                                                True}), {})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_int.filter':
        agg.Filter(
            Range('price', lt=100),
            aggs={'qf.attr_int': agg.Terms(Field('attr.int'), size=10_000)})
    }).post_filter(Range('price', lt=100)).to_dict(compiler=compiler))
コード例 #7
0
def test_attr_range_facet_filter__single_selected_filter(range_qf, compiler):
    sq = range_qf.apply(SearchQuery(), {'a8__gte': 2.71})
    assert_search_query(
        sq,
        SearchQuery().aggs({
            'qf.attr_range.filter':
            agg.Filter(Range('attr.float', gte=0x8_402d70a4, lte=0x8_7f800000),
                       aggs={
                           'qf.attr_range':
                           agg.Terms(script=Script(
                               'doc[params.field].value >>> 32',
                               lang='painless',
                               params={
                                   'field': 'attr.float',
                               }),
                                     size=100)
                       }),
            'qf.attr_range:8':
            agg.Filter(Range('attr.float', gte=0x8_00000000,
                             lte=0x8_ffffffff), )
        }).post_filter(Range('attr.float', gte=0x8_402d70a4,
                             lte=0x8_7f800000)), compiler)

    qf_res = range_qf.process_results(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_range.filter': {
                        'doc_count': 32,
                        'qf.attr_range': {
                            'buckets': [{
                                'key': 8,
                                'doc_count': 32
                            }, {
                                'key': 439,
                                'doc_count': 18
                            }]
                        }
                    },
                    'qf.attr_range:8': {
                        'doc_count': 84
                    }
                }
            },
            aggregations=sq.get_context().aggregations))
    assert qf_res.attr_range.name == 'attr_range'
    assert qf_res.attr_range.alias == 'a'
    f = qf_res.attr_range.get_facet(8)
    assert f.attr_id == 8
    assert f.count == 84
    assert f.selected is True
    f = qf_res.attr_range.get_facet(439)
    assert f.attr_id == 439
    assert f.count == 18
    assert f.selected is False
コード例 #8
0
def test_attr_range_facet_filter__existing_post_filter(range_qf, compiler):
    sq = range_qf.apply(SearchQuery().post_filter(Field('status').term(0)), {})
    assert_search_query(
        sq,
        SearchQuery().aggs({
            'qf.attr_range.filter':
            agg.Filter(Term('status', 0),
                       aggs={
                           'qf.attr_range':
                           agg.Terms(script=Script(
                               'doc[params.field].value >>> 32',
                               lang='painless',
                               params={
                                   'field': 'attr.float',
                               }),
                                     size=100),
                       }),
        }).post_filter(Term('status', 0)), compiler)
コード例 #9
0
def test_attr_bool_facet_filter__empty_params(bool_qf, compiler):
    sq = bool_qf.apply(SearchQuery(), {})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_bool':
        agg.Terms(Field('attr.bool'), size=100)
    }).to_dict(compiler=compiler))
    qf_res = bool_qf.process_result(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_bool': {
                        'buckets': [{
                            'key': 0b11,
                            'doc_count': 123,
                        }, {
                            'key': 0b10,
                            'doc_count': 99
                        }, {
                            '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 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 False
    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 False
    facet = qf_res.attr_bool.get_facet(2)
    assert len(facet.all_values) == 1
    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 False
コード例 #10
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)
コード例 #11
0
def test_attr_range_facet_filter__empty(range_qf, compiler):
    sq = range_qf.apply(SearchQuery(), {})
    assert_search_query(
        sq,
        SearchQuery().aggs({
            'qf.attr_range':
            agg.Terms(script=Script('doc[params.field].value >>> 32',
                                    lang='painless',
                                    params={
                                        'field': 'attr.float',
                                    }),
                      size=100),
        }), compiler)

    qf_res = range_qf.process_results(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_range': {
                        'buckets': [{
                            'key': '8',
                            'doc_count': 84
                        }, {
                            'key': '439',
                            'doc_count': 28
                        }]
                    }
                }
            },
            aggregations=sq.get_context().aggregations))
    assert qf_res.attr_range.name == 'attr_range'
    assert qf_res.attr_range.alias == 'a'
    f = qf_res.attr_range.get_facet(8)
    assert f.attr_id == 8
    assert f.count == 84
    assert f.selected is False
    f = qf_res.attr_range.get_facet(439)
    assert f.attr_id == 439
    assert f.count == 28
    assert f.selected is False
コード例 #12
0
    def test_aggregations(self):
        f = DynamicDocument.fields

        sq = SearchQuery().aggregations(min_price=agg.Min(f.price))
        self.assert_expression(
            sq,
            {
                "aggregations": {
                    "min_price": {
                        "min": {"field": "price"}
                    }
                }
            }
        )
        self.assertEqual(collect_doc_classes(sq), {DynamicDocument})

        sq = SearchQuery().aggregations(genders=agg.Terms(f.gender))
        self.assert_expression(
            sq,
            {
                "aggregations": {
                    "genders": {
                        "terms": {"field": "gender"}
                    }
                }
            }
        )
        self.assertEqual(collect_doc_classes(sq), {DynamicDocument})

        sq = (
            SearchQuery()
            .aggregations(
                type=agg.Terms(f.type, aggs={'min_price': agg.Min(f.price)})
            )
        )
        self.assert_expression(
            sq,
            {
                "aggregations": {
                    "type": {
                        "terms": {"field": "type"},
                        "aggregations": {
                            "min_price": {
                                "min": {"field": "price"}
                            }
                        }
                    }
                }
            },
        )
        self.assertEqual(collect_doc_classes(sq), {DynamicDocument})

        sq = (
            SearchQuery()
            .aggregations(
                top_tags=(
                    agg.Terms(
                        f.tags,
                        size=3,
                        aggs={
                            'top_tag_hits': agg.TopHits(
                                sort=f.last_activity_date.desc(),
                                size=1,
                                _source=Params(include=[f.title]))
                        }
                    )
                )
            )
        )
        self.assert_expression(
            sq,
            {
                "aggregations": {
                    "top_tags": {
                        "terms": {
                            "field": "tags",
                            "size": 3
                        },
                        "aggregations": {
                            "top_tag_hits": {
                                "top_hits": {
                                    "sort": {
                                        "last_activity_date": "desc"
                                    },
                                    "_source": {
                                        "include": ["title"]
                                    },
                                    "size" : 1
                                }
                            }
                        }
                    }
                }
            }  
        )
        self.assertEqual(collect_doc_classes(sq), {DynamicDocument})

        sq = (
            SearchQuery()
            .aggregations({
                'top_sites': agg.Terms(
                    f.domain,
                    order=Sort('top_hit', 'desc'),
                    aggs={
                        'top_tags_hits': agg.TopHits(),
                        'top_hit': agg.Max(script='_doc.score'),
                    }
                )
            })
        )
        self.assert_expression(
            sq,
            {
                "aggregations": {
                    "top_sites": {
                        "terms": {
                            "field": "domain",
                            "order": {
                                "top_hit": "desc"
                            }
                        },
                        "aggregations": {
                            "top_tags_hits": {
                                "top_hits": {}
                            },
                            "top_hit" : {
                                "max": {
                                    "script": "_doc.score"
                                }
                            }
                        }
                    }
                }
            }
        )
        self.assertEqual(collect_doc_classes(sq), {DynamicDocument})
コード例 #13
0
    def test_instance_mapper(self):
        class _Gender(object):
            def __init__(self, key, title):
                self.key = key
                self.title = title

        Male = _Gender('m', 'Male')
        Female = _Gender('f', 'Female')
        GENDERS = {g.key: g for g in [Male, Female]}

        f = DynamicDocument.fields

        gender_mapper = Mock(return_value=GENDERS)
        a = agg.Terms(f.gender, instance_mapper=gender_mapper)
        a = a.build_agg_result(
            {
                "buckets": [
                    {
                        "key": "m",
                        "doc_count": 10
                    },
                    {
                        "key": "f",
                        "doc_count": 10
                    },
                ]
            }
        )
        self.assertEqual(len(a.buckets), 2)
        self.assertEqual(a.buckets[0].instance.title, 'Male')
        self.assertEqual(a.buckets[1].instance.title, 'Female')
        self.assertEqual(gender_mapper.call_count, 1)

        gender_mapper = Mock(return_value=GENDERS)
        a = agg.Global(
            aggs={
                'all_genders': agg.Terms(f.gender, instance_mapper=gender_mapper),
                'all_salary': agg.Range(
                    f.month_salary,
                    ranges=[
                        {'to': 1000},
                        {'from': 1000, 'to': 2000},
                        {'from': 2000, 'to': 3000},
                        {'from': 3000},
                    ],
                    aggs={
                        'gender': agg.Terms(f.gender, instance_mapper=gender_mapper)
                    }
                )
            }
        )
        a = a.build_agg_result(
            {
                "doc_count": 1819,
                "all_genders": {
                    "buckets": [
                        {
                            "key": "m",
                            "doc_count": 1212
                        },
                        {
                            "key": "f",
                            "doc_count": 607
                        }
                    ]
                },
                "all_salary": {
                    "buckets": [
                        {
                            "to": 1000,
                            "doc_count": 183,
                            "gender": {
                                "buckets": [
                                    {
                                        "key": "f",
                                        "doc_count": 101
                                    },
                                    {
                                        "key": "m",
                                        "doc_count": 82
                                    }
                                ]
                            }
                        },
                        {
                            "from": 1000,
                            "to": 2000,
                            "doc_count": 456,
                            "gender": {
                                "buckets": [
                                    {
                                        "key": "f",
                                        "doc_count": 231
                                    },
                                    {
                                        "key": "m",
                                        "doc_count": 225
                                    }
                                ]
                            }
                        },
                        {
                            "from": 2000,
                            "to": 3000,
                            "doc_count": 1158,
                            "gender": {
                                "buckets": [
                                    {
                                        "key": "m",
                                        "doc_count": 894
                                    },
                                    {
                                        "key": "f",
                                        "doc_count": 264
                                    }
                                ]
                            }
                        },
                        {
                            "from": 3000,
                            "doc_count": 22,
                            "gender": {
                                "buckets": [
                                    {
                                        "key": "m",
                                        "doc_count": 11
                                    },
                                    {
                                        "key": "f",
                                        "doc_count": 11
                                    }
                                ]
                            }
                        },
                    ]
                }
            },
            mapper_registry={}
        )
        self.assertEqual(a.doc_count, 1819)
        all_genders_agg = a.get_aggregation('all_genders')
        self.assertEqual(len(all_genders_agg.buckets), 2)
        self.assertEqual(all_genders_agg.buckets[0].key, 'm')
        self.assertEqual(all_genders_agg.buckets[0].doc_count, 1212)
        self.assertEqual(all_genders_agg.buckets[0].instance.title, 'Male')
        self.assertEqual(all_genders_agg.buckets[1].key, 'f')
        self.assertEqual(all_genders_agg.buckets[1].doc_count, 607)
        self.assertEqual(all_genders_agg.buckets[1].instance.title, 'Female')
        all_salary_agg = a.get_aggregation('all_salary')
        self.assertEqual(len(all_salary_agg.buckets), 4)
        self.assertIs(all_salary_agg.buckets[0].from_, None)
        self.assertEqual(all_salary_agg.buckets[0].to, 1000)
        self.assertEqual(all_salary_agg.buckets[0].doc_count, 183)
        gender_agg = all_salary_agg.buckets[0].get_aggregation('gender')
        self.assertEqual(len(gender_agg.buckets), 2)
        self.assertEqual(gender_agg.buckets[0].key, 'f')
        self.assertEqual(gender_agg.buckets[0].doc_count, 101)
        self.assertEqual(gender_agg.buckets[0].instance.title, 'Female')
        self.assertEqual(gender_agg.buckets[1].key, 'm')
        self.assertEqual(gender_agg.buckets[1].doc_count, 82)
        self.assertEqual(gender_agg.buckets[1].instance.title, 'Male')
        self.assertEqual(all_salary_agg.buckets[1].from_, 1000)
        self.assertEqual(all_salary_agg.buckets[1].to, 2000)
        self.assertEqual(all_salary_agg.buckets[1].doc_count, 456)
        gender_agg = all_salary_agg.buckets[1].get_aggregation('gender')
        self.assertEqual(len(gender_agg.buckets), 2)
        self.assertEqual(gender_agg.buckets[0].key, 'f')
        self.assertEqual(gender_agg.buckets[0].doc_count, 231)
        self.assertEqual(gender_agg.buckets[0].instance.title, 'Female')
        self.assertEqual(gender_agg.buckets[1].key, 'm')
        self.assertEqual(gender_agg.buckets[1].doc_count, 225)
        self.assertEqual(gender_agg.buckets[1].instance.title, 'Male')
        self.assertEqual(gender_mapper.call_count, 1)
コード例 #14
0
    def test_aggs(self):
        f = DynamicDocument.fields

        a = agg.AggExpression()
        self.assertRaises(NotImplementedError, a.build_agg_result, {})

        a = agg.Avg(f.price)
        self.assert_expression(
            a,
            {
                "avg": {"field": "price"}
            }
        )
        res = a.build_agg_result({
            'value': 75.3
        })
        self.assertAlmostEqual(res.value, 75.3)
        res = a.build_agg_result({
            'value': None
        })
        self.assertIs(res.value, None)

        aa = a.clone()
        self.assertIsNot(a, aa)
        self.assertEqual(a.__visit_name__, aa.__visit_name__)
        self.assertEqual(a.params, aa.params)

        a = agg.Min(f.price)
        self.assert_expression(
            a,
            {
                "min": {"field": "price"}
            }
        )
        res = a.build_agg_result({
            'value': 38
        })
        self.assertAlmostEqual(res.value, 38)
        res = a.build_agg_result({
            'value': 1297167619690,
            'value_as_string': '2011-02-08T12:20:19.690Z'
        })
        self.assertAlmostEqual(res.value, 1297167619690)

        a = agg.Max(f.price)
        self.assert_expression(
            a,
            {
                "max": {"field": "price"}
            }
        )
        res = a.build_agg_result({
            'value': 45693.5
        })
        self.assertAlmostEqual(res.value, 45693.5)

        a = agg.Stats(f.grade)
        self.assert_expression(
            a,
            {
                "stats": {"field": "grade"}
            }
        )
        a = a.build_agg_result(
            {
                "count": 6,
                "min": 60,
                "max": 98,
                "avg": 78.5,
                "sum": 471
            }
        )
        self.assertEqual(a.count, 6)
        self.assertEqual(a.min, 60)
        self.assertEqual(a.max, 98)
        self.assertAlmostEqual(a.avg, 78.5)
        self.assertEqual(a.sum, 471)

        a = agg.ExtendedStats(f.grade)
        self.assert_expression(
            a,
            {
                "extended_stats": {"field": "grade"}
            }
        )
        a = a.build_agg_result(
            {
                "count": 6,
                "min": 72,
                "max": 117.6,
                "avg": 94.2,
                "sum": 565.2,
                "sum_of_squares": 54551.51999999999,
                "variance": 218.2799999999976,
                "std_deviation": 14.774302013969987
            }
        )
        self.assertEqual(a.count, 6)
        self.assertEqual(a.min, 72)
        self.assertAlmostEqual(a.max, 117.6)
        self.assertAlmostEqual(a.avg, 94.2)
        self.assertAlmostEqual(a.sum, 565.2)
        self.assertAlmostEqual(a.sum_of_squares, 54551.51999999999)
        self.assertAlmostEqual(a.variance, 218.2799999999976)
        self.assertAlmostEqual(a.std_deviation, 14.774302013969987)

        percentiles_agg = agg.Percentiles(f.load_time, percents=[95, 99, 99.9])
        self.assert_expression(
            percentiles_agg,
            {
                "percentiles": {
                    "field": "load_time",
                    "percents": [95, 99, 99.9]
                }
            }
        )
        a = percentiles_agg.build_agg_result(
            {
                "values": {
                    "95.0": 60,
                    "99.0": 150,
                    "99.9": 153,
                }
            }
        )
        self.assertEqual(
            a.values,
            [(95.0, 60), (99.0, 150), (99.9, 153)],
        )
        self.assertEqual(a.get_value(95), 60)
        self.assertEqual(a.get_value(95.0), 60)
        self.assertEqual(a.get_value(99), 150)
        self.assertEqual(a.get_value(99.0), 150)
        self.assertEqual(a.get_value(99.9), 153)
        a = percentiles_agg.build_agg_result(
            {
                "values": {
                    "95.0": 60,
                    "95.0_as_string": "60",
                    "99.0": 150,
                    "99.0_as_string": "150",
                    "99.9": 153,
                    "99.9_as_string": "153",
                }
            }
        )
        self.assertEqual(
            a.values,
            [(95.0, 60), (99.0, 150), (99.9, 153)],
        )
        self.assertEqual(a.get_value(95), 60)
        self.assertEqual(a.get_value(95.0), 60)
        self.assertEqual(a.get_value(99), 150)
        self.assertEqual(a.get_value(99.0), 150)
        self.assertEqual(a.get_value(99.9), 153)

        percentiles_agg = agg.Percentiles(f.load_time, percents=[50])
        self.assert_expression(
            percentiles_agg,
            {
                "percentiles": {
                    "field": "load_time",
                    "percents": [50]
                }
            }
        )
        a = percentiles_agg.build_agg_result(
            {
                "values": {
                    "50.0": "NaN",
                }
            }
        )
        self.assertEqual(
            len(a.values),
            1
        )
        self.assertAlmostEqual(
            a.values[0][0],
            50.0
        )
        self.assertTrue(
            math.isnan(a.values[0][1])
        )
        self.assertTrue(math.isnan(a.get_value(50)))
        self.assertTrue(math.isnan(a.get_value(50.0)))

        ranks_agg = agg.PercentileRanks(f.load_time, values=[14.8, 30])
        self.assert_expression(
            ranks_agg,
            {
                "percentile_ranks": {
                    "field": "load_time",
                    "values": [14.8, 30.0]
                }
            }
        )
        a = ranks_agg.build_agg_result(
            {
                "values": {
                    "14.8": 12.32,
                    "30": 100,
                }
            }
        )
        self.assertEqual(
            a.values,
            [(14.8, 12.32), (30.0, 100)],
        )
        self.assertEqual(
            a.values,
            [(14.8, 12.32), (30.0, 100)],
        )
        self.assertAlmostEqual(a.get_percent(14.8), 12.32)
        self.assertAlmostEqual(a.get_percent(13.7 + 1.1), 12.32)
        self.assertAlmostEqual(a.get_percent(30), 100.0)
        self.assertAlmostEqual(a.get_percent(30.0), 100.0)
        a = ranks_agg.build_agg_result(
            {
                "values": {
                    "14.8": 12.32,
                    "14.8_as_string": "12.32",
                    "30": 100,
                    "30_as_string": "100",
                }
            }
        )
        self.assertEqual(
            a.values,
            [(14.8, 12.32), (30.0, 100)],
        )
        self.assertEqual(
            a.values,
            [(14.8, 12.32), (30.0, 100)],
        )
        self.assertAlmostEqual(a.get_percent(14.8), 12.32)
        self.assertAlmostEqual(a.get_percent(13.7 + 1.1), 12.32)
        self.assertAlmostEqual(a.get_percent(30), 100.0)
        self.assertAlmostEqual(a.get_percent(30.0), 100.0)

        a = agg.Cardinality(f.author, precision_threshold=100)
        self.assert_expression(
            a,
            {
                "cardinality": {
                    "field": "author",
                    "precision_threshold": 100
                }
            }
        )
        a = a.build_agg_result(
            {
                "value": 184
            }
        )
        self.assertEqual(a.value, 184)

        a = agg.Global()
        self.assert_expression(a, {"global": {}})
        a = a.build_agg_result(
            {"doc_count": 185}
        )
        self.assertEqual(a.doc_count, 185)

        a = agg.Filter(f.company == 1)
        self.assert_expression(a, {"filter": {"term": {"company": 1}}})
        a2 = a.clone()
        self.assertIsNot(a, a2)
        self.assert_expression(a2, {"filter": {"term": {"company": 1}}})
        a = a.build_agg_result(
            {"doc_count": 148}
        )
        self.assertEqual(a.doc_count, 148)

        a = agg.Terms(f.status)
        self.assert_expression(
            a,
            {
                "terms": {"field": "status"}
            }
        )
        a1 = a.clone()
        self.assertIsNot(a, a1)
        a = a.build_agg_result(
            {
                'buckets': [
                    {'doc_count': 7353499, 'key': 0},
                    {'doc_count': 2267139, 'key': 1},
                    {'doc_count': 1036951, 'key': 4},
                    {'doc_count': 438384, 'key': 2},
                    {'doc_count': 9594, 'key': 3},
                    {'doc_count': 46, 'key': 5}
                ]
            }
        )
        self.assertEqual(len(a.buckets), 6)
        self.assertEqual(list(iter(a)), a.buckets)
        self.assertEqual(a.buckets[0].key, 0)
        self.assertEqual(a.buckets[0].doc_count, 7353499)
        self.assertEqual(repr(a.buckets[0]), '<Bucket key=0 doc_count=7353499>')

        self.assertIs(a.buckets[0], a.get_bucket(0))
        self.assertEqual(a.buckets[1].key, 1)
        self.assertEqual(a.buckets[1].doc_count, 2267139)
        self.assertIs(a.buckets[1], a.get_bucket(1))
        self.assertEqual(repr(a.buckets[1]), '<Bucket key=1 doc_count=2267139>')

        self.assertEqual(a.buckets[2].key, 4)
        self.assertEqual(a.buckets[2].doc_count, 1036951)
        self.assertIs(a.buckets[2], a.get_bucket(4))
        self.assertEqual(repr(a.buckets[2]), '<Bucket key=4 doc_count=1036951>')

        self.assertEqual(a.buckets[3].key, 2)
        self.assertEqual(a.buckets[3].doc_count, 438384)
        self.assertIs(a.buckets[3], a.get_bucket(2))
        self.assertEqual(repr(a.buckets[3]), '<Bucket key=2 doc_count=438384>')

        self.assertEqual(a.buckets[4].key, 3)
        self.assertEqual(a.buckets[4].doc_count, 9594)
        self.assertIs(a.buckets[4], a.get_bucket(3))
        self.assertEqual(repr(a.buckets[4]), '<Bucket key=3 doc_count=9594>')

        self.assertEqual(a.buckets[5].key, 5)
        self.assertEqual(a.buckets[5].doc_count, 46)
        self.assertIs(a.buckets[5], a.get_bucket(5))
        self.assertEqual(repr(a.buckets[5]), '<Bucket key=5 doc_count=46>')

        a = agg.Terms(f.is_visible, type=Boolean)
        self.assert_expression(
            a,
            {
                "terms": {"field": "is_visible"}
            }
        )
        a = a.build_agg_result(
            {
                'buckets': [
                    {'doc_count': 7, 'key': 'T'},
                    {'doc_count': 2, 'key': 'F'},
                ]
            }
        )
        self.assertEqual(len(a.buckets), 2)
        self.assertEqual(a.buckets[0].key, True)
        self.assertEqual(a.buckets[0].doc_count, 7)
        self.assertIs(a.buckets[0], a.get_bucket(True))
        self.assertEqual(a.buckets[1].key, False)
        self.assertEqual(a.buckets[1].doc_count, 2)
        self.assertIs(a.buckets[1], a.get_bucket(False))

        a = agg.Terms(f.category, type=List(Integer))
        self.assert_expression(
            a,
            {
                "terms": {"field": "category"}
            }
        )
        a = a.build_agg_result(
            {
                'buckets': [
                    {'doc_count': 792, 'key': 28},
                    {'doc_count': 185, 'key': 3},
                ]
            }
        )
        self.assertEqual(len(a.buckets), 2)
        self.assertEqual(a.buckets[0].key, 28)
        self.assertEqual(a.buckets[0].doc_count, 792)
        self.assertIs(a.buckets[0], a.get_bucket(28))
        self.assertEqual(a.buckets[1].key, 3)
        self.assertEqual(a.buckets[1].doc_count, 185)
        self.assertIs(a.buckets[1], a.get_bucket(3))

        class ProductDocument(Document):
            is_visible = Field(Boolean)
        a = agg.Terms(ProductDocument.is_visible)
        self.assert_expression(
            a,
            {
                "terms": {"field": "is_visible"}
            }
        )
        a = a.build_agg_result(
            {
                'buckets': [
                    {'doc_count': 7, 'key': 'T'},
                    {'doc_count': 2, 'key': 'F'},
                ]
            }
        )
        self.assertEqual(len(a.buckets), 2)
        self.assertEqual(a.buckets[0].key, True)
        self.assertEqual(a.buckets[0].doc_count, 7)
        self.assertIs(a.buckets[0], a.get_bucket(True))
        self.assertEqual(a.buckets[1].key, False)
        self.assertEqual(a.buckets[1].doc_count, 2)
        self.assertIs(a.buckets[1], a.get_bucket(False))

        a = agg.SignificantTerms(f.crime_type)
        self.assert_expression(
            a,
            {
                "significant_terms": {"field": "crime_type"}
            }
        )
        a = a.build_agg_result(
            {
                "doc_count": 47347,
                "buckets" : [
                    {
                        "key": "Bicycle theft",
                        "doc_count": 3640,
                        "score": 0.371,
                        "bg_count": 66799,
                    },
                    {
                        "key": "Mobile phone theft",
                        "doc_count": 27617,
                        "score": 0.0599,
                        "bg_count": 53182,
                    }
                ]
            }
        )
        self.assertEqual(len(a.buckets), 2)
        self.assertEqual(a.buckets[0].key, 'Bicycle theft')
        self.assertEqual(a.buckets[0].doc_count, 3640)
        self.assertAlmostEqual(a.buckets[0].score, 0.371)
        self.assertEqual(a.buckets[0].bg_count, 66799)
        self.assertIs(a.buckets[0], a.get_bucket('Bicycle theft'))
        self.assertEqual(a.buckets[1].key, 'Mobile phone theft')
        self.assertEqual(a.buckets[1].doc_count, 27617)
        self.assertAlmostEqual(a.buckets[1].score, 0.0599)
        self.assertEqual(a.buckets[1].bg_count, 53182)
        self.assertIs(a.buckets[1], a.get_bucket('Mobile phone theft'))

        a = agg.Range(
            f.price,
            ranges=[{'to': 200}, {'from': 200, 'to': 1000}, {'from': 1000}],
            type=Integer,
        )
        self.assert_expression(
            a,
            {
                "range": {
                    "field": "price",
                    "ranges": [
                        {"to": 200},
                        {"from": 200, "to": 1000},
                        {"from": 1000}
                    ]
                }
            }
        )
        a1 = a.clone()
        self.assertIsNot(a1, a)
        a = a.build_agg_result(
            {
                "buckets": [
                    {
                        "to": 200,
                        "doc_count": 12
                    },
                    {
                        "from": 200,
                        "to": 1000,
                        "doc_count": 197
                    },
                    {
                        "from": 1000,
                        "doc_count": 8
                    }
                ]
            }
        )
        self.assertEqual(len(a.buckets), 3)
        self.assertEqual(a.buckets[0].doc_count, 12)
        self.assertEqual(a.buckets[1].doc_count, 197)
        self.assertEqual(a.buckets[2].doc_count, 8)

        a = agg.Filters([Term(f.body, 'error'), Term(f.body, 'warning')])
        self.assert_expression(
            a,
            {
                "filters": {
                    "filters": [
                        {"term": {"body": "error"}},
                        {"term": {"body": "warning"}}
                    ]
                }
            }
        )
        a = a.build_agg_result(
            {
                "buckets": [
                    {
                        "doc_count" : 34
                    },
                    {
                        "doc_count" : 439
                    },
                ]
            }
        )
        self.assertEqual(len(a.buckets), 2)
        self.assertIs(a.buckets[0].key, None)
        self.assertEqual(a.buckets[0].doc_count, 34)
        self.assertIs(a.buckets[1].key, None)
        self.assertEqual(a.buckets[1].doc_count, 439)
        self.assertIs(a.get_bucket(None), None)

        a = agg.Filters(Params(errors=Term(f.body, 'error'), warnings=Term(f.body, 'warning')))
        self.assert_expression(
            a,
            {
                "filters": {
                    "filters": {
                        "errors": {"term": {"body": "error"}},
                        "warnings": {"term": {"body": "warning"}}
                    }
                }
            }
        )
        a = a.build_agg_result(
            {
                "buckets": {
                    "errors": {
                        "doc_count" : 34
                    },
                    "warnings": {
                        "doc_count" : 439
                    },
                }
            }
        )
        self.assertEqual(len(a.buckets), 2)
        self.assertIs(a.buckets[0].key, 'errors')
        self.assertEqual(a.buckets[0].doc_count, 34)
        self.assertIs(a.buckets[0], a.get_bucket('errors'))
        self.assertIs(a.buckets[1].key, 'warnings')
        self.assertEqual(a.buckets[1].doc_count, 439)
        self.assertIs(a.buckets[1], a.get_bucket('warnings'))

        a = agg.Nested(f.resellers, aggs={'min_price': agg.Min(f.resellers.price)})
        self.assert_expression(
            a,
            {
                "nested": {"path": "resellers"},
                "aggregations": {
                    "min_price": {"min": {"field": "resellers.price"}}
                }
            }
        )
        a = a.build_agg_result(
            {
                "min_price": {
                    "value" : 350
                }
            }
        )
        self.assertEqual(a.get_aggregation('min_price').value, 350)

        a = agg.Nested(
            f.resellers,
            aggs={"resellers": agg.Terms(
                f.resellers.id,
                aggs={"reverse": agg.ReverseNested(
                    f.resellers,
                    aggs={"reseller_volume": agg.Sum(f.price)}
                )})})
        self.assert_expression(
            a,
            {
                "nested": {"path": "resellers"},
                "aggregations": {
                    "resellers": {
                        "terms": {"field": "resellers.id"},
                        "aggregations": {
                            "reverse": {
                                "reverse_nested": {"path": "resellers"},
                                "aggregations": {
                                    "reseller_volume": {
                                        "sum": {"field": "price"}
                                    }
                                }
                            }
                        }
                    }
                }
            }
        )
        a = a.build_agg_result(
            {
                "doc_count": 100,
                "resellers": {
                    "buckets": [
                        {
                            "key": 1122,
                            "doc_count": 48,
                            "reverse": {
                                "reseller_volume": {"value": 500100}
                            }
                        },
                        {
                            "key": 2233,
                            "doc_count": 52,
                            "reverse": {
                                "reseller_volume": {"value": 100500}
                            }
                        }
                    ]
                }
            }
        )
        self.assertEqual(
            a
            .get_aggregation("resellers")
            .buckets[1]
            .get_aggregation("reverse")
            .get_aggregation("reseller_volume")
            .value,
            100500
        )

        a = agg.Sampler(shard_size=1000, aggs={'avg_price': agg.Avg(f.price)})
        self.assert_expression(
            a,
            {
                "sampler": {"shard_size": 1000},
                "aggregations": {
                    "avg_price": {"avg": {"field": "price"}}
                }
            }
        )
        a = a.build_agg_result(
            {
                "doc_count": 1000,
                "avg_price": {
                    "value" : 750
                }
            }
        )
        self.assertEqual(a.doc_count, 1000)
        self.assertEqual(a.get_aggregation('avg_price').value, 750)
        
        # complex aggregation with sub aggregations
        a = agg.Global()
        a = a.aggs({
                'selling_type': agg.Terms(
                    f.selling_type,
                    aggs={
                        'price_avg': agg.Avg(f.price),
                        'price_min': agg.Min(f.price),
                        'price_max': agg.Max(f.price),
                        'price_hist': agg.Histogram(f.price, interval=50),
                    }
                ),
                'price_avg': agg.Avg(f.price),
            }
        )
        self.assert_expression(
            a,
            {
                "global": {},
                "aggregations": {
                    "selling_type": {
                        "terms": {"field": "selling_type"},
                        "aggregations": {
                            "price_avg": {"avg": {"field": "price"}},
                            "price_min": {"min": {"field": "price"}},
                            "price_max": {"max": {"field": "price"}},
                            "price_hist": {
                                "histogram": {
                                    "field": "price",
                                    "interval": 50,
                                    'min_doc_count': 1
                                }
                            },
                        }
                    },
                    "price_avg": {"avg": {"field": "price"}}
                }
            }
        )
        a = a.build_agg_result(
            {
                'doc_count': 100,
                'selling_type': {
                    'buckets': [
                        {
                            'key': 'retail',
                            'doc_count': 70,
                            'price_avg': {'value': 60.5},
                            'price_min': {'value': 1.1},
                            'price_max': {'value': 83.4},
                            'price_hist': {
                                'buckets': [
                                    {'key': 50, 'doc_count': 60},
                                    {'key': 100, 'doc_count': 7},
                                    {'key': 150, 'doc_count': 3},
                                ]
                            },
                        },
                        {
                            'key': 'wholesale',
                            'doc_count': 30,
                            'price_avg': {'value': 47.9},
                            'price_min': {'value': 20.1},
                            'price_max': {'value': 64.8},
                            'price_hist': {
                                'buckets': [
                                    {'key': 0, 'doc_count': 17},
                                    {'key': 50, 'doc_count': 5},
                                    {'key': 100, 'doc_count': 6},
                                    {'key': 150, 'doc_count': 2},
                                ]
                            },
                        },
                    ],
                },
                'price_avg': {'value': 56.3},
            }
        )
        self.assertEqual(a.doc_count, 100)
        type_agg = a.get_aggregation('selling_type')
        self.assertEqual(len(type_agg.buckets), 2)
        self.assertEqual(type_agg.buckets[0].key, 'retail')
        self.assertEqual(type_agg.buckets[0].doc_count, 70)
        self.assertIs(type_agg.buckets[0], type_agg.get_bucket('retail'))
        self.assertAlmostEqual(type_agg.buckets[0].get_aggregation('price_avg').value, 60.5)
        self.assertAlmostEqual(type_agg.buckets[0].get_aggregation('price_min').value, 1.1)
        self.assertAlmostEqual(type_agg.buckets[0].get_aggregation('price_max').value, 83.4)
        price_hist_agg = type_agg.buckets[0].get_aggregation('price_hist')
        self.assertEqual(price_hist_agg.buckets[0].key, 50)
        self.assertEqual(price_hist_agg.buckets[0].doc_count, 60)
        self.assertIs(price_hist_agg.buckets[0], price_hist_agg.get_bucket(50))
        self.assertEqual(price_hist_agg.buckets[1].key, 100)
        self.assertEqual(price_hist_agg.buckets[1].doc_count, 7)
        self.assertIs(price_hist_agg.buckets[1], price_hist_agg.get_bucket(100))
        self.assertEqual(price_hist_agg.buckets[2].key, 150)
        self.assertEqual(price_hist_agg.buckets[2].doc_count, 3)
        self.assertIs(price_hist_agg.buckets[2], price_hist_agg.get_bucket(150))
        self.assertEqual(len(price_hist_agg.buckets), 3)
        self.assertEqual(type_agg.buckets[1].key, 'wholesale')
        self.assertEqual(type_agg.buckets[1].doc_count, 30)
        self.assertIs(type_agg.buckets[1], type_agg.get_bucket('wholesale'))
        self.assertAlmostEqual(type_agg.buckets[1].get_aggregation('price_avg').value, 47.9)
        self.assertAlmostEqual(type_agg.buckets[1].get_aggregation('price_min').value, 20.1)
        self.assertAlmostEqual(type_agg.buckets[1].get_aggregation('price_max').value, 64.8)
        price_hist_agg = type_agg.buckets[1].get_aggregation('price_hist')
        self.assertEqual(len(price_hist_agg.buckets), 4)
        self.assertEqual(price_hist_agg.buckets[0].key, 0)
        self.assertEqual(price_hist_agg.buckets[0].doc_count, 17)
        self.assertIs(price_hist_agg.buckets[0], price_hist_agg.get_bucket(0))
        self.assertEqual(price_hist_agg.buckets[1].key, 50)
        self.assertEqual(price_hist_agg.buckets[1].doc_count, 5)
        self.assertIs(price_hist_agg.buckets[1], price_hist_agg.get_bucket(50))
        self.assertEqual(price_hist_agg.buckets[2].key, 100)
        self.assertEqual(price_hist_agg.buckets[2].doc_count, 6)
        self.assertIs(price_hist_agg.buckets[2], price_hist_agg.get_bucket(100))
        self.assertEqual(price_hist_agg.buckets[3].key, 150)
        self.assertEqual(price_hist_agg.buckets[3].doc_count, 2)
        self.assertIs(price_hist_agg.buckets[3], price_hist_agg.get_bucket(150))
        self.assertEqual(a.get_aggregation('price_avg').value, 56.3)

        class QuestionDocument(DynamicDocument):
            pass
        
        class PaperDocument(DynamicDocument):
            pass
        
        question_mapper = Mock(
            return_value={
                '602679': Mock(id=602679, type='question'),
                '602678': Mock(id=602678, type='question'),
            }
        )
        paper_mapper = Mock(return_value={'602672': Mock(id=602672, type='paper')})
        top_hits_agg = agg.Terms(
            f.tags,
            size=3,
            aggs={
                'top_tags_hits': agg.TopHits(
                    size=1,
                    sort=f.last_activity_date.desc(),
                    _source={'include': f.title},
                    instance_mapper={
                        QuestionDocument: question_mapper, PaperDocument: paper_mapper
                    },
                )
            }
        )
        self.assert_expression(
            top_hits_agg,
            {
                "terms": {
                    "field": "tags",
                    "size": 3
                },
                "aggregations": {
                    "top_tags_hits": {
                        "top_hits": {
                            "sort": {
                                "last_activity_date": "desc"
                            },
                            "_source": {
                                "include": "title"
                            },
                            "size" : 1
                        }
                    }
                }
            }
        )
        a = top_hits_agg.build_agg_result(
            {
                "buckets": [
                    {
                        "key": "windows-7",
                        "doc_count": 25365,
                        "top_tags_hits": {
                            "hits": {
                                "total": 25365,
                                "max_score": 1,
                                "hits": [
                                    {
                                        "_index": "stack",
                                        "_type": "question",
                                        "_id": "602679",
                                        "_score": 1,
                                        "_source": {
                                            "title": "Windows port opening"
                                        },
                                        "sort": [
                                            1370143231177
                                        ]
                                    }
                                ]
                            }
                        }
                    },
                    {
                        "key": "linux",
                        "doc_count": 18342,
                        "top_tags_hits": {
                            "hits": {
                                "total": 18342,
                                "max_score": 1,
                                "hits": [
                                    {
                                        "_index": "stack",
                                        "_type": "paper",
                                        "_id": "602672",
                                        "_score": 1,
                                        "_source": {
                                            "title": "Ubuntu RFID Screensaver lock-unlock"
                                        },
                                        "sort": [
                                            1370143379747
                                        ]
                                    }
                                ]
                            }
                        }
                    },
                    {
                        "key": "windows",
                        "doc_count": 18119,
                        "top_tags_hits": {
                            "hits": {
                                "total": 18119,
                                "max_score": 1,
                                "hits": [
                                    {
                                        "_index": "stack",
                                        "_type": "question",
                                        "_id": "602678",
                                        "_score": 1,
                                        "_source": {
                                            "title": "If I change my computers date / time, what could be affected?"
                                        },
                                        "sort": [
                                            1370142868283
                                        ]
                                    }
                                ]
                            }
                        }
                    }
                ]
            },
            doc_cls_map={'question': QuestionDocument, 'paper': PaperDocument},
            mapper_registry={},
        )
        self.assertEqual(len(a.buckets), 3)
        self.assertEqual(a.buckets[0].doc_count, 25365)
        self.assertEqual(a.buckets[0].key, 'windows-7')
        top_tags_agg = a.buckets[0].get_aggregation('top_tags_hits')
        self.assertEqual(top_tags_agg.total, 25365)
        self.assertEqual(top_tags_agg.max_score, 1)
        self.assertEqual(len(top_tags_agg.hits), 1)
        self.assertIsInstance(top_tags_agg.hits[0], QuestionDocument)
        self.assertEqual(top_tags_agg.hits[0]._index, 'stack')
        self.assertEqual(top_tags_agg.hits[0]._type, 'question')
        self.assertEqual(top_tags_agg.hits[0]._score, 1)
        self.assertEqual(top_tags_agg.hits[0]._id, '602679')
        self.assertEqual(top_tags_agg.hits[0].title, 'Windows port opening')
        self.assertEqual(top_tags_agg.hits[0].instance.id, 602679)
        self.assertEqual(top_tags_agg.hits[0].instance.type, 'question')
        self.assertEqual(a.buckets[1].doc_count, 18342)
        self.assertEqual(a.buckets[1].key, 'linux')
        top_tags_agg = a.buckets[1].get_aggregation('top_tags_hits')
        self.assertEqual(top_tags_agg.total, 18342)
        self.assertEqual(top_tags_agg.max_score, 1)
        self.assertEqual(len(top_tags_agg.hits), 1)
        self.assertIsInstance(top_tags_agg.hits[0], PaperDocument)
        self.assertEqual(top_tags_agg.hits[0]._index, 'stack')
        self.assertEqual(top_tags_agg.hits[0]._type, 'paper')
        self.assertEqual(top_tags_agg.hits[0]._score, 1)
        self.assertEqual(top_tags_agg.hits[0]._id, '602672')
        self.assertEqual(top_tags_agg.hits[0].title, 'Ubuntu RFID Screensaver lock-unlock')
        self.assertEqual(top_tags_agg.hits[0].instance.id, 602672)
        self.assertEqual(top_tags_agg.hits[0].instance.type, 'paper')
        self.assertEqual(a.buckets[2].doc_count, 18119)
        self.assertEqual(a.buckets[2].key, 'windows')
        top_tags_agg = a.buckets[2].get_aggregation('top_tags_hits')
        self.assertEqual(top_tags_agg.total, 18119)
        self.assertEqual(top_tags_agg.max_score, 1)
        self.assertEqual(len(top_tags_agg.hits), 1)
        self.assertIsInstance(top_tags_agg.hits[0], DynamicDocument)
        self.assertEqual(top_tags_agg.hits[0]._index, 'stack')
        self.assertEqual(top_tags_agg.hits[0]._type, 'question')
        self.assertEqual(top_tags_agg.hits[0]._score, 1)
        self.assertEqual(top_tags_agg.hits[0]._id, '602678')
        self.assertEqual(top_tags_agg.hits[0].title, 'If I change my computers date / time, what could be affected?')
        self.assertEqual(top_tags_agg.hits[0].instance.id, 602678)
        self.assertEqual(top_tags_agg.hits[0].instance.type, 'question')
        self.assertEqual(question_mapper.call_count, 1)
        self.assertEqual(paper_mapper.call_count, 1)
コード例 #15
0
def test_combined_facet_filters(qf, compiler):
    sq = qf.apply(SearchQuery(), {
        'a1': 'true',
        'a18': '58084',
        'a324': '57005',
        'a8__gte': '2.71',
    })
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_bool.filter':
        agg.Filter(Bool.must(
            Term('attr.bool', 0b11),
            Term('attr.int', 0x12_0000e2e4),
            Term('attr.int', 0x144_0000dead),
        ),
                   aggs={
                       'qf.attr_bool': agg.Terms(Field('attr.bool'), size=100),
                   }),
        'qf.attr_bool.filter:1':
        agg.Filter(Bool.must(
            Term('attr.int', 0x12_0000e2e4),
            Term('attr.int', 0x144_0000dead),
        ),
                   aggs={
                       'qf.attr_bool:1':
                       agg.Terms(
                           Field('attr.bool'),
                           size=2,
                           include=[0b10, 0b11],
                       ),
                   }),
        'qf.attr_int.filter':
        agg.Filter(Bool.must(
            Term('attr.bool', 0b11),
            Term('attr.int', 0x12_0000e2e4),
            Term('attr.int', 0x144_0000dead),
        ),
                   aggs={
                       'qf.attr_int': agg.Terms(Field('attr.int'),
                                                size=10_000),
                   }),
        'qf.attr_int.filter:18':
        agg.Filter(Bool.must(
            Term('attr.bool', 0b11),
            Term('attr.int', 0x144_0000dead),
        ),
                   aggs={
                       'qf.attr_int:18': agg.Terms(Field('attr.int'),
                                                   size=100),
                   }),
        'qf.attr_int.filter:324':
        agg.Filter(Bool.must(
            Term('attr.bool', 0b11),
            Term('attr.int', 0x12_0000e2e4),
        ),
                   aggs={
                       'qf.attr_int:324': agg.Terms(Field('attr.int'),
                                                    size=100),
                   })
    }).post_filter(Term('attr.bool', 0b11)).post_filter(
        Term('attr.int', 0x12_0000e2e4)).post_filter(
            Term('attr.int', 0x144_0000dead)).filter(
                Range('attr.float', gte=0x8_402d70a4,
                      lte=0x8_7f800000)).to_dict(compiler=compiler))
コード例 #16
0
def test_attr_int_facet_filter__multiple_selected_values(int_qf, compiler):
    sq = int_qf.apply(SearchQuery(), {
        'a18': '58084',
        'a324': ['57005', '48879']
    })
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_int.filter':
        agg.Filter(Bool.must(
            Term('attr.int', 0x12_0000e2e4),
            Terms('attr.int', [0x144_0000dead, 0x144_0000beef]),
        ),
                   aggs={
                       'qf.attr_int': agg.Terms(Field('attr.int'),
                                                size=10_000),
                   }),
        'qf.attr_int.filter:18':
        agg.Filter(Terms('attr.int', [0x144_0000dead, 0x144_0000beef]),
                   aggs={
                       'qf.attr_int:18': agg.Terms(Field('attr.int'),
                                                   size=100),
                   }),
        'qf.attr_int.filter:324':
        agg.Filter(Term('attr.int', 0x12_0000e2e4),
                   aggs={
                       'qf.attr_int:324': agg.Terms(Field('attr.int'),
                                                    size=100),
                   })
    }).post_filter(Term('attr.int', 0x12_0000e2e4)).post_filter(
        Terms('attr.int',
              [0x144_0000dead, 0x1440000beef])).to_dict(compiler=compiler))
    qf_res = int_qf.process_result(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_int.filter': {
                        'doc_count': 404,
                        'qf.attr_int': {
                            'buckets': [{
                                'key': 0x144_0000dead,
                                'doc_count': 1
                            }, {
                                'key': 0x12_0000e2e4,
                                'doc_count': 1
                            }, {
                                'key': 0x144_0000beef,
                                'doc_count': 1
                            }]
                        }
                    },
                    'qf.attr_int.filter:18': {
                        'doc_count': 200,
                        'qf.attr_int:18': {
                            'buckets': [
                                {
                                    'key': 0x12_0000e2e4,
                                    'doc_count': 99
                                },
                                {
                                    'key': 0x12_0000e7e5,
                                    'doc_count': 88
                                },
                            ]
                        }
                    },
                    'qf.attr_int.filter:324': {
                        'doc_count': 200,
                        'qf.attr_int:324': {
                            'buckets': [
                                {
                                    'key': 0x144_0000dead,
                                    'doc_count': 123
                                },
                                {
                                    'key': 0x144_0000beef,
                                    'doc_count': 1
                                },
                            ]
                        }
                    },
                }
            },
            aggregations=sq.get_context().aggregations))
コード例 #17
0
def test_attr_range_facet_filter__multiple_selected_filters(
        range_qf, compiler):
    sq = range_qf.apply(SearchQuery(), {'a8__gte': 2.71, 'a99__lte': 3.14})
    assert_search_query(
        sq,
        SearchQuery().aggs({
            'qf.attr_range.filter':
            agg.Filter(
                Bool.must(
                    Range('attr.float', gte=0x8_402d70a4, lte=0x8_7f800000),
                    Bool.should(
                        Range('attr.float',
                              gte=0x63_00000000,
                              lte=0x63_4048f5c3),
                        Range('attr.float',
                              gte=0x63_80000000,
                              lte=0x63_ff800000))),
                aggs={
                    'qf.attr_range':
                    agg.Terms(script=Script('doc[params.field].value >>> 32',
                                            lang='painless',
                                            params={
                                                'field': 'attr.float',
                                            }),
                              size=100)
                }),
            'qf.attr_range:8':
            agg.Filter(
                Bool.must(
                    Bool.should(
                        Range('attr.float',
                              gte=0x63_00000000,
                              lte=0x63_4048f5c3),
                        Range('attr.float',
                              gte=0x63_80000000,
                              lte=0x63_ff800000)),
                    Range('attr.float', gte=0x8_00000000, lte=0x8_ffffffff))),
            'qf.attr_range:99':
            agg.Filter(
                Bool.must(
                    Range('attr.float', gte=0x8_402d70a4, lte=0x8_7f800000),
                    Range('attr.float', gte=0x63_00000000,
                          lte=0x63_ffffffff))),
        }).post_filter(Range('attr.float', gte=0x8_402d70a4,
                             lte=0x8_7f800000)).post_filter(
                                 Bool.should(
                                     Range('attr.float',
                                           gte=0x63_00000000,
                                           lte=0x63_4048f5c3),
                                     Range('attr.float',
                                           gte=0x63_80000000,
                                           lte=0x63_ff800000))), compiler)

    qf_res = range_qf.process_results(
        SearchResult(
            {
                'aggregations': {
                    'qf.attr_range.filter': {
                        'doc_count': 32,
                        'qf.attr_range': {
                            'buckets': [{
                                'key': 8,
                                'doc_count': 32
                            }, {
                                'key': 99,
                                'doc_count': 18
                            }]
                        }
                    },
                    'qf.attr_range:8': {
                        'doc_count': 84
                    },
                    'qf.attr_range:99': {
                        'doc_count': 33
                    }
                }
            },
            aggregations=sq.get_context().aggregations))
    assert qf_res.attr_range.name == 'attr_range'
    assert qf_res.attr_range.alias == 'a'
    f = qf_res.attr_range.get_facet(8)
    assert f.attr_id == 8
    assert f.count == 84
    assert f.selected is True
    f = qf_res.attr_range.get_facet(99)
    assert f.attr_id == 99
    assert f.count == 33
    assert f.selected is True
コード例 #18
0
def test_attr_bool_facet_filter__unknown_param(bool_qf, compiler):
    sq = bool_qf.apply(SearchQuery(), {'b18': 'true'})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_bool':
        agg.Terms(Field('attr.bool'), size=100)
    }).to_dict(compiler=compiler))
コード例 #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
コード例 #20
0
def test_attr_int_facet_filter__unknown_param(int_qf, compiler):
    sq = int_qf.apply(SearchQuery(), {'b18': '224'})
    assert sq.to_dict(compiler=compiler) == (SearchQuery().aggs({
        'qf.attr_int':
        agg.Terms(Field('attr.int'), size=10_000)
    }).to_dict(compiler=compiler))