aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/tests/queryeval/matching_elements_search/matching_elements_search_test.cpp
blob: 5e5d9a9a2826196801c93b4f5d8999f6909a8c7a (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
126
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/searchcommon/attribute/attributecontent.h>
#include <vespa/searchlib/attribute/attributefactory.h>
#include <vespa/searchlib/attribute/attributevector.h>
#include <vespa/searchlib/attribute/stringbase.h>
#include <vespa/searchlib/attribute/integerbase.h>
#include <vespa/searchlib/attribute/i_document_weight_attribute.h>
#include <vespa/searchlib/common/matching_elements.h>
#include <vespa/searchlib/queryeval/matching_elements_search.h>
#include <vespa/searchcommon/attribute/config.h>
#include <vespa/vespalib/gtest/gtest.h>

using search::attribute::BasicType;
using search::attribute::CollectionType;
using search::attribute::Config;
using search::queryeval::MatchingElementsSearch;
using search::AttributeFactory;
using search::AttributeVector;
using search::IDocumentWeightAttribute;
using search::IntegerAttribute;
using search::MatchingElements;
using search::StringAttribute;

std::shared_ptr<AttributeVector> make_attribute(BasicType type) {
    Config cfg(type, CollectionType::WSET);
    cfg.setFastSearch(true);
    auto result = AttributeFactory::createAttribute("field", cfg);
    uint32_t docid = 0;
    for (size_t i = 0; i < 2; ++i) {
        result->addDoc(docid);
    }
    result->commit();
    return result;
}

std::unique_ptr<MatchingElementsSearch> make_search(AttributeVector &attr, const std::vector<vespalib::string> &terms)
{
    using LookupResult = IDocumentWeightAttribute::LookupResult;
    auto dwa = attr.asDocumentWeightAttribute();
    assert(dwa != nullptr);
    auto snapshot = dwa->get_dictionary_snapshot();
    std::vector<LookupResult> dict_entries;
    for (const auto &term : terms) {
        dict_entries.emplace_back(dwa->lookup(term, snapshot));
    }
    auto result = MatchingElementsSearch::create(attr, snapshot, dict_entries);
    result->initRange(1, attr.getCommittedDocIdLimit());
    return result;
}

template <typename KeyType>
class MatchingElementsSearchTest : public ::testing::Test {
public:
    static constexpr bool is_string = std::is_same_v<KeyType, const char *>;
    using Values = std::vector<std::pair<KeyType, int32_t>>;
    using MatchResult = std::map<std::conditional_t<is_string, vespalib::string, KeyType>, int32_t>;
    using LookupTest = std::pair<std::vector<vespalib::string>, MatchResult>;
    using LookupTests = std::vector<LookupTest>;
    using AttributeSubType = std::conditional_t<is_string, StringAttribute, IntegerAttribute>;
    static Values _values;
    static LookupTests _lookup_tests;
    std::shared_ptr<AttributeVector> _attr;
    std::conditional_t<is_string, search::attribute::WeightedStringContent, search::attribute::WeightedIntegerContent> _content;

    MatchingElementsSearchTest()
        : _attr(make_attribute(std::is_same_v<KeyType, int64_t> ? BasicType::INT64 : BasicType::STRING))
    {
        auto &attr = dynamic_cast<AttributeSubType &>(*_attr);
        uint32_t docid = 1;
        attr.clearDoc(docid);
        for (const auto &value : _values) {
            attr.append(docid, value.first, value.second);
        }
        attr.commit();
    }

    MatchResult
    get_matches(MatchingElementsSearch &matching_elements_search) {
        MatchingElements matching_elements_store;
        uint32_t docid = 1;
        matching_elements_search.find_matching_elements(docid, matching_elements_store);
        auto matching_elements = matching_elements_store.get_matching_elements(docid, "field");
        _content.fill(*_attr, docid);
        MatchResult result;
        for (auto &element_id : matching_elements) {
            if (element_id < _content.size()) {
                auto &element = _content[element_id];
                result.emplace(element.value(), element.weight());
            }
        }
        return result;
    }

    void verify_matching_elements() {
        for (const auto &lookup_test : _lookup_tests) {
            auto search = make_search(*_attr, lookup_test.first);
            auto matches = get_matches(*search);
            EXPECT_EQ(lookup_test.second, matches);
        }
    }
};

template <> MatchingElementsSearchTest<int64_t>::Values MatchingElementsSearchTest<int64_t>::_values{{10, 5}, {20, 7}};
template <> MatchingElementsSearchTest<const char *>::Values MatchingElementsSearchTest<const char *>::_values{{"FOO", 3}, {"bar", 7}, {"foo", 5}};
template <> MatchingElementsSearchTest<int64_t>::LookupTests MatchingElementsSearchTest<int64_t>::_lookup_tests{
    {{"10", "11"}, {{10, 5}}},
    {{"11", "20"}, {{20, 7}}},
    {{"10", "20"}, {{10, 5}, {20, 7}}}
};
template <> MatchingElementsSearchTest<const char *>::LookupTests MatchingElementsSearchTest<const char *>::_lookup_tests{
    {{"foo", "baz"}, {{"FOO", 3}, {"foo", 5}}},
    {{"baz", "bar"}, {{"bar", 7}}},
    {{"foo", "bar"}, {{"FOO", 3}, {"foo", 5}, {"bar", 7}}},
    {{"FOO"},        {{"FOO", 3}, {"foo", 5}}}
};

using MatchingElementsSearchTestTypes = ::testing::Types<int64_t, const char *>;
TYPED_TEST_SUITE(MatchingElementsSearchTest, MatchingElementsSearchTestTypes);

TYPED_TEST(MatchingElementsSearchTest, verify_matching_elements)
{
    this->verify_matching_elements();
}

GTEST_MAIN_RUN_ALL_TESTS()