aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/tests/common/location_iterator/location_iterator_test.cpp
blob: 3a9537837192f688cd8634c282489b818a4b212a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/searchlib/attribute/attributefactory.h>
#include <vespa/searchlib/attribute/attributeguard.h>
#include <vespa/searchlib/attribute/attributevector.h>
#include <vespa/searchlib/attribute/integerbase.h>
#include <vespa/searchlib/common/geo_location.h>
#include <vespa/searchlib/common/location.h>
#include <vespa/searchlib/common/locationiterators.h>
#include <vespa/searchcommon/attribute/config.h>
#include <vespa/vespalib/gtest/gtest.h>
#include <cinttypes>

#include <vespa/log/log.h>
LOG_SETUP("location_iterator_test");

using namespace search;
using namespace search::attribute;
using namespace search::common;
using namespace search::fef;

AttributeVector::SP make_attribute(CollectionType collection, bool fast_search = false) {
    Config cfg(BasicType::INT64, collection);
    cfg.setFastSearch(fast_search);
    return AttributeFactory::createAttribute("my_attribute", cfg);
}

void add_docs(AttributeVector::SP attr_ptr, size_t limit = 1000) {
    AttributeVector::DocId docid;
    attr_ptr->addReservedDoc();
    for (size_t i = 1; i < limit; ++i) {
        attr_ptr->addDoc(docid);
    }
    attr_ptr->commit();
    ASSERT_EQ((limit - 1), docid);
}

using Position = std::pair<int32_t, int32_t>;
using Positions = std::vector<Position>;

constexpr double pi = 3.14159265358979323846;
// microdegrees -> degrees -> radians -> km (using Earth mean radius)
constexpr double udeg_to_km = 1.0e-6 * (pi / 180.0) * 6371.0088;

class SingleIteratorTest : public ::testing::Test {
private:
    AttributeVector::SP   _attr;
    IntegerAttribute *    _api;
    TermFieldMatchData    _tfmd;
    std::vector<Position> _positions;

    void set_doc(IntegerAttribute *ia, uint32_t docid, const Position &p) {
	ia->clearDoc(docid);
	int64_t value = vespalib::geo::ZCurve::encode(p.first, p.second);
	LOG(debug, "single: value for docid %u is %" PRId64, docid, value);
	ia->update(docid, value);
	ia->commit();
        if (docid >= _positions.size()) {
            _positions.resize(1+docid);
        }
        _positions[docid] = p;
    }

    void populate_single(IntegerAttribute *ia) {
	Position invalid(0, 0x80000000);
	set_doc(ia, 1, Position(10000, 15000));
	set_doc(ia, 3, invalid);
	set_doc(ia, 5, Position(20000, -25000));
	set_doc(ia, 7, Position(-30000, 35000));
    }

public:
    SingleIteratorTest()
      : _attr(make_attribute(CollectionType::SINGLE, true)),
        _api(dynamic_cast<IntegerAttribute *>(_attr.get()))
    {
        EXPECT_TRUE(_api != nullptr);
        add_docs(_attr);
        populate_single(_api);
    }

    void expect_hits(GeoLocation geo, std::vector<uint32_t> hit_vector) {
        Location bridge(geo);
        bridge.setVec(*_attr);
        auto iterator = create_location_iterator(_tfmd, 9, true, bridge);
        iterator->initFullRange();
        auto hits = hit_vector.cbegin();
        for (uint32_t d = 1; d < 0x80000000; ++d) {
            iterator->seek(d);
            if (iterator->isAtEnd()) {
                break;
            }
            EXPECT_EQ(iterator->getDocId(), *hits++);
            d = std::max(d, iterator->getDocId());
            _tfmd.setRawScore(0, 0.0);
            iterator->unpack(d);
            EXPECT_EQ(_tfmd.getDocId(), d);
            EXPECT_NE(_tfmd.getRawScore(), 0.0);
            int32_t dx = geo.point.x - _positions[d].first;
            int32_t dy = geo.point.y - _positions[d].second;
            double sq_distance = dx*dx + dy*dy;
            double dist = std::sqrt(sq_distance);
            double score = 1.0 / (1.0 + (udeg_to_km * dist));
            LOG(info, "distance[%u] = %.2f, rawscore = %.6f / expected %.6f",
                d, dist, _tfmd.getRawScore(), score);
            EXPECT_DOUBLE_EQ(_tfmd.getRawScore(), score);
        }
        EXPECT_EQ(hits, hit_vector.cend());
        EXPECT_TRUE(iterator->isAtEnd());
    }
};


TEST_F(SingleIteratorTest, finds_locations_sets_rawscore) {
    GeoLocation origin({0, 0}, 1u<<30);
    expect_hits(origin, {1, 5, 7});

    GeoLocation exact({20000, -25000}, 0);
    expect_hits(exact, {5});

    GeoLocation close({-30300, 35400}, 2000);
    expect_hits(close, {7});
}

GTEST_MAIN_RUN_ALL_TESTS()